@@ -18,7 +18,8 @@ export type DVirtualScrollPerformance<T> = Pick<
1818
1919export interface DVirtualScrollRef < T > {
2020 scrollToItem : ( item : T ) => void ;
21- scrollByStep : ( step : number ) => T | undefined ;
21+ scrollToStep : ( step : 1 | - 1 ) => T | undefined ;
22+ scrollToNested : ( ) => T | undefined ;
2223 scrollToStart : ( ) => T | undefined ;
2324 scrollToEnd : ( ) => T | undefined ;
2425}
@@ -92,8 +93,8 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
9293 let firstFocusableItem : T | undefined ;
9394 let lastFocusableItem : T | undefined ;
9495
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 ) => {
9798 let size = 0 ;
9899 for ( const item of arr ) {
99100 if ( checkFocusable ( item ) ) {
@@ -103,20 +104,22 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
103104 }
104105 }
105106
106- size += getItemSize ( item ) ;
107- accSize += getItemSize ( item ) ;
107+ const key = dItemKey ( item ) ;
108+ const itemSize = getItemSize ( item ) ;
109+ size += itemSize ;
110+ accSize += itemSize ;
108111
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 ) ;
111114
112115 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 ) ) ) {
114117 if ( nestedData . list . length === 0 ) {
115118 data . nestedSize = nestedData . emptySize ?? 0 ;
116119 size += data . nestedSize ;
117120 accSize += data . nestedSize ;
118121 } else {
119- data . nestedSize = reduceArr ( nestedData . list ) ;
122+ data . nestedSize = reduceArr ( nestedData . list , level + 1 ) ;
120123 size += data . nestedSize ;
121124 }
122125 }
@@ -198,7 +201,7 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
198201 childrenList = getList ( nestedList . length === 0 ? [ EMPTY ] : nestedList , parent . concat ( [ item as T ] ) ) ;
199202 } else {
200203 childrenList = dataRef . current . listCache . get ( key ) ?? [ ] ;
201- if ( dExpands . has ( dItemKey ( item as T ) ) ) {
204+ if ( dExpands . has ( key ) ) {
202205 childrenList = getList ( nestedList . length === 0 ? [ EMPTY ] : nestedList , parent . concat ( [ item as T ] ) ) ;
203206 dataRef . current . listCache . set ( key , childrenList ) ;
204207 }
@@ -324,10 +327,10 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
324327 return lastFocusableItem ;
325328 } ) ;
326329
327- const scrollByStep = useEventCallback ( ( step : number ) => {
330+ const scrollToStep = useEventCallback ( ( step : 1 | - 1 ) => {
328331 if ( ! isUndefined ( paddingSize ) ) {
329332 if ( isUndefined ( dFocusItem ) ) {
330- return step > 0 ? scrollToStart ( ) : scrollToEnd ( ) ;
333+ return ;
331334 }
332335
333336 let findItem : T | undefined ;
@@ -337,27 +340,28 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
337340 let index = - 1 ;
338341 let findIndex = - 1 ;
339342 const accSizeList = [ ] ;
343+ const focusKey = dItemKey ( dFocusItem ) ;
340344 for ( const iterator of itemsMap ) {
341345 index += 1 ;
342- if ( dItemKey ( iterator [ 1 ] . item ) === dItemKey ( dFocusItem ) ) {
346+ if ( iterator [ 0 ] === focusKey ) {
343347 findIndex = index ;
344348 }
345349 accSizeList . push ( iterator [ 1 ] ) ;
346350 }
347351
348352 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 ) ;
352356 if ( accSizeItem && checkFocusable ( accSizeItem . item ) ) {
353357 findItem = accSizeItem . item ;
354358 offsetSize = [ accSizeItem . accSize - getItemSize ( findItem ) + paddingSize , accSizeItem . accSize + paddingSize ] ;
355359 break ;
356360 }
357361 }
358362 } 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 ) ;
361365 if ( accSizeItem && checkFocusable ( accSizeItem . item ) ) {
362366 findItem = accSizeItem . item ;
363367 offsetSize = [ accSizeItem . accSize - getItemSize ( findItem ) + paddingSize , accSizeItem . accSize + paddingSize ] ;
@@ -375,7 +379,7 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
375379 } else if ( offsetSize [ 0 ] > listElScrollPosition + listElClientSize ) {
376380 scrollTo ( offsetSize [ 1 ] - listElClientSize + paddingSize ) ;
377381 } else {
378- if ( step > 0 ) {
382+ if ( step === 1 ) {
379383 if ( offsetSize [ 1 ] > listElScrollPosition + listElClientSize ) {
380384 scrollTo ( offsetSize [ 1 ] - listElClientSize + paddingSize ) ;
381385 }
@@ -392,15 +396,73 @@ function VirtualScroll<T>(props: DVirtualScrollProps<T>, ref: React.ForwardedRef
392396 }
393397 } ) ;
394398
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+
395456 useImperativeHandle (
396457 ref ,
397458 ( ) => ( {
398459 scrollToItem,
399- scrollByStep,
460+ scrollToStep,
461+ scrollToNested,
400462 scrollToStart,
401463 scrollToEnd,
402464 } ) ,
403- [ scrollByStep , scrollToEnd , scrollToStart , scrollToItem ]
465+ [ scrollToItem , scrollToStep , scrollToNested , scrollToStart , scrollToEnd ]
404466 ) ;
405467
406468 return children ( {
0 commit comments