@@ -18,7 +18,8 @@ export type DVirtualScrollPerformance<T> = Pick<
18
18
19
19
export interface DVirtualScrollRef < T > {
20
20
scrollToItem : ( item : T ) => void ;
21
- scrollByStep : ( step : number ) => T | undefined ;
21
+ scrollToStep : ( step : 1 | - 1 ) => T | undefined ;
22
+ scrollToNested : ( ) => T | undefined ;
22
23
scrollToStart : ( ) => T | undefined ;
23
24
scrollToEnd : ( ) => T | undefined ;
24
25
}
@@ -92,8 +93,8 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
92
93
let firstFocusableItem : T | undefined ;
93
94
let lastFocusableItem : T | undefined ;
94
95
95
- const items = new Map < DId , { item : T ; accSize : number ; nestedSize : number } > ( ) ;
96
- const reduceArr = ( arr : T [ ] ) => {
96
+ const items = new Map < DId , { item : T ; level : number ; accSize : number ; nestedSize : number } > ( ) ;
97
+ const reduceArr = ( arr : T [ ] , level = 0 ) => {
97
98
let size = 0 ;
98
99
for ( const item of arr ) {
99
100
if ( checkFocusable ( item ) ) {
@@ -103,20 +104,22 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
103
104
}
104
105
}
105
106
106
- size += getItemSize ( item ) ;
107
- accSize += getItemSize ( item ) ;
107
+ const key = dItemKey ( item ) ;
108
+ const itemSize = getItemSize ( item ) ;
109
+ size += itemSize ;
110
+ accSize += itemSize ;
108
111
109
- const data = { item, accSize, nestedSize : 0 } ;
110
- items . set ( dItemKey ( item ) , data ) ;
112
+ const data = { item, level , accSize, nestedSize : 0 } ;
113
+ items . set ( key , data ) ;
111
114
112
115
const nestedData = dItemNested ?.( item ) ;
113
- if ( nestedData && nestedData . list && ( isUndefined ( dExpands ) || dExpands . has ( dItemKey ( item ) ) ) ) {
116
+ if ( nestedData && nestedData . list && ( isUndefined ( dExpands ) || dExpands . has ( key ) ) ) {
114
117
if ( nestedData . list . length === 0 ) {
115
118
data . nestedSize = nestedData . emptySize ?? 0 ;
116
119
size += data . nestedSize ;
117
120
accSize += data . nestedSize ;
118
121
} else {
119
- data . nestedSize = reduceArr ( nestedData . list ) ;
122
+ data . nestedSize = reduceArr ( nestedData . list , level + 1 ) ;
120
123
size += data . nestedSize ;
121
124
}
122
125
}
@@ -198,7 +201,7 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
198
201
childrenList = getList ( nestedList . length === 0 ? [ EMPTY ] : nestedList , parent . concat ( [ item as T ] ) ) ;
199
202
} else {
200
203
childrenList = dataRef . current . listCache . get ( key ) ?? [ ] ;
201
- if ( dExpands . has ( dItemKey ( item as T ) ) ) {
204
+ if ( dExpands . has ( key ) ) {
202
205
childrenList = getList ( nestedList . length === 0 ? [ EMPTY ] : nestedList , parent . concat ( [ item as T ] ) ) ;
203
206
dataRef . current . listCache . set ( key , childrenList ) ;
204
207
}
@@ -324,10 +327,10 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
324
327
return lastFocusableItem ;
325
328
} ) ;
326
329
327
- const scrollByStep = useEventCallback ( ( step : number ) => {
330
+ const scrollToStep = useEventCallback ( ( step : 1 | - 1 ) => {
328
331
if ( ! isUndefined ( paddingSize ) ) {
329
332
if ( isUndefined ( dFocusItem ) ) {
330
- return step > 0 ? scrollToStart ( ) : scrollToEnd ( ) ;
333
+ return ;
331
334
}
332
335
333
336
let findItem : T | undefined ;
@@ -337,27 +340,28 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
337
340
let index = - 1 ;
338
341
let findIndex = - 1 ;
339
342
const accSizeList = [ ] ;
343
+ const focusKey = dItemKey ( dFocusItem ) ;
340
344
for ( const iterator of itemsMap ) {
341
345
index += 1 ;
342
- if ( dItemKey ( iterator [ 1 ] . item ) === dItemKey ( dFocusItem ) ) {
346
+ if ( iterator [ 0 ] === focusKey ) {
343
347
findIndex = index ;
344
348
}
345
349
accSizeList . push ( iterator [ 1 ] ) ;
346
350
}
347
351
348
352
if ( findIndex !== - 1 ) {
349
- if ( step < 0 ) {
350
- for ( let index = findIndex - 1 , n = 0 ; n < accSizeList . length ; index -- , n ++ ) {
351
- const accSizeItem = nth ( accSizeList , index ) ;
353
+ if ( step === 1 ) {
354
+ for ( let index = findIndex + 1 , n = 0 ; n < accSizeList . length ; index ++ , n ++ ) {
355
+ const accSizeItem = nth ( accSizeList , index % accSizeList . length ) ;
352
356
if ( accSizeItem && checkFocusable ( accSizeItem . item ) ) {
353
357
findItem = accSizeItem . item ;
354
358
offsetSize = [ accSizeItem . accSize - getItemSize ( findItem ) + paddingSize , accSizeItem . accSize + paddingSize ] ;
355
359
break ;
356
360
}
357
361
}
358
362
} else {
359
- for ( let index = findIndex + 1 , n = 0 ; n < accSizeList . length ; index ++ , n ++ ) {
360
- const accSizeItem = nth ( accSizeList , index % accSizeList . length ) ;
363
+ for ( let index = findIndex - 1 , n = 0 ; n < accSizeList . length ; index -- , n ++ ) {
364
+ const accSizeItem = nth ( accSizeList , index ) ;
361
365
if ( accSizeItem && checkFocusable ( accSizeItem . item ) ) {
362
366
findItem = accSizeItem . item ;
363
367
offsetSize = [ accSizeItem . accSize - getItemSize ( findItem ) + paddingSize , accSizeItem . accSize + paddingSize ] ;
@@ -375,7 +379,7 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
375
379
} else if ( offsetSize [ 0 ] > listElScrollPosition + listElClientSize ) {
376
380
scrollTo ( offsetSize [ 1 ] - listElClientSize + paddingSize ) ;
377
381
} else {
378
- if ( step > 0 ) {
382
+ if ( step === 1 ) {
379
383
if ( offsetSize [ 1 ] > listElScrollPosition + listElClientSize ) {
380
384
scrollTo ( offsetSize [ 1 ] - listElClientSize + paddingSize ) ;
381
385
}
@@ -392,15 +396,73 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
392
396
}
393
397
} ) ;
394
398
399
+ const scrollToNested = useEventCallback ( ( ) => {
400
+ if ( ! isUndefined ( paddingSize ) ) {
401
+ if ( isUndefined ( dFocusItem ) ) {
402
+ return ;
403
+ }
404
+
405
+ let findItem : T | undefined ;
406
+ let offsetSize : [ number , number ] | undefined ;
407
+
408
+ if ( listRef . current ) {
409
+ let index = - 1 ;
410
+ let findIndex = - 1 ;
411
+ let level = 0 ;
412
+ const accSizeList = [ ] ;
413
+ const focusKey = dItemKey ( dFocusItem ) ;
414
+ for ( const iterator of itemsMap ) {
415
+ index += 1 ;
416
+ if ( iterator [ 0 ] === focusKey ) {
417
+ findIndex = index ;
418
+ level = iterator [ 1 ] . level ;
419
+ }
420
+ accSizeList . push ( iterator [ 1 ] ) ;
421
+ }
422
+
423
+ if ( findIndex !== - 1 ) {
424
+ for ( let index = findIndex + 1 ; index < accSizeList . length ; index ++ ) {
425
+ const accSizeItem = accSizeList [ index ] ;
426
+ if ( accSizeItem . level <= level ) {
427
+ return ;
428
+ }
429
+ if ( checkFocusable ( accSizeItem . item ) ) {
430
+ findItem = accSizeItem . item ;
431
+ offsetSize = [ accSizeItem . accSize - getItemSize ( findItem ) + paddingSize , accSizeItem . accSize + paddingSize ] ;
432
+ break ;
433
+ }
434
+ }
435
+ }
436
+
437
+ if ( ! isUndefined ( offsetSize ) ) {
438
+ const listElScrollPosition = listRef . current [ dHorizontal ? 'scrollLeft' : 'scrollTop' ] ;
439
+ const listElClientSize = listRef . current [ dHorizontal ? 'clientWidth' : 'clientHeight' ] ;
440
+ if ( listElScrollPosition > offsetSize [ 1 ] ) {
441
+ scrollTo ( offsetSize [ 0 ] - paddingSize ) ;
442
+ } else if ( offsetSize [ 0 ] > listElScrollPosition + listElClientSize ) {
443
+ scrollTo ( offsetSize [ 1 ] - listElClientSize + paddingSize ) ;
444
+ } else {
445
+ if ( offsetSize [ 1 ] > listElScrollPosition + listElClientSize ) {
446
+ scrollTo ( offsetSize [ 1 ] - listElClientSize + paddingSize ) ;
447
+ }
448
+ }
449
+ }
450
+ }
451
+
452
+ return findItem ;
453
+ }
454
+ } ) ;
455
+
395
456
useImperativeHandle (
396
457
ref ,
397
458
( ) => ( {
398
459
scrollToItem,
399
- scrollByStep,
460
+ scrollToStep,
461
+ scrollToNested,
400
462
scrollToStart,
401
463
scrollToEnd,
402
464
} ) ,
403
- [ scrollByStep , scrollToEnd , scrollToStart , scrollToItem ]
465
+ [ scrollToItem , scrollToStep , scrollToNested , scrollToStart , scrollToEnd ]
404
466
) ;
405
467
406
468
return children ( {
0 commit comments