@@ -24,6 +24,8 @@ export class TableLayout<T> extends ListLayout<T> {
24
24
stickyColumnIndices : number [ ] ;
25
25
wasLoading = false ;
26
26
isLoading = false ;
27
+ lastPersistedKeys : Set < Key > = null ;
28
+ persistedIndices : Map < Key , number [ ] > = new Map ( ) ;
27
29
28
30
constructor ( options : ListLayoutOptions < T > ) {
29
31
super ( options ) ;
@@ -50,6 +52,7 @@ export class TableLayout<T> extends ListLayout<T> {
50
52
let header = this . buildHeader ( ) ;
51
53
let body = this . buildBody ( 0 ) ;
52
54
this . stickyColumnIndices = this . collection . columns . filter ( c => c . props . isSelectionCell || this . collection . rowHeaderColumnKeys . has ( c . key ) ) . map ( c => c . index ) ;
55
+ this . lastPersistedKeys = null ;
53
56
54
57
body . layoutInfo . rect . width = Math . max ( header . layoutInfo . rect . width , body . layoutInfo . rect . width ) ;
55
58
this . contentSize = new Size ( body . layoutInfo . rect . width , body . layoutInfo . rect . maxY ) ;
@@ -125,8 +128,9 @@ export class TableLayout<T> extends ListLayout<T> {
125
128
// used to get the column widths when rendering to the DOM
126
129
getColumnWidth_ ( node : GridNode < T > ) {
127
130
let colspan = node . colspan ?? 1 ;
131
+ let colIndex = node . colIndex ?? node . index ;
128
132
let width = 0 ;
129
- for ( let i = node . index ; i < node . index + colspan ; i ++ ) {
133
+ for ( let i = colIndex ; i < colIndex + colspan ; i ++ ) {
130
134
let column = this . collection . columns [ i ] ;
131
135
width += this . getColumnWidth ( column . key ) ;
132
136
}
@@ -274,6 +278,7 @@ export class TableLayout<T> extends ListLayout<T> {
274
278
getVisibleLayoutInfos ( rect : Rect ) {
275
279
let res : LayoutInfo [ ] = [ ] ;
276
280
281
+ this . buildPersistedIndices ( ) ;
277
282
for ( let node of this . rootNodes ) {
278
283
res . push ( node . layoutInfo ) ;
279
284
this . addVisibleLayoutInfos ( res , node , rect ) ;
@@ -298,24 +303,35 @@ export class TableLayout<T> extends ListLayout<T> {
298
303
case 'rowgroup' : {
299
304
let firstVisibleRow = this . binarySearch ( node . children , rect . topLeft , 'y' ) ;
300
305
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 ++ ;
308
319
}
320
+
309
321
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
+
310
327
res . push ( node . children [ i ] . layoutInfo ) ;
311
328
this . addVisibleLayoutInfos ( res , node . children [ i ] , rect ) ;
312
329
}
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 ) ;
319
335
}
320
336
break ;
321
337
}
@@ -324,35 +340,27 @@ export class TableLayout<T> extends ListLayout<T> {
324
340
let firstVisibleCell = this . binarySearch ( node . children , rect . topLeft , 'x' ) ;
325
341
let lastVisibleCell = this . binarySearch ( node . children , rect . topRight , 'x' ) ;
326
342
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 ++ ;
333
350
}
351
+
334
352
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 ++ ;
343
356
}
344
357
345
358
res . push ( node . children [ i ] . layoutInfo ) ;
346
359
}
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
- }
353
360
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 ++ ] ;
356
364
res . push ( node . children [ idx ] . layoutInfo ) ;
357
365
}
358
366
break ;
@@ -381,6 +389,46 @@ export class TableLayout<T> extends ListLayout<T> {
381
389
return Math . max ( 0 , Math . min ( items . length - 1 , low ) ) ;
382
390
}
383
391
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
+
384
432
getInitialLayoutInfo ( layoutInfo : LayoutInfo ) {
385
433
let res = super . getInitialLayoutInfo ( layoutInfo ) ;
386
434
0 commit comments