Skip to content

Commit af0891b

Browse files
improved auto-scroll smoothness
1 parent 77ffe23 commit af0891b

File tree

2 files changed

+60
-22
lines changed

2 files changed

+60
-22
lines changed

src/components/design-library-list/design-preview.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const DesignPreview = ( {
4646
const container = ref.current
4747
if ( container ) {
4848
const deltaY = e.clientY - lastY.current
49-
container.scrollTop = lastScrollTop.current - ( deltaY * 2 )
49+
container.scrollTop = lastScrollTop.current - ( deltaY * 4 )
5050
}
5151
}
5252

src/components/design-library-list/use-auto-scroll.js

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,77 @@ const NOOP = () => {}
77

88
export const useAutoScroll = ( hostRef, shadowBodySizeRef, selectedTab ) => {
99
const scrollPositionRef = useRef( 0 )
10-
const scrollIntervalRef = useRef( null )
10+
const animationFrameRef = useRef( null )
11+
const isScrollingRef = useRef( false )
12+
13+
const smoothScrollToBottom = ( shadowDomBody, targetScrollTop ) => {
14+
if ( ! shadowDomBody || ! isScrollingRef.current ) {
15+
return
16+
}
17+
18+
const currentScrollTop = shadowDomBody.scrollTop
19+
const distance = targetScrollTop - currentScrollTop
20+
const totalDistance = shadowBodySizeRef.current.maxScrollTop
21+
const progress = 1 - ( distance / totalDistance ) // 0 at start, 1 at end
22+
23+
// If we're close enough to the target, stop scrolling
24+
if ( Math.abs( distance ) < 1 ) {
25+
isScrollingRef.current = false
26+
return
27+
}
28+
29+
// Bell curve: faster ramp up, starts at reasonable speed, peaks in middle
30+
// Creates a more aggressive acceleration and deceleration pattern
31+
const bellCurve = 10 * progress * ( 1 - progress ) // Peaks at 2.0 in the middle
32+
const baseSpeed = 15 // Base speed multiplier
33+
const scrollStep = Math.max( baseSpeed * bellCurve, 5 ) // Minimum 1.5px for better start
34+
35+
// Apply the scroll step
36+
shadowDomBody.scrollTop = currentScrollTop + scrollStep
37+
scrollPositionRef.current = shadowDomBody.scrollTop
38+
39+
// Continue scrolling on next frame
40+
animationFrameRef.current = requestAnimationFrame( () =>
41+
smoothScrollToBottom( shadowDomBody, targetScrollTop )
42+
)
43+
}
1144

1245
const onMouseOverImpl = () => {
1346
const shadowDomBody = hostRef?.current?.shadowRoot?.querySelector?.( 'body' )
1447
if ( shadowDomBody && shadowBodySizeRef.current ) {
48+
// Reset scroll position and start smooth scrolling
1549
scrollPositionRef.current = 0
50+
isScrollingRef.current = true
51+
1652
setTimeout( () => {
17-
if ( scrollPositionRef.current === -1 ) {
53+
if ( scrollPositionRef.current === -1 || ! isScrollingRef.current ) {
1854
return
1955
}
2056

21-
if ( scrollIntervalRef.current ) {
22-
clearInterval( scrollIntervalRef.current )
57+
// Clear any existing animation
58+
if ( animationFrameRef.current ) {
59+
cancelAnimationFrame( animationFrameRef.current )
2360
}
2461

25-
scrollIntervalRef.current = setInterval( () => {
26-
const scrollDifference = shadowBodySizeRef.current.maxScrollTop - scrollPositionRef.current
27-
const shouldScroll = shadowBodySizeRef.current.maxScrollTop - scrollPositionRef.current > 0
28-
29-
if ( ! shadowDomBody || ! shouldScroll ) {
30-
clearInterval( scrollIntervalRef.current )
31-
return
32-
}
33-
34-
const scrollBy = scrollDifference >= 20 ? 20 : scrollDifference
35-
shadowDomBody.scrollTop = scrollPositionRef.current + scrollBy
36-
scrollPositionRef.current += scrollBy
37-
}, 60 )
62+
// Start smooth scrolling to bottom
63+
const targetScrollTop = shadowBodySizeRef.current.maxScrollTop
64+
if ( targetScrollTop > 0 ) {
65+
smoothScrollToBottom( shadowDomBody, targetScrollTop )
66+
}
3867
}, 1000 )
3968
}
4069
}
4170

4271
const onMouseOutImpl = () => {
4372
const shadowDomBody = hostRef?.current?.shadowRoot?.querySelector?.( 'body' )
4473
if ( shadowDomBody ) {
45-
clearInterval( scrollIntervalRef.current )
46-
scrollIntervalRef.current = null
74+
// Stop scrolling and smoothly return to top
75+
isScrollingRef.current = false
76+
if ( animationFrameRef.current ) {
77+
cancelAnimationFrame( animationFrameRef.current )
78+
animationFrameRef.current = null
79+
}
80+
4781
shadowDomBody.scrollTo( {
4882
top: 0,
4983
behavior: 'smooth',
@@ -53,8 +87,12 @@ export const useAutoScroll = ( hostRef, shadowBodySizeRef, selectedTab ) => {
5387
}
5488

5589
const onMouseDownImpl = () => {
56-
clearInterval( scrollIntervalRef.current )
57-
scrollIntervalRef.current = null
90+
// Stop auto-scrolling when user interacts
91+
isScrollingRef.current = false
92+
if ( animationFrameRef.current ) {
93+
cancelAnimationFrame( animationFrameRef.current )
94+
animationFrameRef.current = null
95+
}
5896
scrollPositionRef.current = -1
5997
}
6098

0 commit comments

Comments
 (0)