@@ -11,7 +11,7 @@ import ScrollBar from './ScrollBar';
11
11
import type { RenderFunc , SharedConfig , GetKey , ExtraRenderInfo } from './interface' ;
12
12
import useChildren from './hooks/useChildren' ;
13
13
import useHeights from './hooks/useHeights' ;
14
- import useScrollTo from './hooks/useScrollTo' ;
14
+ import useScrollTo , { type ScrollPos , type ScrollTarget } from './hooks/useScrollTo' ;
15
15
import useDiffItem from './hooks/useDiffItem' ;
16
16
import useFrameWheel from './hooks/useFrameWheel' ;
17
17
import useMobileTouchMove from './hooks/useMobileTouchMove' ;
@@ -27,21 +27,18 @@ const ScrollStyle: React.CSSProperties = {
27
27
overflowAnchor : 'none' ,
28
28
} ;
29
29
30
- export type ScrollAlign = 'top' | 'bottom' | 'auto' ;
31
- export type ScrollConfig =
32
- | {
33
- index : number ;
34
- align ?: ScrollAlign ;
35
- offset ?: number ;
36
- }
37
- | {
38
- key : React . Key ;
39
- align ?: ScrollAlign ;
40
- offset ?: number ;
41
- } ;
30
+ export interface ScrollInfo {
31
+ x : number ;
32
+ y : number ;
33
+ }
34
+
35
+ export type ScrollConfig = ScrollTarget | ScrollPos ;
36
+
42
37
export type ScrollTo = ( arg : number | ScrollConfig ) => void ;
38
+
43
39
export type ListRef = {
44
40
scrollTo : ScrollTo ;
41
+ getScrollInfo : ( ) => ScrollInfo ;
45
42
} ;
46
43
47
44
export interface ListProps < T > extends Omit < React . HTMLAttributes < any > , 'children' > {
@@ -70,7 +67,7 @@ export interface ListProps<T> extends Omit<React.HTMLAttributes<any>, 'children'
70
67
* Given the virtual offset value.
71
68
* It's the logic offset from start position.
72
69
*/
73
- onVirtualScroll ?: ( info : { x : number ; y : number } ) => void ;
70
+ onVirtualScroll ?: ( info : ScrollInfo ) => void ;
74
71
75
72
/** Trigger when render list item changed */
76
73
onVisibleChange ?: ( visibleList : T [ ] , fullList : T [ ] ) => void ;
@@ -287,21 +284,25 @@ export function RawList<T>(props: ListProps<T>, ref: React.Ref<ListRef>) {
287
284
const originScroll = useOriginScroll ( isScrollAtTop , isScrollAtBottom ) ;
288
285
289
286
// ================================ Scroll ================================
290
- const lastVirtualScrollInfoRef = useRef < [ number , number ] > ( [ 0 , 0 ] ) ;
287
+ const getVirtualScrollInfo = ( ) => ( {
288
+ x : isRTL ? - offsetLeft : offsetLeft ,
289
+ y : offsetTop ,
290
+ } ) ;
291
+
292
+ const lastVirtualScrollInfoRef = useRef ( getVirtualScrollInfo ( ) ) ;
291
293
292
294
const triggerScroll = useEvent ( ( ) => {
293
295
if ( onVirtualScroll ) {
294
- const x = isRTL ? - offsetLeft : offsetLeft ;
295
- const y = offsetTop ;
296
+ const nextInfo = getVirtualScrollInfo ( ) ;
296
297
297
298
// Trigger when offset changed
298
- if ( lastVirtualScrollInfoRef . current [ 0 ] !== x || lastVirtualScrollInfoRef . current [ 1 ] !== y ) {
299
- onVirtualScroll ( {
300
- x ,
301
- y ,
302
- } ) ;
299
+ if (
300
+ lastVirtualScrollInfoRef . current . x !== nextInfo . x ||
301
+ lastVirtualScrollInfoRef . current . y !== nextInfo . y
302
+ ) {
303
+ onVirtualScroll ( nextInfo ) ;
303
304
304
- lastVirtualScrollInfoRef . current = [ x , y ] ;
305
+ lastVirtualScrollInfoRef . current = nextInfo ;
305
306
}
306
307
}
307
308
} ) ;
@@ -331,19 +332,24 @@ export function RawList<T>(props: ListProps<T>, ref: React.Ref<ListRef>) {
331
332
triggerScroll ( ) ;
332
333
}
333
334
335
+ const keepInHorizontalRange = ( nextOffsetLeft : number ) => {
336
+ let tmpOffsetLeft = nextOffsetLeft ;
337
+ const max = scrollWidth - size . width ;
338
+ tmpOffsetLeft = Math . max ( tmpOffsetLeft , 0 ) ;
339
+ tmpOffsetLeft = Math . min ( tmpOffsetLeft , max ) ;
340
+
341
+ return tmpOffsetLeft ;
342
+ } ;
343
+
334
344
const onWheelDelta : Parameters < typeof useFrameWheel > [ 4 ] = useEvent ( ( offsetXY , fromHorizontal ) => {
335
345
if ( fromHorizontal ) {
336
346
// Horizontal scroll no need sync virtual position
337
347
338
348
flushSync ( ( ) => {
339
349
setOffsetLeft ( ( left ) => {
340
- let newLeft = left + ( isRTL ? - offsetXY : offsetXY ) ;
341
-
342
- const max = scrollWidth - size . width ;
343
- newLeft = Math . max ( newLeft , 0 ) ;
344
- newLeft = Math . min ( newLeft , max ) ;
350
+ const nextOffsetLeft = left + ( isRTL ? - offsetXY : offsetXY ) ;
345
351
346
- return newLeft ;
352
+ return keepInHorizontalRange ( nextOffsetLeft ) ;
347
353
} ) ;
348
354
} ) ;
349
355
@@ -413,7 +419,24 @@ export function RawList<T>(props: ListProps<T>, ref: React.Ref<ListRef>) {
413
419
) ;
414
420
415
421
React . useImperativeHandle ( ref , ( ) => ( {
416
- scrollTo,
422
+ getScrollInfo : getVirtualScrollInfo ,
423
+ scrollTo : ( config ) => {
424
+ function isPosScroll ( arg : any ) : arg is ScrollPos {
425
+ return arg && typeof arg === 'object' && ( 'left' in arg || 'top' in arg ) ;
426
+ }
427
+
428
+ if ( isPosScroll ( config ) ) {
429
+ // Scroll X
430
+ if ( config . left !== undefined ) {
431
+ setOffsetLeft ( keepInHorizontalRange ( config . left ) ) ;
432
+ }
433
+
434
+ // Scroll Y
435
+ scrollTo ( config . top ) ;
436
+ } else {
437
+ scrollTo ( config ) ;
438
+ }
439
+ } ,
417
440
} ) ) ;
418
441
419
442
// ================================ Effect ================================
0 commit comments