@@ -8,62 +8,119 @@ export function createCachedBounds<Props extends object>({
88} : {
99 itemCount : number ;
1010 itemProps : Props ;
11- itemSize : number | SizeFunction < Props > ;
11+ itemSize : number | SizeFunction < Props > | undefined ;
1212} ) : CachedBounds {
1313 const cache = new Map < number , Bounds > ( ) ;
1414
15- return {
16- get ( index : number ) {
15+ const api = {
16+ getEstimatedSize ( ) {
17+ const lastBounds = cache . get ( cache . size - 1 ) ;
18+ if ( lastBounds ) {
19+ return ( lastBounds . scrollOffset + lastBounds . size ) / cache . size ;
20+ }
21+ } ,
22+ getItemBounds ( index : number ) {
1723 assert ( index < itemCount , `Invalid index ${ index } ` ) ;
1824
19- while ( cache . size - 1 < index ) {
20- const currentIndex = cache . size ;
25+ if ( itemSize ) {
26+ while ( cache . size - 1 < index ) {
27+ const currentIndex = cache . size ;
2128
22- let size : number ;
23- switch ( typeof itemSize ) {
24- case "function" : {
25- size = itemSize ( currentIndex , itemProps ) ;
26- break ;
29+ let size : number ;
30+ switch ( typeof itemSize ) {
31+ case "function" : {
32+ size = itemSize ( currentIndex , itemProps ) ;
33+ break ;
34+ }
35+ case "number" : {
36+ size = itemSize ;
37+ break ;
38+ }
2739 }
28- case "number" : {
29- size = itemSize ;
30- break ;
40+
41+ if ( currentIndex === 0 ) {
42+ cache . set ( currentIndex , {
43+ size,
44+ scrollOffset : 0
45+ } ) ;
46+ } else {
47+ const previousRowBounds = cache . get ( currentIndex - 1 ) ;
48+ assert (
49+ previousRowBounds !== undefined ,
50+ `Unexpected bounds cache miss for index ${ index } `
51+ ) ;
52+
53+ cache . set ( currentIndex , {
54+ scrollOffset :
55+ previousRowBounds . scrollOffset + previousRowBounds . size ,
56+ size
57+ } ) ;
3158 }
3259 }
3360
34- if ( currentIndex === 0 ) {
35- cache . set ( currentIndex , {
36- size,
37- scrollOffset : 0
38- } ) ;
61+ const bounds = cache . get ( index ) ;
62+ assert (
63+ bounds !== undefined ,
64+ `Unexpected bounds cache miss for index ${ index } `
65+ ) ;
66+
67+ return bounds ;
68+ } else {
69+ return cache . get ( index ) ;
70+ }
71+ } ,
72+ hasItemBounds ( index : number ) {
73+ return cache . has ( index ) ;
74+ } ,
75+ setItemSize ( index : number , size : number ) {
76+ // Note this function assumes items are measured in sequence;
77+ // I think that's a safe assumption but if it turns out not to be we'll need to rethink things
78+ let scrollOffset = 0 ;
79+ if ( index > 0 ) {
80+ if ( cache . size >= index ) {
81+ const bounds = cache . get ( index - 1 ) ;
82+ assert ( bounds , `Unexpected cache miss at index ${ index - 1 } ` ) ;
83+
84+ scrollOffset = bounds . scrollOffset + bounds . size ;
3985 } else {
40- const previousRowBounds = cache . get ( currentIndex - 1 ) ;
86+ const lastBounds = cache . get ( cache . size - 1 ) ;
4187 assert (
42- previousRowBounds !== undefined ,
43- `Unexpected bounds cache miss for index ${ index } `
88+ lastBounds ,
89+ `Unexpected cache miss at index ${ cache . size - 1 } `
4490 ) ;
4591
46- cache . set ( currentIndex , {
47- scrollOffset :
48- previousRowBounds . scrollOffset + previousRowBounds . size ,
49- size
50- } ) ;
92+ const estimatedSize = api . getEstimatedSize ( ) ;
93+ assert (
94+ estimatedSize !== undefined ,
95+ "Expected at least one measurement"
96+ ) ;
97+
98+ const numEstimated = index - cache . size ;
99+ scrollOffset =
100+ lastBounds . scrollOffset +
101+ lastBounds . size +
102+ estimatedSize * numEstimated ;
51103 }
52104 }
53105
54- const bounds = cache . get ( index ) ;
55- assert (
56- bounds !== undefined ,
57- `Unexpected bounds cache miss for index ${ index } `
58- ) ;
106+ cache . set ( index , { scrollOffset, size } ) ;
59107
60- return bounds ;
61- } ,
62- set ( index : number , bounds : Bounds ) {
63- cache . set ( index , bounds ) ;
108+ // Adjust offset for items afterward in the cache
109+ while ( index < cache . size ) {
110+ const bounds = cache . get ( index ) ;
111+ assert ( bounds , `Unexpected cache miss at index ${ index } ` ) ;
112+
113+ bounds . scrollOffset = scrollOffset ;
114+
115+ scrollOffset += bounds . size ;
116+
117+ index ++ ;
118+ }
64119 } ,
65120 get size ( ) {
66121 return cache . size ;
67122 }
68123 } ;
124+
125+ return api ;
69126}
0 commit comments