@@ -24,6 +24,8 @@ export class TableLayout<T> extends ListLayout<T> {
2424 stickyColumnIndices : number [ ] ;
2525 wasLoading = false ;
2626 isLoading = false ;
27+ lastPersistedKeys : Set < Key > = null ;
28+ persistedIndices : Map < Key , number [ ] > = new Map ( ) ;
2729
2830 constructor ( options : ListLayoutOptions < T > ) {
2931 super ( options ) ;
@@ -50,6 +52,7 @@ export class TableLayout<T> extends ListLayout<T> {
5052 let header = this . buildHeader ( ) ;
5153 let body = this . buildBody ( 0 ) ;
5254 this . stickyColumnIndices = this . collection . columns . filter ( c => c . props . isSelectionCell || this . collection . rowHeaderColumnKeys . has ( c . key ) ) . map ( c => c . index ) ;
55+ this . lastPersistedKeys = null ;
5356
5457 body . layoutInfo . rect . width = Math . max ( header . layoutInfo . rect . width , body . layoutInfo . rect . width ) ;
5558 this . contentSize = new Size ( body . layoutInfo . rect . width , body . layoutInfo . rect . maxY ) ;
@@ -125,8 +128,9 @@ export class TableLayout<T> extends ListLayout<T> {
125128 // used to get the column widths when rendering to the DOM
126129 getColumnWidth_ ( node : GridNode < T > ) {
127130 let colspan = node . colspan ?? 1 ;
131+ let colIndex = node . colIndex ?? node . index ;
128132 let width = 0 ;
129- for ( let i = node . index ; i < node . index + colspan ; i ++ ) {
133+ for ( let i = colIndex ; i < colIndex + colspan ; i ++ ) {
130134 let column = this . collection . columns [ i ] ;
131135 width += this . getColumnWidth ( column . key ) ;
132136 }
@@ -274,6 +278,7 @@ export class TableLayout<T> extends ListLayout<T> {
274278 getVisibleLayoutInfos ( rect : Rect ) {
275279 let res : LayoutInfo [ ] = [ ] ;
276280
281+ this . buildPersistedIndices ( ) ;
277282 for ( let node of this . rootNodes ) {
278283 res . push ( node . layoutInfo ) ;
279284 this . addVisibleLayoutInfos ( res , node , rect ) ;
@@ -298,24 +303,35 @@ export class TableLayout<T> extends ListLayout<T> {
298303 case 'rowgroup' : {
299304 let firstVisibleRow = this . binarySearch ( node . children , rect . topLeft , 'y' ) ;
300305 let lastVisibleRow = this . binarySearch ( node . children , rect . bottomRight , 'y' ) ;
301- // Check to see if a persisted key exists before the visible rows
302- // This is for keeping focus on a row that scrolls out of view
303- for ( let h = 0 ; h < firstVisibleRow ; h ++ ) {
304- if ( this . virtualizer . isPersistedKey ( node . children [ h ] ) ) {
305- res . push ( node . children [ h ] . layoutInfo ) ;
306- this . addVisibleLayoutInfos ( res , node . children [ h ] , rect ) ;
307- }
306+
307+ // Add persisted rows before the visible rows.
308+ let persistedRowIndices = this . persistedIndices . get ( node . layoutInfo . key ) ;
309+ let persistIndex = 0 ;
310+ while (
311+ persistedRowIndices &&
312+ persistIndex < persistedRowIndices . length &&
313+ persistedRowIndices [ persistIndex ] < firstVisibleRow
314+ ) {
315+ let idx = persistedRowIndices [ persistIndex ] ;
316+ res . push ( node . children [ idx ] . layoutInfo ) ;
317+ this . addVisibleLayoutInfos ( res , node . children [ idx ] , rect ) ;
318+ persistIndex ++ ;
308319 }
320+
309321 for ( let i = firstVisibleRow ; i <= lastVisibleRow ; i ++ ) {
322+ // Skip persisted rows that overlap with visible cells.
323+ while ( persistedRowIndices && persistIndex < persistedRowIndices . length && persistedRowIndices [ persistIndex ] < i ) {
324+ persistIndex ++ ;
325+ }
326+
310327 res . push ( node . children [ i ] . layoutInfo ) ;
311328 this . addVisibleLayoutInfos ( res , node . children [ i ] , rect ) ;
312329 }
313- // Check to see if a persisted key exists after the visible rows
314- for ( let j = lastVisibleRow + 1 ; j < node . children . length ; j ++ ) {
315- if ( this . virtualizer . isPersistedKey ( node . children [ j ] ) ) {
316- res . push ( node . children [ j ] . layoutInfo ) ;
317- this . addVisibleLayoutInfos ( res , node . children [ j ] , rect ) ;
318- }
330+
331+ // Add persisted rows after the visible rows.
332+ while ( persistedRowIndices && persistIndex < persistedRowIndices . length ) {
333+ let idx = persistedRowIndices [ persistIndex ++ ] ;
334+ res . push ( node . children [ idx ] . layoutInfo ) ;
319335 }
320336 break ;
321337 }
@@ -324,35 +340,27 @@ export class TableLayout<T> extends ListLayout<T> {
324340 let firstVisibleCell = this . binarySearch ( node . children , rect . topLeft , 'x' ) ;
325341 let lastVisibleCell = this . binarySearch ( node . children , rect . topRight , 'x' ) ;
326342 let stickyIndex = 0 ;
327- // Check to see if a persisted key exists before the visible cells
328- // This is for keeping focus on a cell that scrolls out of view
329- for ( let h = 0 ; h < firstVisibleCell ; h ++ ) {
330- if ( this . virtualizer . isPersistedKey ( node . children [ h ] ) ) {
331- res . push ( node . children [ h ] . layoutInfo ) ;
332- }
343+
344+ // Add persisted/sticky cells before the visible cells.
345+ let persistedCellIndices = this . persistedIndices . get ( node . layoutInfo . key ) || this . stickyColumnIndices ;
346+ while ( stickyIndex < persistedCellIndices . length && persistedCellIndices [ stickyIndex ] < firstVisibleCell ) {
347+ let idx = persistedCellIndices [ stickyIndex ] ;
348+ res . push ( node . children [ idx ] . layoutInfo ) ;
349+ stickyIndex ++ ;
333350 }
351+
334352 for ( let i = firstVisibleCell ; i <= lastVisibleCell ; i ++ ) {
335- // Sticky columns and row headers are always in the DOM. Interleave these
336- // with the visible range so that they are in the right order.
337- if ( stickyIndex < this . stickyColumnIndices . length ) {
338- let idx = this . stickyColumnIndices [ stickyIndex ] ;
339- while ( idx < i ) {
340- res . push ( node . children [ idx ] . layoutInfo ) ;
341- idx = this . stickyColumnIndices [ stickyIndex ++ ] ;
342- }
353+ // Skip sticky cells that overlap with visible cells.
354+ while ( stickyIndex < persistedCellIndices . length && persistedCellIndices [ stickyIndex ] < i ) {
355+ stickyIndex ++ ;
343356 }
344357
345358 res . push ( node . children [ i ] . layoutInfo ) ;
346359 }
347- // Check to see if a persisted key exists after the visible cells
348- for ( let j = lastVisibleCell ; j < node . children . length ; j ++ ) {
349- if ( this . virtualizer . isPersistedKey ( node . children [ j ] ) ) {
350- res . push ( node . children [ j ] . layoutInfo ) ;
351- }
352- }
353360
354- while ( stickyIndex < this . stickyColumnIndices . length ) {
355- let idx = this . stickyColumnIndices [ stickyIndex ++ ] ;
361+ // Add any remaining sticky cells after the visible cells.
362+ while ( stickyIndex < persistedCellIndices . length ) {
363+ let idx = persistedCellIndices [ stickyIndex ++ ] ;
356364 res . push ( node . children [ idx ] . layoutInfo ) ;
357365 }
358366 break ;
@@ -381,6 +389,46 @@ export class TableLayout<T> extends ListLayout<T> {
381389 return Math . max ( 0 , Math . min ( items . length - 1 , low ) ) ;
382390 }
383391
392+ buildPersistedIndices ( ) {
393+ if ( this . virtualizer . persistedKeys === this . lastPersistedKeys ) {
394+ return ;
395+ }
396+
397+ this . lastPersistedKeys = this . virtualizer . persistedKeys ;
398+ this . persistedIndices . clear ( ) ;
399+
400+ // Build a map of parentKey => indices of children to persist.
401+ for ( let key of this . virtualizer . persistedKeys ) {
402+ let layoutInfo = this . layoutInfos . get ( key ) ;
403+
404+ // Walk up ancestors so parents are also persisted if children are.
405+ while ( layoutInfo && layoutInfo . parentKey ) {
406+ let collectionNode = this . collection . getItem ( layoutInfo . key ) ;
407+ let indices = this . persistedIndices . get ( layoutInfo . parentKey ) ;
408+ if ( ! indices ) {
409+ // stickyColumnIndices are always persisted along with any cells from persistedKeys.
410+ indices = collectionNode . type === 'cell' ? [ ...this . stickyColumnIndices ] : [ ] ;
411+ this . persistedIndices . set ( layoutInfo . parentKey , indices ) ;
412+ }
413+
414+ let index = collectionNode . index ;
415+ if ( layoutInfo . parentKey === 'body' ) {
416+ index -= this . collection . headerRows . length ;
417+ }
418+
419+ if ( ! indices . includes ( index ) ) {
420+ indices . push ( index ) ;
421+ }
422+
423+ layoutInfo = this . layoutInfos . get ( layoutInfo . parentKey ) ;
424+ }
425+ }
426+
427+ for ( let indices of this . persistedIndices . values ( ) ) {
428+ indices . sort ( ( a , b ) => a - b ) ;
429+ }
430+ }
431+
384432 getInitialLayoutInfo ( layoutInfo : LayoutInfo ) {
385433 let res = super . getInitialLayoutInfo ( layoutInfo ) ;
386434
0 commit comments