@pixui-dev/pxw 0.1.21 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/bin/pxw.js +192 -199
  2. package/bin/wpbuild.js +10 -10
  3. package/config/default.conf +20 -20
  4. package/config/devops.js +360 -372
  5. package/config/h5es.js +10 -10
  6. package/config/index.html +183 -183
  7. package/config/pfbs.js +251 -245
  8. package/config/util.js +136 -140
  9. package/config/webpack.js +324 -325
  10. package/lib/assets/check.html +62 -62
  11. package/lib/assets/preact.js +4354 -4354
  12. package/lib/check/main.less +62 -62
  13. package/lib/check/main.tsx +41 -41
  14. package/lib/check/tool.js +3 -3
  15. package/lib/check/util.tsx +110 -110
  16. package/lib/grpc-web/dist/ChunkParser.js +117 -117
  17. package/lib/grpc-web/dist/Code.js +58 -58
  18. package/lib/grpc-web/dist/client.js +299 -299
  19. package/lib/grpc-web/dist/debug.js +16 -16
  20. package/lib/grpc-web/dist/detach.js +7 -7
  21. package/lib/grpc-web/dist/index.js +29 -29
  22. package/lib/grpc-web/dist/invoke.js +32 -32
  23. package/lib/grpc-web/dist/message.js +3 -3
  24. package/lib/grpc-web/dist/metadata.js +5 -5
  25. package/lib/grpc-web/dist/service.js +3 -3
  26. package/lib/grpc-web/dist/transports/Transport.js +15 -15
  27. package/lib/grpc-web/dist/transports/http/fetch.js +117 -117
  28. package/lib/grpc-web/dist/transports/http/http.js +15 -15
  29. package/lib/grpc-web/dist/transports/http/xhr.js +136 -136
  30. package/lib/grpc-web/dist/transports/http/xhrUtil.js +36 -36
  31. package/lib/grpc-web/dist/transports/websocket/websocket.js +95 -95
  32. package/lib/grpc-web/dist/typings/ChunkParser.d.ts +17 -17
  33. package/lib/grpc-web/dist/typings/Code.d.ts +20 -20
  34. package/lib/grpc-web/dist/typings/client.d.ts +25 -25
  35. package/lib/grpc-web/dist/typings/debug.d.ts +1 -1
  36. package/lib/grpc-web/dist/typings/detach.d.ts +1 -1
  37. package/lib/grpc-web/dist/typings/index.d.ts +45 -45
  38. package/lib/grpc-web/dist/typings/invoke.d.ts +20 -20
  39. package/lib/grpc-web/dist/typings/message.d.ts +8 -8
  40. package/lib/grpc-web/dist/typings/metadata.d.ts +2 -2
  41. package/lib/grpc-web/dist/typings/service.d.ts +16 -16
  42. package/lib/grpc-web/dist/typings/transports/Transport.d.ts +22 -22
  43. package/lib/grpc-web/dist/typings/transports/http/fetch.d.ts +6 -6
  44. package/lib/grpc-web/dist/typings/transports/http/http.d.ts +5 -5
  45. package/lib/grpc-web/dist/typings/transports/http/xhr.d.ts +27 -27
  46. package/lib/grpc-web/dist/typings/transports/http/xhrUtil.d.ts +3 -3
  47. package/lib/grpc-web/dist/typings/transports/websocket/websocket.d.ts +2 -2
  48. package/lib/grpc-web/dist/typings/unary.d.ts +23 -23
  49. package/lib/grpc-web/dist/typings/util.d.ts +2 -2
  50. package/lib/grpc-web/dist/unary.js +44 -44
  51. package/lib/grpc-web/dist/util.js +11 -11
  52. package/lib/grpcTransport/PixHttp2Transport.ts +107 -107
  53. package/lib/grpcTransport/PixLuaTransport.ts +82 -82
  54. package/lib/h5es-types/v1.9.2/h5es.d.ts +1698 -1698
  55. package/lib/h5es-types/v3.5.0/h5es.d.ts +1788 -1788
  56. package/lib/pi_component/tinyList/tinyList.js +483 -483
  57. package/lib/pi_component/tinyList/tinyList.tsx +517 -517
  58. package/lib/preact-router.js +395 -395
  59. package/lib/preact.js +4355 -4355
  60. package/lib/preact.tq.js +4385 -4385
  61. package/lib/react-window/src/FixedSizeGrid.js +172 -172
  62. package/lib/react-window/src/FixedSizeList.js +91 -91
  63. package/lib/react-window/src/VariableSizeGrid.js +329 -329
  64. package/lib/react-window/src/VariableSizeList.js +231 -231
  65. package/lib/react-window/src/__tests__/FixedSizeGrid.js +942 -942
  66. package/lib/react-window/src/__tests__/FixedSizeList.js +749 -749
  67. package/lib/react-window/src/__tests__/VariableSizeGrid.js +598 -598
  68. package/lib/react-window/src/__tests__/VariableSizeList.js +345 -345
  69. package/lib/react-window/src/__tests__/__snapshots__/FixedSizeGrid.js.snap +912 -912
  70. package/lib/react-window/src/__tests__/__snapshots__/FixedSizeList.js.snap +568 -568
  71. package/lib/react-window/src/__tests__/__snapshots__/VariableSizeGrid.js.snap +542 -542
  72. package/lib/react-window/src/__tests__/__snapshots__/VariableSizeList.js.snap +331 -331
  73. package/lib/react-window/src/__tests__/areEqual.js +28 -28
  74. package/lib/react-window/src/__tests__/shouldComponentUpdate.js +32 -32
  75. package/lib/react-window/src/areEqual.js +13 -13
  76. package/lib/react-window/src/createGridComponent.js +657 -657
  77. package/lib/react-window/src/createListComponent.js +574 -574
  78. package/lib/react-window/src/domHelpers.js +69 -69
  79. package/lib/react-window/src/index.js +9 -9
  80. package/lib/react-window/src/shallowDiffers.js +17 -17
  81. package/lib/react-window/src/shouldComponentUpdate.js +11 -11
  82. package/lib/react-window/src/test.js.flow +382 -382
  83. package/lib/react-window/src/timer.js +36 -36
  84. package/lib/types/dom.ts +17 -17
  85. package/lib/types/ext.d.ts +81 -81
  86. package/lib/types/preact/css.d.ts +7476 -7476
  87. package/lib/types/preact/index.d.ts +340 -340
  88. package/lib/types/preact/internal.d.ts +94 -94
  89. package/lib/types/preact/jsx.d.ts +320 -309
  90. package/lib/types/preact-router/index.d.ts +84 -84
  91. package/package.json +114 -113
  92. package/scripts/pack.js +40 -40
  93. package/scripts/postinstall.js +12 -12
  94. package/scripts/run-pxw.js +13 -13
  95. package/tsconfig.json +30 -30
@@ -1,329 +1,329 @@
1
- // @flow
2
-
3
- import createGridComponent from './createGridComponent';
4
-
5
- import type { Props, ScrollToAlign } from './createGridComponent';
6
-
7
- const DEFAULT_ESTIMATED_ITEM_SIZE = 50;
8
-
9
- type VariableSizeProps = {|
10
- estimatedColumnWidth: number,
11
- estimatedRowHeight: number,
12
- ...Props<any>,
13
- |};
14
-
15
- type itemSizeGetter = (index: number) => number;
16
- type ItemType = 'column' | 'row';
17
-
18
- type ItemMetadata = {|
19
- offset: number,
20
- size: number,
21
- |};
22
- type ItemMetadataMap = { [index: number]: ItemMetadata };
23
- type InstanceProps = {|
24
- columnMetadataMap: ItemMetadataMap,
25
- estimatedColumnWidth: number,
26
- estimatedRowHeight: number,
27
- lastMeasuredColumnIndex: number,
28
- lastMeasuredRowIndex: number,
29
- rowMetadataMap: ItemMetadataMap,
30
- |};
31
-
32
- const getEstimatedTotalHeight = ({ rowCount }: Props<any>, { rowMetadataMap, estimatedRowHeight, lastMeasuredRowIndex }: InstanceProps) => {
33
- let totalSizeOfMeasuredRows = 0;
34
-
35
- // Edge case check for when the number of items decreases while a scroll is in progress.
36
- // https://github.com/bvaughn/react-window/pull/138
37
- if (lastMeasuredRowIndex >= rowCount) {
38
- lastMeasuredRowIndex = rowCount - 1;
39
- }
40
-
41
- if (lastMeasuredRowIndex >= 0) {
42
- const itemMetadata = rowMetadataMap[lastMeasuredRowIndex];
43
- totalSizeOfMeasuredRows = itemMetadata.offset + itemMetadata.size;
44
- }
45
-
46
- const numUnmeasuredItems = rowCount - lastMeasuredRowIndex - 1;
47
- const totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedRowHeight;
48
-
49
- return totalSizeOfMeasuredRows + totalSizeOfUnmeasuredItems;
50
- };
51
-
52
- const getEstimatedTotalWidth = ({ columnCount }: Props<any>, { columnMetadataMap, estimatedColumnWidth, lastMeasuredColumnIndex }: InstanceProps) => {
53
- let totalSizeOfMeasuredRows = 0;
54
-
55
- // Edge case check for when the number of items decreases while a scroll is in progress.
56
- // https://github.com/bvaughn/react-window/pull/138
57
- if (lastMeasuredColumnIndex >= columnCount) {
58
- lastMeasuredColumnIndex = columnCount - 1;
59
- }
60
-
61
- if (lastMeasuredColumnIndex >= 0) {
62
- const itemMetadata = columnMetadataMap[lastMeasuredColumnIndex];
63
- totalSizeOfMeasuredRows = itemMetadata.offset + itemMetadata.size;
64
- }
65
-
66
- const numUnmeasuredItems = columnCount - lastMeasuredColumnIndex - 1;
67
- const totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedColumnWidth;
68
-
69
- return totalSizeOfMeasuredRows + totalSizeOfUnmeasuredItems;
70
- };
71
-
72
- const getItemMetadata = (itemType: ItemType, props: Props<any>, index: number, instanceProps: InstanceProps): ItemMetadata => {
73
- let itemMetadataMap, itemSize, lastMeasuredIndex;
74
- if (itemType === 'column') {
75
- itemMetadataMap = instanceProps.columnMetadataMap;
76
- itemSize = ((props.columnWidth: any): itemSizeGetter);
77
- lastMeasuredIndex = instanceProps.lastMeasuredColumnIndex;
78
- } else {
79
- itemMetadataMap = instanceProps.rowMetadataMap;
80
- itemSize = ((props.rowHeight: any): itemSizeGetter);
81
- lastMeasuredIndex = instanceProps.lastMeasuredRowIndex;
82
- }
83
-
84
- if (index > lastMeasuredIndex) {
85
- let offset = 0;
86
- if (lastMeasuredIndex >= 0) {
87
- const itemMetadata = itemMetadataMap[lastMeasuredIndex];
88
- offset = itemMetadata.offset + itemMetadata.size;
89
- }
90
-
91
- for (let i = lastMeasuredIndex + 1; i <= index; i++) {
92
- let size = itemSize(i);
93
-
94
- itemMetadataMap[i] = {
95
- offset,
96
- size,
97
- };
98
-
99
- offset += size;
100
- }
101
-
102
- if (itemType === 'column') {
103
- instanceProps.lastMeasuredColumnIndex = index;
104
- } else {
105
- instanceProps.lastMeasuredRowIndex = index;
106
- }
107
- }
108
-
109
- return itemMetadataMap[index];
110
- };
111
-
112
- const findNearestItem = (itemType: ItemType, props: Props<any>, instanceProps: InstanceProps, offset: number) => {
113
- let itemMetadataMap, lastMeasuredIndex;
114
- if (itemType === 'column') {
115
- itemMetadataMap = instanceProps.columnMetadataMap;
116
- lastMeasuredIndex = instanceProps.lastMeasuredColumnIndex;
117
- } else {
118
- itemMetadataMap = instanceProps.rowMetadataMap;
119
- lastMeasuredIndex = instanceProps.lastMeasuredRowIndex;
120
- }
121
-
122
- const lastMeasuredItemOffset = lastMeasuredIndex > 0 ? itemMetadataMap[lastMeasuredIndex].offset : 0;
123
-
124
- if (lastMeasuredItemOffset >= offset) {
125
- // If we've already measured items within this range just use a binary search as it's faster.
126
- return findNearestItemBinarySearch(itemType, props, instanceProps, lastMeasuredIndex, 0, offset);
127
- } else {
128
- // If we haven't yet measured this high, fallback to an exponential search with an inner binary search.
129
- // The exponential search avoids pre-computing sizes for the full set of items as a binary search would.
130
- // The overall complexity for this approach is O(log n).
131
- return findNearestItemExponentialSearch(itemType, props, instanceProps, Math.max(0, lastMeasuredIndex), offset);
132
- }
133
- };
134
-
135
- const findNearestItemBinarySearch = (itemType: ItemType, props: Props<any>, instanceProps: InstanceProps, high: number, low: number, offset: number): number => {
136
- while (low <= high) {
137
- const middle = low + Math.floor((high - low) / 2);
138
- const currentOffset = getItemMetadata(itemType, props, middle, instanceProps).offset;
139
-
140
- if (currentOffset === offset) {
141
- return middle;
142
- } else if (currentOffset < offset) {
143
- low = middle + 1;
144
- } else if (currentOffset > offset) {
145
- high = middle - 1;
146
- }
147
- }
148
-
149
- if (low > 0) {
150
- return low - 1;
151
- } else {
152
- return 0;
153
- }
154
- };
155
-
156
- const findNearestItemExponentialSearch = (itemType: ItemType, props: Props<any>, instanceProps: InstanceProps, index: number, offset: number): number => {
157
- const itemCount = itemType === 'column' ? props.columnCount : props.rowCount;
158
- let interval = 1;
159
-
160
- while (index < itemCount && getItemMetadata(itemType, props, index, instanceProps).offset < offset) {
161
- index += interval;
162
- interval *= 2;
163
- }
164
-
165
- return findNearestItemBinarySearch(itemType, props, instanceProps, Math.min(index, itemCount - 1), Math.floor(index / 2), offset);
166
- };
167
-
168
- const getOffsetForIndexAndAlignment = (
169
- itemType: ItemType,
170
- props: Props<any>,
171
- index: number,
172
- align: ScrollToAlign,
173
- scrollOffset: number,
174
- instanceProps: InstanceProps,
175
- scrollbarSize: number,
176
- ): number => {
177
- const size = itemType === 'column' ? props.width : props.height;
178
- const itemMetadata = getItemMetadata(itemType, props, index, instanceProps);
179
-
180
- // Get estimated total size after ItemMetadata is computed,
181
- // To ensure it reflects actual measurements instead of just estimates.
182
- const estimatedTotalSize = itemType === 'column' ? getEstimatedTotalWidth(props, instanceProps) : getEstimatedTotalHeight(props, instanceProps);
183
-
184
- const maxOffset = Math.max(0, Math.min(estimatedTotalSize - size, itemMetadata.offset));
185
- const minOffset = Math.max(0, itemMetadata.offset - size + scrollbarSize + itemMetadata.size);
186
-
187
- if (align === 'smart') {
188
- if (scrollOffset >= minOffset - size && scrollOffset <= maxOffset + size) {
189
- align = 'auto';
190
- } else {
191
- align = 'center';
192
- }
193
- }
194
-
195
- switch (align) {
196
- case 'start':
197
- return maxOffset;
198
- case 'end':
199
- return minOffset;
200
- case 'center':
201
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
202
- case 'auto':
203
- default:
204
- if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
205
- return scrollOffset;
206
- } else if (minOffset > maxOffset) {
207
- // Because we only take into account the scrollbar size when calculating minOffset
208
- // this value can be larger than maxOffset when at the end of the list
209
- return minOffset;
210
- } else if (scrollOffset < minOffset) {
211
- return minOffset;
212
- } else {
213
- return maxOffset;
214
- }
215
- }
216
- };
217
-
218
- const VariableSizeGrid = createGridComponent({
219
- getColumnOffset: (props: Props<any>, index: number, instanceProps: InstanceProps): number => getItemMetadata('column', props, index, instanceProps).offset,
220
-
221
- getColumnStartIndexForOffset: (props: Props<any>, scrollLeft: number, instanceProps: InstanceProps): number => findNearestItem('column', props, instanceProps, scrollLeft),
222
-
223
- getColumnStopIndexForStartIndex: (props: Props<any>, startIndex: number, scrollLeft: number, instanceProps: InstanceProps): number => {
224
- const { columnCount, width } = props;
225
-
226
- const itemMetadata = getItemMetadata('column', props, startIndex, instanceProps);
227
- const maxOffset = scrollLeft + width;
228
-
229
- let offset = itemMetadata.offset + itemMetadata.size;
230
- let stopIndex = startIndex;
231
-
232
- while (stopIndex < columnCount - 1 && offset < maxOffset) {
233
- stopIndex++;
234
- offset += getItemMetadata('column', props, stopIndex, instanceProps).size;
235
- }
236
-
237
- return stopIndex;
238
- },
239
-
240
- getColumnWidth: (props: Props<any>, index: number, instanceProps: InstanceProps): number => instanceProps.columnMetadataMap[index].size,
241
-
242
- getEstimatedTotalHeight,
243
- getEstimatedTotalWidth,
244
-
245
- getOffsetForColumnAndAlignment: (props: Props<any>, index: number, align: ScrollToAlign, scrollOffset: number, instanceProps: InstanceProps, scrollbarSize: number): number =>
246
- getOffsetForIndexAndAlignment('column', props, index, align, scrollOffset, instanceProps, scrollbarSize),
247
-
248
- getOffsetForRowAndAlignment: (props: Props<any>, index: number, align: ScrollToAlign, scrollOffset: number, instanceProps: InstanceProps, scrollbarSize: number): number =>
249
- getOffsetForIndexAndAlignment('row', props, index, align, scrollOffset, instanceProps, scrollbarSize),
250
-
251
- getRowOffset: (props: Props<any>, index: number, instanceProps: InstanceProps): number => getItemMetadata('row', props, index, instanceProps).offset,
252
-
253
- getRowHeight: (props: Props<any>, index: number, instanceProps: InstanceProps): number => instanceProps.rowMetadataMap[index].size,
254
-
255
- getRowStartIndexForOffset: (props: Props<any>, scrollTop: number, instanceProps: InstanceProps): number => findNearestItem('row', props, instanceProps, scrollTop),
256
-
257
- getRowStopIndexForStartIndex: (props: Props<any>, startIndex: number, scrollTop: number, instanceProps: InstanceProps): number => {
258
- const { rowCount, height } = props;
259
-
260
- const itemMetadata = getItemMetadata('row', props, startIndex, instanceProps);
261
- const maxOffset = scrollTop + height;
262
-
263
- let offset = itemMetadata.offset + itemMetadata.size;
264
- let stopIndex = startIndex;
265
-
266
- while (stopIndex < rowCount - 1 && offset < maxOffset) {
267
- stopIndex++;
268
- offset += getItemMetadata('row', props, stopIndex, instanceProps).size;
269
- }
270
-
271
- return stopIndex;
272
- },
273
-
274
- initInstanceProps(props: Props<any>, instance: any): InstanceProps {
275
- const { estimatedColumnWidth, estimatedRowHeight } = ((props: any): VariableSizeProps);
276
-
277
- const instanceProps = {
278
- columnMetadataMap: {},
279
- estimatedColumnWidth: estimatedColumnWidth || DEFAULT_ESTIMATED_ITEM_SIZE,
280
- estimatedRowHeight: estimatedRowHeight || DEFAULT_ESTIMATED_ITEM_SIZE,
281
- lastMeasuredColumnIndex: -1,
282
- lastMeasuredRowIndex: -1,
283
- rowMetadataMap: {},
284
- };
285
-
286
- instance.resetAfterColumnIndex = (columnIndex: number, shouldForceUpdate?: boolean = true) => {
287
- instance.resetAfterIndices({ columnIndex, shouldForceUpdate });
288
- };
289
-
290
- instance.resetAfterRowIndex = (rowIndex: number, shouldForceUpdate?: boolean = true) => {
291
- instance.resetAfterIndices({ rowIndex, shouldForceUpdate });
292
- };
293
-
294
- instance.resetAfterIndices = ({ columnIndex, rowIndex, shouldForceUpdate = true }: { columnIndex?: number, rowIndex?: number, shouldForceUpdate: boolean }) => {
295
- if (typeof columnIndex === 'number') {
296
- instanceProps.lastMeasuredColumnIndex = Math.min(instanceProps.lastMeasuredColumnIndex, columnIndex - 1);
297
- }
298
- if (typeof rowIndex === 'number') {
299
- instanceProps.lastMeasuredRowIndex = Math.min(instanceProps.lastMeasuredRowIndex, rowIndex - 1);
300
- }
301
-
302
- // We could potentially optimize further by only evicting styles after this index,
303
- // But since styles are only cached while scrolling is in progress-
304
- // It seems an unnecessary optimization.
305
- // It's unlikely that resetAfterIndex() will be called while a user is scrolling.
306
- instance._getItemStyleCache(-1);
307
-
308
- if (shouldForceUpdate) {
309
- instance.forceUpdate();
310
- }
311
- };
312
-
313
- return instanceProps;
314
- },
315
-
316
- shouldResetStyleCacheOnItemSizeChange: false,
317
-
318
- validateProps: ({ columnWidth, rowHeight }: Props<any>): void => {
319
- if (process.env.NODE_ENV !== 'production') {
320
- if (typeof columnWidth !== 'function') {
321
- throw Error('An invalid "columnWidth" prop has been specified. ' + 'Value should be a function. ' + `"${columnWidth === null ? 'null' : typeof columnWidth}" was specified.`);
322
- } else if (typeof rowHeight !== 'function') {
323
- throw Error('An invalid "rowHeight" prop has been specified. ' + 'Value should be a function. ' + `"${rowHeight === null ? 'null' : typeof rowHeight}" was specified.`);
324
- }
325
- }
326
- },
327
- });
328
-
329
- export default VariableSizeGrid;
1
+ // @flow
2
+
3
+ import createGridComponent from './createGridComponent';
4
+
5
+ import type { Props, ScrollToAlign } from './createGridComponent';
6
+
7
+ const DEFAULT_ESTIMATED_ITEM_SIZE = 50;
8
+
9
+ type VariableSizeProps = {|
10
+ estimatedColumnWidth: number,
11
+ estimatedRowHeight: number,
12
+ ...Props<any>,
13
+ |};
14
+
15
+ type itemSizeGetter = (index: number) => number;
16
+ type ItemType = 'column' | 'row';
17
+
18
+ type ItemMetadata = {|
19
+ offset: number,
20
+ size: number,
21
+ |};
22
+ type ItemMetadataMap = { [index: number]: ItemMetadata };
23
+ type InstanceProps = {|
24
+ columnMetadataMap: ItemMetadataMap,
25
+ estimatedColumnWidth: number,
26
+ estimatedRowHeight: number,
27
+ lastMeasuredColumnIndex: number,
28
+ lastMeasuredRowIndex: number,
29
+ rowMetadataMap: ItemMetadataMap,
30
+ |};
31
+
32
+ const getEstimatedTotalHeight = ({ rowCount }: Props<any>, { rowMetadataMap, estimatedRowHeight, lastMeasuredRowIndex }: InstanceProps) => {
33
+ let totalSizeOfMeasuredRows = 0;
34
+
35
+ // Edge case check for when the number of items decreases while a scroll is in progress.
36
+ // https://github.com/bvaughn/react-window/pull/138
37
+ if (lastMeasuredRowIndex >= rowCount) {
38
+ lastMeasuredRowIndex = rowCount - 1;
39
+ }
40
+
41
+ if (lastMeasuredRowIndex >= 0) {
42
+ const itemMetadata = rowMetadataMap[lastMeasuredRowIndex];
43
+ totalSizeOfMeasuredRows = itemMetadata.offset + itemMetadata.size;
44
+ }
45
+
46
+ const numUnmeasuredItems = rowCount - lastMeasuredRowIndex - 1;
47
+ const totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedRowHeight;
48
+
49
+ return totalSizeOfMeasuredRows + totalSizeOfUnmeasuredItems;
50
+ };
51
+
52
+ const getEstimatedTotalWidth = ({ columnCount }: Props<any>, { columnMetadataMap, estimatedColumnWidth, lastMeasuredColumnIndex }: InstanceProps) => {
53
+ let totalSizeOfMeasuredRows = 0;
54
+
55
+ // Edge case check for when the number of items decreases while a scroll is in progress.
56
+ // https://github.com/bvaughn/react-window/pull/138
57
+ if (lastMeasuredColumnIndex >= columnCount) {
58
+ lastMeasuredColumnIndex = columnCount - 1;
59
+ }
60
+
61
+ if (lastMeasuredColumnIndex >= 0) {
62
+ const itemMetadata = columnMetadataMap[lastMeasuredColumnIndex];
63
+ totalSizeOfMeasuredRows = itemMetadata.offset + itemMetadata.size;
64
+ }
65
+
66
+ const numUnmeasuredItems = columnCount - lastMeasuredColumnIndex - 1;
67
+ const totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedColumnWidth;
68
+
69
+ return totalSizeOfMeasuredRows + totalSizeOfUnmeasuredItems;
70
+ };
71
+
72
+ const getItemMetadata = (itemType: ItemType, props: Props<any>, index: number, instanceProps: InstanceProps): ItemMetadata => {
73
+ let itemMetadataMap, itemSize, lastMeasuredIndex;
74
+ if (itemType === 'column') {
75
+ itemMetadataMap = instanceProps.columnMetadataMap;
76
+ itemSize = ((props.columnWidth: any): itemSizeGetter);
77
+ lastMeasuredIndex = instanceProps.lastMeasuredColumnIndex;
78
+ } else {
79
+ itemMetadataMap = instanceProps.rowMetadataMap;
80
+ itemSize = ((props.rowHeight: any): itemSizeGetter);
81
+ lastMeasuredIndex = instanceProps.lastMeasuredRowIndex;
82
+ }
83
+
84
+ if (index > lastMeasuredIndex) {
85
+ let offset = 0;
86
+ if (lastMeasuredIndex >= 0) {
87
+ const itemMetadata = itemMetadataMap[lastMeasuredIndex];
88
+ offset = itemMetadata.offset + itemMetadata.size;
89
+ }
90
+
91
+ for (let i = lastMeasuredIndex + 1; i <= index; i++) {
92
+ let size = itemSize(i);
93
+
94
+ itemMetadataMap[i] = {
95
+ offset,
96
+ size,
97
+ };
98
+
99
+ offset += size;
100
+ }
101
+
102
+ if (itemType === 'column') {
103
+ instanceProps.lastMeasuredColumnIndex = index;
104
+ } else {
105
+ instanceProps.lastMeasuredRowIndex = index;
106
+ }
107
+ }
108
+
109
+ return itemMetadataMap[index];
110
+ };
111
+
112
+ const findNearestItem = (itemType: ItemType, props: Props<any>, instanceProps: InstanceProps, offset: number) => {
113
+ let itemMetadataMap, lastMeasuredIndex;
114
+ if (itemType === 'column') {
115
+ itemMetadataMap = instanceProps.columnMetadataMap;
116
+ lastMeasuredIndex = instanceProps.lastMeasuredColumnIndex;
117
+ } else {
118
+ itemMetadataMap = instanceProps.rowMetadataMap;
119
+ lastMeasuredIndex = instanceProps.lastMeasuredRowIndex;
120
+ }
121
+
122
+ const lastMeasuredItemOffset = lastMeasuredIndex > 0 ? itemMetadataMap[lastMeasuredIndex].offset : 0;
123
+
124
+ if (lastMeasuredItemOffset >= offset) {
125
+ // If we've already measured items within this range just use a binary search as it's faster.
126
+ return findNearestItemBinarySearch(itemType, props, instanceProps, lastMeasuredIndex, 0, offset);
127
+ } else {
128
+ // If we haven't yet measured this high, fallback to an exponential search with an inner binary search.
129
+ // The exponential search avoids pre-computing sizes for the full set of items as a binary search would.
130
+ // The overall complexity for this approach is O(log n).
131
+ return findNearestItemExponentialSearch(itemType, props, instanceProps, Math.max(0, lastMeasuredIndex), offset);
132
+ }
133
+ };
134
+
135
+ const findNearestItemBinarySearch = (itemType: ItemType, props: Props<any>, instanceProps: InstanceProps, high: number, low: number, offset: number): number => {
136
+ while (low <= high) {
137
+ const middle = low + Math.floor((high - low) / 2);
138
+ const currentOffset = getItemMetadata(itemType, props, middle, instanceProps).offset;
139
+
140
+ if (currentOffset === offset) {
141
+ return middle;
142
+ } else if (currentOffset < offset) {
143
+ low = middle + 1;
144
+ } else if (currentOffset > offset) {
145
+ high = middle - 1;
146
+ }
147
+ }
148
+
149
+ if (low > 0) {
150
+ return low - 1;
151
+ } else {
152
+ return 0;
153
+ }
154
+ };
155
+
156
+ const findNearestItemExponentialSearch = (itemType: ItemType, props: Props<any>, instanceProps: InstanceProps, index: number, offset: number): number => {
157
+ const itemCount = itemType === 'column' ? props.columnCount : props.rowCount;
158
+ let interval = 1;
159
+
160
+ while (index < itemCount && getItemMetadata(itemType, props, index, instanceProps).offset < offset) {
161
+ index += interval;
162
+ interval *= 2;
163
+ }
164
+
165
+ return findNearestItemBinarySearch(itemType, props, instanceProps, Math.min(index, itemCount - 1), Math.floor(index / 2), offset);
166
+ };
167
+
168
+ const getOffsetForIndexAndAlignment = (
169
+ itemType: ItemType,
170
+ props: Props<any>,
171
+ index: number,
172
+ align: ScrollToAlign,
173
+ scrollOffset: number,
174
+ instanceProps: InstanceProps,
175
+ scrollbarSize: number,
176
+ ): number => {
177
+ const size = itemType === 'column' ? props.width : props.height;
178
+ const itemMetadata = getItemMetadata(itemType, props, index, instanceProps);
179
+
180
+ // Get estimated total size after ItemMetadata is computed,
181
+ // To ensure it reflects actual measurements instead of just estimates.
182
+ const estimatedTotalSize = itemType === 'column' ? getEstimatedTotalWidth(props, instanceProps) : getEstimatedTotalHeight(props, instanceProps);
183
+
184
+ const maxOffset = Math.max(0, Math.min(estimatedTotalSize - size, itemMetadata.offset));
185
+ const minOffset = Math.max(0, itemMetadata.offset - size + scrollbarSize + itemMetadata.size);
186
+
187
+ if (align === 'smart') {
188
+ if (scrollOffset >= minOffset - size && scrollOffset <= maxOffset + size) {
189
+ align = 'auto';
190
+ } else {
191
+ align = 'center';
192
+ }
193
+ }
194
+
195
+ switch (align) {
196
+ case 'start':
197
+ return maxOffset;
198
+ case 'end':
199
+ return minOffset;
200
+ case 'center':
201
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
202
+ case 'auto':
203
+ default:
204
+ if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
205
+ return scrollOffset;
206
+ } else if (minOffset > maxOffset) {
207
+ // Because we only take into account the scrollbar size when calculating minOffset
208
+ // this value can be larger than maxOffset when at the end of the list
209
+ return minOffset;
210
+ } else if (scrollOffset < minOffset) {
211
+ return minOffset;
212
+ } else {
213
+ return maxOffset;
214
+ }
215
+ }
216
+ };
217
+
218
+ const VariableSizeGrid = createGridComponent({
219
+ getColumnOffset: (props: Props<any>, index: number, instanceProps: InstanceProps): number => getItemMetadata('column', props, index, instanceProps).offset,
220
+
221
+ getColumnStartIndexForOffset: (props: Props<any>, scrollLeft: number, instanceProps: InstanceProps): number => findNearestItem('column', props, instanceProps, scrollLeft),
222
+
223
+ getColumnStopIndexForStartIndex: (props: Props<any>, startIndex: number, scrollLeft: number, instanceProps: InstanceProps): number => {
224
+ const { columnCount, width } = props;
225
+
226
+ const itemMetadata = getItemMetadata('column', props, startIndex, instanceProps);
227
+ const maxOffset = scrollLeft + width;
228
+
229
+ let offset = itemMetadata.offset + itemMetadata.size;
230
+ let stopIndex = startIndex;
231
+
232
+ while (stopIndex < columnCount - 1 && offset < maxOffset) {
233
+ stopIndex++;
234
+ offset += getItemMetadata('column', props, stopIndex, instanceProps).size;
235
+ }
236
+
237
+ return stopIndex;
238
+ },
239
+
240
+ getColumnWidth: (props: Props<any>, index: number, instanceProps: InstanceProps): number => instanceProps.columnMetadataMap[index].size,
241
+
242
+ getEstimatedTotalHeight,
243
+ getEstimatedTotalWidth,
244
+
245
+ getOffsetForColumnAndAlignment: (props: Props<any>, index: number, align: ScrollToAlign, scrollOffset: number, instanceProps: InstanceProps, scrollbarSize: number): number =>
246
+ getOffsetForIndexAndAlignment('column', props, index, align, scrollOffset, instanceProps, scrollbarSize),
247
+
248
+ getOffsetForRowAndAlignment: (props: Props<any>, index: number, align: ScrollToAlign, scrollOffset: number, instanceProps: InstanceProps, scrollbarSize: number): number =>
249
+ getOffsetForIndexAndAlignment('row', props, index, align, scrollOffset, instanceProps, scrollbarSize),
250
+
251
+ getRowOffset: (props: Props<any>, index: number, instanceProps: InstanceProps): number => getItemMetadata('row', props, index, instanceProps).offset,
252
+
253
+ getRowHeight: (props: Props<any>, index: number, instanceProps: InstanceProps): number => instanceProps.rowMetadataMap[index].size,
254
+
255
+ getRowStartIndexForOffset: (props: Props<any>, scrollTop: number, instanceProps: InstanceProps): number => findNearestItem('row', props, instanceProps, scrollTop),
256
+
257
+ getRowStopIndexForStartIndex: (props: Props<any>, startIndex: number, scrollTop: number, instanceProps: InstanceProps): number => {
258
+ const { rowCount, height } = props;
259
+
260
+ const itemMetadata = getItemMetadata('row', props, startIndex, instanceProps);
261
+ const maxOffset = scrollTop + height;
262
+
263
+ let offset = itemMetadata.offset + itemMetadata.size;
264
+ let stopIndex = startIndex;
265
+
266
+ while (stopIndex < rowCount - 1 && offset < maxOffset) {
267
+ stopIndex++;
268
+ offset += getItemMetadata('row', props, stopIndex, instanceProps).size;
269
+ }
270
+
271
+ return stopIndex;
272
+ },
273
+
274
+ initInstanceProps(props: Props<any>, instance: any): InstanceProps {
275
+ const { estimatedColumnWidth, estimatedRowHeight } = ((props: any): VariableSizeProps);
276
+
277
+ const instanceProps = {
278
+ columnMetadataMap: {},
279
+ estimatedColumnWidth: estimatedColumnWidth || DEFAULT_ESTIMATED_ITEM_SIZE,
280
+ estimatedRowHeight: estimatedRowHeight || DEFAULT_ESTIMATED_ITEM_SIZE,
281
+ lastMeasuredColumnIndex: -1,
282
+ lastMeasuredRowIndex: -1,
283
+ rowMetadataMap: {},
284
+ };
285
+
286
+ instance.resetAfterColumnIndex = (columnIndex: number, shouldForceUpdate?: boolean = true) => {
287
+ instance.resetAfterIndices({ columnIndex, shouldForceUpdate });
288
+ };
289
+
290
+ instance.resetAfterRowIndex = (rowIndex: number, shouldForceUpdate?: boolean = true) => {
291
+ instance.resetAfterIndices({ rowIndex, shouldForceUpdate });
292
+ };
293
+
294
+ instance.resetAfterIndices = ({ columnIndex, rowIndex, shouldForceUpdate = true }: { columnIndex?: number, rowIndex?: number, shouldForceUpdate: boolean }) => {
295
+ if (typeof columnIndex === 'number') {
296
+ instanceProps.lastMeasuredColumnIndex = Math.min(instanceProps.lastMeasuredColumnIndex, columnIndex - 1);
297
+ }
298
+ if (typeof rowIndex === 'number') {
299
+ instanceProps.lastMeasuredRowIndex = Math.min(instanceProps.lastMeasuredRowIndex, rowIndex - 1);
300
+ }
301
+
302
+ // We could potentially optimize further by only evicting styles after this index,
303
+ // But since styles are only cached while scrolling is in progress-
304
+ // It seems an unnecessary optimization.
305
+ // It's unlikely that resetAfterIndex() will be called while a user is scrolling.
306
+ instance._getItemStyleCache(-1);
307
+
308
+ if (shouldForceUpdate) {
309
+ instance.forceUpdate();
310
+ }
311
+ };
312
+
313
+ return instanceProps;
314
+ },
315
+
316
+ shouldResetStyleCacheOnItemSizeChange: false,
317
+
318
+ validateProps: ({ columnWidth, rowHeight }: Props<any>): void => {
319
+ if (process.env.NODE_ENV !== 'production') {
320
+ if (typeof columnWidth !== 'function') {
321
+ throw Error('An invalid "columnWidth" prop has been specified. ' + 'Value should be a function. ' + `"${columnWidth === null ? 'null' : typeof columnWidth}" was specified.`);
322
+ } else if (typeof rowHeight !== 'function') {
323
+ throw Error('An invalid "rowHeight" prop has been specified. ' + 'Value should be a function. ' + `"${rowHeight === null ? 'null' : typeof rowHeight}" was specified.`);
324
+ }
325
+ }
326
+ },
327
+ });
328
+
329
+ export default VariableSizeGrid;