@legendapp/list 3.0.0-beta.2 → 3.0.0-beta.21

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 (47) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -0
  3. package/animated.native.d.mts +9 -0
  4. package/animated.native.d.ts +9 -0
  5. package/animated.native.js +9 -0
  6. package/animated.native.mjs +7 -0
  7. package/index.d.mts +781 -10
  8. package/index.d.ts +781 -10
  9. package/index.js +973 -530
  10. package/index.mjs +973 -532
  11. package/index.native.d.mts +781 -10
  12. package/index.native.d.ts +781 -10
  13. package/index.native.js +981 -494
  14. package/index.native.mjs +980 -495
  15. package/keyboard-controller.native.d.mts +12 -0
  16. package/keyboard-controller.native.d.ts +12 -0
  17. package/keyboard-controller.native.js +69 -0
  18. package/keyboard-controller.native.mjs +48 -0
  19. package/keyboard.d.mts +5 -2
  20. package/keyboard.d.ts +5 -2
  21. package/keyboard.js +232 -28
  22. package/keyboard.mjs +235 -31
  23. package/keyboard.native.d.mts +16 -0
  24. package/keyboard.native.d.ts +16 -0
  25. package/keyboard.native.js +318 -0
  26. package/keyboard.native.mjs +296 -0
  27. package/package.json +1 -1
  28. package/reanimated.d.mts +3 -3
  29. package/reanimated.d.ts +3 -3
  30. package/reanimated.js +15 -4
  31. package/reanimated.mjs +14 -3
  32. package/reanimated.native.d.mts +18 -0
  33. package/reanimated.native.d.ts +18 -0
  34. package/reanimated.native.js +89 -0
  35. package/reanimated.native.mjs +65 -0
  36. package/section-list.d.mts +1 -2
  37. package/section-list.d.ts +1 -2
  38. package/section-list.js +36 -3670
  39. package/section-list.mjs +34 -3669
  40. package/section-list.native.d.mts +1 -2
  41. package/section-list.native.d.ts +1 -2
  42. package/section-list.native.js +36 -3449
  43. package/section-list.native.mjs +33 -3447
  44. package/types-JPHClxiw.d.mts +0 -670
  45. package/types-JPHClxiw.d.ts +0 -670
  46. package/types-YNdphn_A.d.mts +0 -670
  47. package/types-YNdphn_A.d.ts +0 -670
@@ -1,3432 +1,18 @@
1
- import * as React2 from 'react';
2
- import React2__default, { useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle, forwardRef, memo, useContext } from 'react';
3
- import { Animated, View as View$1, Platform, RefreshControl, Text as Text$1, unstable_batchedUpdates, Dimensions, StyleSheet as StyleSheet$1 } from 'react-native';
4
- import { useSyncExternalStore } from 'use-sync-external-store/shim';
1
+ import * as React from 'react';
2
+ import { Platform } from 'react-native';
3
+ import { typedMemo, typedForwardRef, LegendList } from '@legendapp/list';
5
4
 
6
5
  // src/section-list/SectionList.tsx
7
- Animated.View;
8
- var View = View$1;
9
- var Text = Text$1;
10
- var createAnimatedValue = (value) => new Animated.Value(value);
11
-
12
- // src/state/state.tsx
13
- var ContextState = React2.createContext(null);
14
- function StateProvider({ children }) {
15
- const [value] = React2.useState(() => ({
16
- animatedScrollY: createAnimatedValue(0),
17
- columnWrapperStyle: void 0,
18
- internalState: void 0,
19
- listeners: /* @__PURE__ */ new Map(),
20
- mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
21
- mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
22
- mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
23
- mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
24
- mapViewabilityValues: /* @__PURE__ */ new Map(),
25
- values: /* @__PURE__ */ new Map([
26
- ["alignItemsPaddingTop", 0],
27
- ["stylePaddingTop", 0],
28
- ["headerSize", 0],
29
- ["numContainers", 0],
30
- ["activeStickyIndex", void 0],
31
- ["totalSize", 0],
32
- ["scrollAdjustPending", 0],
33
- ["scrollingTo", void 0]
34
- ]),
35
- viewRefs: /* @__PURE__ */ new Map()
36
- }));
37
- return /* @__PURE__ */ React2.createElement(ContextState.Provider, { value }, children);
38
- }
39
- function useStateContext() {
40
- return React2.useContext(ContextState);
41
- }
42
- function createSelectorFunctionsArr(ctx, signalNames) {
43
- let lastValues = [];
44
- let lastSignalValues = [];
45
- return {
46
- get: () => {
47
- const currentValues = [];
48
- let hasChanged = false;
49
- for (let i = 0; i < signalNames.length; i++) {
50
- const value = peek$(ctx, signalNames[i]);
51
- currentValues.push(value);
52
- if (value !== lastSignalValues[i]) {
53
- hasChanged = true;
54
- }
55
- }
56
- lastSignalValues = currentValues;
57
- if (hasChanged) {
58
- lastValues = currentValues;
59
- }
60
- return lastValues;
61
- },
62
- subscribe: (cb) => {
63
- const listeners = [];
64
- for (const signalName of signalNames) {
65
- listeners.push(listen$(ctx, signalName, cb));
66
- }
67
- return () => {
68
- for (const listener of listeners) {
69
- listener();
70
- }
71
- };
72
- }
73
- };
74
- }
75
- function listen$(ctx, signalName, cb) {
76
- const { listeners } = ctx;
77
- let setListeners = listeners.get(signalName);
78
- if (!setListeners) {
79
- setListeners = /* @__PURE__ */ new Set();
80
- listeners.set(signalName, setListeners);
81
- }
82
- setListeners.add(cb);
83
- return () => setListeners.delete(cb);
84
- }
85
- function peek$(ctx, signalName) {
86
- const { values } = ctx;
87
- return values.get(signalName);
88
- }
89
- function set$(ctx, signalName, value) {
90
- const { listeners, values } = ctx;
91
- if (values.get(signalName) !== value) {
92
- values.set(signalName, value);
93
- const setListeners = listeners.get(signalName);
94
- if (setListeners) {
95
- for (const listener of setListeners) {
96
- listener(value);
97
- }
98
- }
99
- }
100
- }
101
- function getContentSize(ctx) {
102
- var _a3, _b;
103
- const { values, internalState } = ctx;
104
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
105
- const stylePaddingBottom = (internalState == null ? void 0 : internalState.props.stylePaddingBottom) || 0;
106
- const headerSize = values.get("headerSize") || 0;
107
- const footerSize = values.get("footerSize") || 0;
108
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
109
- return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom;
110
- }
111
- function useArr$(signalNames) {
112
- const ctx = React2.useContext(ContextState);
113
- const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
114
- const value = useSyncExternalStore(subscribe, get);
115
- return value;
116
- }
117
- function useSelector$(signalName, selector) {
118
- const ctx = React2.useContext(ContextState);
119
- const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
120
- const value = useSyncExternalStore(subscribe, () => selector(get()[0]));
121
- return value;
122
- }
123
-
124
- // src/components/DebugView.tsx
125
- var DebugRow = ({ children }) => {
126
- return /* @__PURE__ */ React2.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
127
- };
128
- var DebugView = React2.memo(function DebugView2({ state }) {
129
- const ctx = useStateContext();
130
- const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
131
- "totalSize",
132
- "scrollAdjust",
133
- "debugRawScroll",
134
- "debugComputedScroll",
135
- "numContainers",
136
- "numContainersPooled"
137
- ]);
138
- const contentSize = getContentSize(ctx);
139
- const [, forceUpdate] = useReducer((x) => x + 1, 0);
140
- useInterval(() => {
141
- forceUpdate();
142
- }, 100);
143
- return /* @__PURE__ */ React2.createElement(
144
- View,
145
- {
146
- pointerEvents: "none",
147
- style: {
148
- // height: 100,
149
- backgroundColor: "#FFFFFFCC",
150
- borderRadius: 4,
151
- padding: 4,
152
- paddingBottom: 4,
153
- paddingLeft: 4,
154
- position: "absolute",
155
- right: 0,
156
- top: 0
157
- }
158
- },
159
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React2.createElement(Text, null, totalSize.toFixed(2))),
160
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React2.createElement(Text, null, contentSize.toFixed(2))),
161
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "At end:"), /* @__PURE__ */ React2.createElement(Text, null, String(state.isAtEnd))),
162
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React2.createElement(Text, null, scrollAdjust.toFixed(2))),
163
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React2.createElement(Text, null, rawScroll.toFixed(2))),
164
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React2.createElement(Text, null, scroll.toFixed(2)))
165
- );
166
- });
167
- function useInterval(callback, delay) {
168
- useEffect(() => {
169
- const interval = setInterval(callback, delay);
170
- return () => clearInterval(interval);
171
- }, [delay]);
172
- }
173
-
174
- // src/utils/devEnvironment.ts
175
- var metroDev = typeof __DEV__ !== "undefined" ? __DEV__ : void 0;
176
- var _a;
177
- var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
178
- var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
179
- var _a2;
180
- var IS_DEV = (_a2 = metroDev != null ? metroDev : processDev) != null ? _a2 : false;
181
-
182
- // src/constants.ts
183
- var POSITION_OUT_OF_VIEW = -1e7;
184
- var ENABLE_DEVMODE = IS_DEV && false;
185
- var ENABLE_DEBUG_VIEW = IS_DEV && false;
186
-
187
- // src/constants-platform.native.ts
188
- var IsNewArchitecture = global.nativeFabricUIManager != null;
189
- var useAnimatedValue = (initialValue) => {
190
- return useRef(new Animated.Value(initialValue)).current;
191
- };
192
-
193
- // src/utils/helpers.ts
194
- function isFunction(obj) {
195
- return typeof obj === "function";
196
- }
197
- function isArray(obj) {
198
- return Array.isArray(obj);
199
- }
200
- var warned = /* @__PURE__ */ new Set();
201
- function warnDevOnce(id, text) {
202
- if (IS_DEV && !warned.has(id)) {
203
- warned.add(id);
204
- console.warn(`[legend-list] ${text}`);
205
- }
206
- }
207
- function roundSize(size) {
208
- return Math.floor(size * 8) / 8;
209
- }
210
- function isNullOrUndefined(value) {
211
- return value === null || value === void 0;
212
- }
213
- function comparatorDefault(a, b) {
214
- return a - b;
215
- }
216
- function getPadding(s, type) {
217
- var _a3, _b, _c;
218
- return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
219
- }
220
- function extractPadding(style, contentContainerStyle, type) {
221
- return getPadding(style, type) + getPadding(contentContainerStyle, type);
222
- }
223
- function findContainerId(ctx, key) {
224
- const numContainers = peek$(ctx, "numContainers");
225
- for (let i = 0; i < numContainers; i++) {
226
- const itemKey = peek$(ctx, `containerItemKey${i}`);
227
- if (itemKey === key) {
228
- return i;
229
- }
230
- }
231
- return -1;
232
- }
233
-
234
- // src/hooks/useValue$.ts
235
- function useValue$(key, params) {
236
- const { getValue, delay } = params || {};
237
- const ctx = useStateContext();
238
- const getNewValue = () => {
239
- var _a3;
240
- return (_a3 = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a3 : 0;
241
- };
242
- const animValue = useAnimatedValue(getNewValue());
243
- useMemo(() => {
244
- let prevValue;
245
- let didQueueTask = false;
246
- listen$(ctx, key, (v) => {
247
- const newValue = getNewValue();
248
- if (delay !== void 0) {
249
- const fn = () => {
250
- didQueueTask = false;
251
- const latestValue = getNewValue();
252
- if (latestValue !== void 0) {
253
- animValue.setValue(latestValue);
254
- }
255
- };
256
- const delayValue = isFunction(delay) ? delay(newValue, prevValue) : delay;
257
- prevValue = newValue;
258
- if (!didQueueTask) {
259
- didQueueTask = true;
260
- if (delayValue === void 0) {
261
- fn();
262
- } else if (delayValue === 0) {
263
- queueMicrotask(fn);
264
- } else {
265
- setTimeout(fn, delayValue);
266
- }
267
- }
268
- } else {
269
- animValue.setValue(newValue);
270
- }
271
- });
272
- }, []);
273
- return animValue;
274
- }
275
- var typedForwardRef = forwardRef;
276
- var typedMemo = memo;
277
-
278
- // src/components/PositionView.native.tsx
279
- var PositionViewState = typedMemo(function PositionView({
280
- id,
281
- horizontal,
282
- style,
283
- refView,
284
- ...rest
285
- }) {
286
- const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
287
- return /* @__PURE__ */ React2.createElement(
288
- View$1,
289
- {
290
- ref: refView,
291
- style: [
292
- style,
293
- horizontal ? { transform: [{ translateX: position }] } : { transform: [{ translateY: position }] }
294
- ],
295
- ...rest
296
- }
297
- );
298
- });
299
- var PositionViewAnimated = typedMemo(function PositionView2({
300
- id,
301
- horizontal,
302
- style,
303
- refView,
304
- ...rest
305
- }) {
306
- const position$ = useValue$(`containerPosition${id}`, {
307
- getValue: (v) => v != null ? v : POSITION_OUT_OF_VIEW
308
- });
309
- let position;
310
- if (Platform.OS === "ios" || Platform.OS === "android") {
311
- position = horizontal ? { transform: [{ translateX: position$ }] } : { transform: [{ translateY: position$ }] };
312
- } else {
313
- position = horizontal ? { left: position$ } : { top: position$ };
314
- }
315
- return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: [style, position], ...rest });
316
- });
317
- var PositionViewSticky = typedMemo(function PositionViewSticky2({
318
- id,
319
- horizontal,
320
- style,
321
- refView,
322
- animatedScrollY,
323
- stickyOffset,
324
- index,
325
- ...rest
326
- }) {
327
- const [position = POSITION_OUT_OF_VIEW, headerSize] = useArr$([`containerPosition${id}`, "headerSize"]);
328
- const transform = React2.useMemo(() => {
329
- if (animatedScrollY && stickyOffset !== void 0) {
330
- const stickyPosition = animatedScrollY.interpolate({
331
- extrapolateLeft: "clamp",
332
- extrapolateRight: "extend",
333
- inputRange: [position + headerSize, position + 5e3 + headerSize],
334
- outputRange: [position, position + 5e3]
335
- });
336
- return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
337
- }
338
- }, [animatedScrollY, headerSize, horizontal, stickyOffset, position]);
339
- const viewStyle = React2.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
340
- return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: viewStyle, ...rest });
341
- });
342
- var PositionView3 = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
343
- var symbolFirst = Symbol();
344
- function useInit(cb) {
345
- const refValue = useRef(symbolFirst);
346
- if (refValue.current === symbolFirst) {
347
- refValue.current = cb();
348
- }
349
- return refValue.current;
350
- }
351
-
352
- // src/state/ContextContainer.ts
353
- var ContextContainer = createContext(null);
354
- function useIsLastItem() {
355
- const { itemKey } = useContext(ContextContainer);
356
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
357
- return isLast;
358
- }
359
-
360
- // src/components/Separator.tsx
361
- function Separator({ ItemSeparatorComponent, leadingItem }) {
362
- const isLastItem = useIsLastItem();
363
- return isLastItem ? null : /* @__PURE__ */ React2.createElement(ItemSeparatorComponent, { leadingItem });
364
- }
365
- function useOnLayoutSync({
366
- ref,
367
- onLayoutProp,
368
- onLayoutChange
369
- }, deps = []) {
370
- const lastLayoutRef = useRef(null);
371
- const onLayout = useCallback(
372
- (event) => {
373
- var _a3, _b;
374
- const { layout } = event.nativeEvent;
375
- if (layout.height !== ((_a3 = lastLayoutRef.current) == null ? void 0 : _a3.height) || layout.width !== ((_b = lastLayoutRef.current) == null ? void 0 : _b.width)) {
376
- onLayoutChange(layout, false);
377
- onLayoutProp == null ? void 0 : onLayoutProp(event);
378
- lastLayoutRef.current = layout;
379
- }
380
- },
381
- [onLayoutChange]
382
- );
383
- if (IsNewArchitecture) {
384
- useLayoutEffect(() => {
385
- if (ref.current) {
386
- ref.current.measure((x, y, width, height) => {
387
- const layout = { height, width, x, y };
388
- lastLayoutRef.current = layout;
389
- onLayoutChange(layout, true);
390
- });
391
- }
392
- }, deps);
393
- }
394
- return { onLayout };
395
- }
396
-
397
- // src/components/Container.tsx
398
- var Container = typedMemo(function Container2({
399
- id,
400
- recycleItems,
401
- horizontal,
402
- getRenderedItem: getRenderedItem2,
403
- updateItemSize: updateItemSize2,
404
- ItemSeparatorComponent
405
- }) {
406
- const ctx = useStateContext();
407
- const { columnWrapperStyle, animatedScrollY } = ctx;
408
- const [column = 0, data, itemKey, numColumns, extraData, isSticky, stickyOffset] = useArr$([
409
- `containerColumn${id}`,
410
- `containerItemData${id}`,
411
- `containerItemKey${id}`,
412
- "numColumns",
413
- "extraData",
414
- `containerSticky${id}`,
415
- `containerStickyOffset${id}`
416
- ]);
417
- const itemLayoutRef = useRef({
418
- horizontal,
419
- itemKey,
420
- updateItemSize: updateItemSize2
421
- });
422
- itemLayoutRef.current.horizontal = horizontal;
423
- itemLayoutRef.current.itemKey = itemKey;
424
- itemLayoutRef.current.updateItemSize = updateItemSize2;
425
- const ref = useRef(null);
426
- const [layoutRenderCount, forceLayoutRender] = useState(0);
427
- const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
428
- const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
429
- const didLayoutRef = useRef(false);
430
- const style = useMemo(() => {
431
- let paddingStyles;
432
- if (columnWrapperStyle) {
433
- const { columnGap, rowGap, gap } = columnWrapperStyle;
434
- if (horizontal) {
435
- paddingStyles = {
436
- paddingRight: columnGap || gap || void 0,
437
- paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
438
- };
439
- } else {
440
- paddingStyles = {
441
- paddingBottom: rowGap || gap || void 0,
442
- paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
443
- };
444
- }
445
- }
446
- return horizontal ? {
447
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
448
- height: otherAxisSize,
449
- left: 0,
450
- position: "absolute",
451
- top: otherAxisPos,
452
- ...paddingStyles || {}
453
- } : {
454
- left: otherAxisPos,
455
- position: "absolute",
456
- right: numColumns > 1 ? null : 0,
457
- top: 0,
458
- width: otherAxisSize,
459
- ...paddingStyles || {}
460
- };
461
- }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
462
- const renderedItemInfo = useMemo(
463
- () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
464
- [itemKey, data, extraData]
465
- );
466
- const { index, renderedItem } = renderedItemInfo || {};
467
- const contextValue = useMemo(() => {
468
- ctx.viewRefs.set(id, ref);
469
- return {
470
- containerId: id,
471
- index,
472
- itemKey,
473
- triggerLayout: () => {
474
- forceLayoutRender((v) => v + 1);
475
- },
476
- value: data
477
- };
478
- }, [id, itemKey, index, data]);
479
- const onLayoutChange = useCallback((rectangle) => {
480
- var _a3, _b;
481
- const {
482
- horizontal: currentHorizontal,
483
- itemKey: currentItemKey,
484
- updateItemSize: updateItemSizeFn
485
- } = itemLayoutRef.current;
486
- if (isNullOrUndefined(currentItemKey)) {
487
- return;
488
- }
489
- didLayoutRef.current = true;
490
- let layout = rectangle;
491
- const size = roundSize(rectangle[currentHorizontal ? "width" : "height"]);
492
- const doUpdate = () => {
493
- itemLayoutRef.current.lastSize = { height: layout.height, width: layout.width };
494
- updateItemSizeFn(currentItemKey, layout);
495
- didLayoutRef.current = true;
496
- };
497
- if (IsNewArchitecture || size > 0) {
498
- doUpdate();
499
- } else {
500
- (_b = (_a3 = ref.current) == null ? void 0 : _a3.measure) == null ? void 0 : _b.call(_a3, (_x, _y, width, height) => {
501
- layout = { height, width };
502
- doUpdate();
503
- });
504
- }
505
- }, []);
506
- const { onLayout } = useOnLayoutSync(
507
- {
508
- onLayoutChange,
509
- ref
510
- },
511
- [itemKey, layoutRenderCount]
512
- );
513
- if (!IsNewArchitecture) {
514
- useEffect(() => {
515
- if (!isNullOrUndefined(itemKey)) {
516
- const timeout = setTimeout(() => {
517
- if (!didLayoutRef.current) {
518
- const {
519
- itemKey: currentItemKey,
520
- lastSize,
521
- updateItemSize: updateItemSizeFn
522
- } = itemLayoutRef.current;
523
- if (lastSize && !isNullOrUndefined(currentItemKey)) {
524
- updateItemSizeFn(currentItemKey, lastSize);
525
- didLayoutRef.current = true;
526
- }
527
- }
528
- }, 16);
529
- return () => {
530
- clearTimeout(timeout);
531
- };
532
- }
533
- }, [itemKey]);
534
- }
535
- const PositionComponent = isSticky ? PositionViewSticky : PositionView3;
536
- return /* @__PURE__ */ React2.createElement(
537
- PositionComponent,
538
- {
539
- animatedScrollY: isSticky ? animatedScrollY : void 0,
540
- horizontal,
541
- id,
542
- index,
543
- key: recycleItems ? void 0 : itemKey,
544
- onLayout,
545
- refView: ref,
546
- stickyOffset: isSticky ? stickyOffset : void 0,
547
- style
548
- },
549
- /* @__PURE__ */ React2.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React2.createElement(Separator, { ItemSeparatorComponent, leadingItem: renderedItemInfo.item }))
550
- );
551
- });
552
-
553
- // src/components/Containers.native.tsx
554
- var Containers = typedMemo(function Containers2({
555
- horizontal,
556
- recycleItems,
557
- ItemSeparatorComponent,
558
- waitForInitialLayout,
559
- updateItemSize: updateItemSize2,
560
- getRenderedItem: getRenderedItem2
561
- }) {
562
- const ctx = useStateContext();
563
- const columnWrapperStyle = ctx.columnWrapperStyle;
564
- const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
565
- const animSize = useValue$("totalSize", {
566
- // Use a microtask if increasing the size significantly, otherwise use a timeout
567
- // If this is the initial scroll, we don't want to delay because we want to update the size immediately
568
- delay: (value, prevValue) => {
569
- var _a3;
570
- return !((_a3 = ctx.internalState) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
571
- }
572
- });
573
- const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("containersDidLayout", { getValue: (value) => value ? 1 : 0 }) : void 0;
574
- const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
575
- const containers = [];
576
- for (let i = 0; i < numContainers; i++) {
577
- containers.push(
578
- /* @__PURE__ */ React2.createElement(
579
- Container,
580
- {
581
- getRenderedItem: getRenderedItem2,
582
- horizontal,
583
- ItemSeparatorComponent,
584
- id: i,
585
- key: i,
586
- recycleItems,
587
- updateItemSize: updateItemSize2
588
- }
589
- )
590
- );
591
- }
592
- const style = horizontal ? { minHeight: otherAxisSize, opacity: animOpacity, width: animSize } : { height: animSize, minWidth: otherAxisSize, opacity: animOpacity };
593
- if (columnWrapperStyle && numColumns > 1) {
594
- const { columnGap, rowGap, gap } = columnWrapperStyle;
595
- const gapX = columnGap || gap || 0;
596
- const gapY = rowGap || gap || 0;
597
- if (horizontal) {
598
- if (gapY) {
599
- style.marginVertical = -gapY / 2;
600
- }
601
- if (gapX) {
602
- style.marginRight = -gapX;
603
- }
604
- } else {
605
- if (gapX) {
606
- style.marginHorizontal = -gapX;
607
- }
608
- if (gapY) {
609
- style.marginBottom = -gapY;
610
- }
611
- }
612
- }
613
- return /* @__PURE__ */ React2.createElement(Animated.View, { style }, containers);
614
- });
615
- function DevNumbers() {
616
- return IS_DEV && React2.memo(function DevNumbers2() {
617
- return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React2.createElement(
618
- View$1,
619
- {
620
- key: index,
621
- style: {
622
- height: 100,
623
- pointerEvents: "none",
624
- position: "absolute",
625
- top: index * 100,
626
- width: "100%"
627
- }
628
- },
629
- /* @__PURE__ */ React2.createElement(Text$1, { style: { color: "red" } }, index * 100)
630
- ));
631
- });
632
- }
633
- var ListComponentScrollView = Animated.ScrollView;
634
- function Padding() {
635
- const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
636
- return /* @__PURE__ */ React2.createElement(Animated.View, { style: { paddingTop: animPaddingTop } });
637
- }
638
- function PaddingDevMode() {
639
- const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
640
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React2.createElement(
641
- Animated.View,
642
- {
643
- style: {
644
- backgroundColor: "green",
645
- height: animPaddingTop,
646
- left: 0,
647
- position: "absolute",
648
- right: 0,
649
- top: 0
650
- }
651
- }
652
- ));
653
- }
654
- function ScrollAdjust() {
655
- const bias = 1e7;
656
- const [scrollAdjust, scrollAdjustUserOffset] = useArr$(["scrollAdjust", "scrollAdjustUserOffset"]);
657
- const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0) + bias;
658
- return /* @__PURE__ */ React2.createElement(
659
- View$1,
660
- {
661
- style: {
662
- height: 0,
663
- left: 0,
664
- position: "absolute",
665
- top: scrollOffset,
666
- width: 0
667
- }
668
- }
669
- );
670
- }
671
- function SnapWrapper({ ScrollComponent, ...props }) {
672
- const [snapToOffsets] = useArr$(["snapToOffsets"]);
673
- return /* @__PURE__ */ React2.createElement(ScrollComponent, { ...props, snapToOffsets });
674
- }
675
- var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
676
- const ref = refView != null ? refView : useRef();
677
- const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
678
- return /* @__PURE__ */ React2.createElement(View$1, { ...rest, onLayout, ref });
679
- };
680
-
681
- // src/components/ListComponent.tsx
682
- var getComponent = (Component) => {
683
- if (React2.isValidElement(Component)) {
684
- return Component;
685
- }
686
- if (Component) {
687
- return /* @__PURE__ */ React2.createElement(Component, null);
688
- }
689
- return null;
690
- };
691
- var ListComponent = typedMemo(function ListComponent2({
692
- canRender,
693
- style,
694
- contentContainerStyle,
695
- horizontal,
696
- initialContentOffset,
697
- recycleItems,
698
- ItemSeparatorComponent,
699
- alignItemsAtEnd,
700
- waitForInitialLayout,
701
- onScroll: onScroll2,
702
- onLayout,
703
- ListHeaderComponent,
704
- ListHeaderComponentStyle,
705
- ListFooterComponent,
706
- ListFooterComponentStyle,
707
- ListEmptyComponent,
708
- getRenderedItem: getRenderedItem2,
709
- updateItemSize: updateItemSize2,
710
- refScrollView,
711
- maintainVisibleContentPosition,
712
- renderScrollComponent,
713
- scrollAdjustHandler,
714
- onLayoutHeader,
715
- snapToIndices,
716
- stickyHeaderIndices,
717
- ...rest
718
- }) {
719
- const ctx = useStateContext();
720
- const ScrollComponent = renderScrollComponent ? useMemo(
721
- () => React2.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
722
- [renderScrollComponent]
723
- ) : ListComponentScrollView;
724
- React2.useEffect(() => {
725
- if (canRender) {
726
- setTimeout(() => {
727
- scrollAdjustHandler.setMounted();
728
- }, 0);
729
- }
730
- }, [canRender]);
731
- const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
732
- return /* @__PURE__ */ React2.createElement(
733
- SnapOrScroll,
734
- {
735
- ...rest,
736
- contentContainerStyle: [
737
- contentContainerStyle,
738
- horizontal ? {
739
- height: "100%"
740
- } : {}
741
- ],
742
- contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
743
- horizontal,
744
- maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
745
- onLayout,
746
- onScroll: onScroll2,
747
- ref: refScrollView,
748
- ScrollComponent: snapToIndices ? ScrollComponent : void 0,
749
- style
750
- },
751
- /* @__PURE__ */ React2.createElement(ScrollAdjust, null),
752
- ENABLE_DEVMODE ? /* @__PURE__ */ React2.createElement(PaddingDevMode, null) : /* @__PURE__ */ React2.createElement(Padding, null),
753
- ListHeaderComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
754
- ListEmptyComponent && getComponent(ListEmptyComponent),
755
- canRender && !ListEmptyComponent && /* @__PURE__ */ React2.createElement(
756
- Containers,
757
- {
758
- getRenderedItem: getRenderedItem2,
759
- horizontal,
760
- ItemSeparatorComponent,
761
- recycleItems,
762
- updateItemSize: updateItemSize2,
763
- waitForInitialLayout
764
- }
765
- ),
766
- ListFooterComponent && /* @__PURE__ */ React2.createElement(
767
- LayoutView,
768
- {
769
- onLayoutChange: (layout) => {
770
- const size = layout[horizontal ? "width" : "height"];
771
- set$(ctx, "footerSize", size);
772
- },
773
- style: ListFooterComponentStyle
774
- },
775
- getComponent(ListFooterComponent)
776
- ),
777
- IS_DEV && ENABLE_DEVMODE && /* @__PURE__ */ React2.createElement(DevNumbers, null)
778
- );
779
- });
780
-
781
- // src/utils/getId.ts
782
- function getId(state, index) {
783
- const { data, keyExtractor } = state.props;
784
- if (!data) {
785
- return "";
786
- }
787
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
788
- const id = ret;
789
- state.idCache[index] = id;
790
- return id;
791
- }
792
-
793
- // src/core/calculateOffsetForIndex.ts
794
- function calculateOffsetForIndex(ctx, state, index) {
795
- let position = 0;
796
- if (index !== void 0) {
797
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
798
- const paddingTop = peek$(ctx, "stylePaddingTop");
799
- if (paddingTop) {
800
- position += paddingTop;
801
- }
802
- const headerSize = peek$(ctx, "headerSize");
803
- if (headerSize) {
804
- position += headerSize;
805
- }
806
- }
807
- return position;
808
- }
809
-
810
- // src/utils/setPaddingTop.ts
811
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
812
- if (stylePaddingTop !== void 0) {
813
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
814
- if (stylePaddingTop < prevStylePaddingTop) {
815
- let prevTotalSize = peek$(ctx, "totalSize") || 0;
816
- set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
817
- state.timeoutSetPaddingTop = setTimeout(() => {
818
- prevTotalSize = peek$(ctx, "totalSize") || 0;
819
- set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
820
- }, 16);
821
- }
822
- set$(ctx, "stylePaddingTop", stylePaddingTop);
823
- }
824
- if (alignItemsPaddingTop !== void 0) {
825
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
826
- }
827
- }
828
-
829
- // src/utils/updateAlignItemsPaddingTop.ts
830
- function updateAlignItemsPaddingTop(ctx, state) {
831
- const {
832
- scrollLength,
833
- props: { alignItemsAtEnd, data }
834
- } = state;
835
- if (alignItemsAtEnd) {
836
- let alignItemsPaddingTop = 0;
837
- if ((data == null ? void 0 : data.length) > 0) {
838
- const contentSize = getContentSize(ctx);
839
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
840
- }
841
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
842
- }
843
- }
844
-
845
- // src/core/addTotalSize.ts
846
- function addTotalSize(ctx, state, key, add) {
847
- const { alignItemsAtEnd } = state.props;
848
- const prevTotalSize = state.totalSize;
849
- let totalSize = state.totalSize;
850
- if (key === null) {
851
- totalSize = add;
852
- if (state.timeoutSetPaddingTop) {
853
- clearTimeout(state.timeoutSetPaddingTop);
854
- state.timeoutSetPaddingTop = void 0;
855
- }
856
- } else {
857
- totalSize += add;
858
- }
859
- if (prevTotalSize !== totalSize) {
860
- if (!IsNewArchitecture && state.initialScroll && totalSize < prevTotalSize) {
861
- state.pendingTotalSize = totalSize;
862
- } else {
863
- state.pendingTotalSize = void 0;
864
- state.totalSize = totalSize;
865
- set$(ctx, "totalSize", totalSize);
866
- if (alignItemsAtEnd) {
867
- updateAlignItemsPaddingTop(ctx, state);
868
- }
869
- }
870
- }
871
- }
872
-
873
- // src/core/setSize.ts
874
- function setSize(ctx, state, itemKey, size) {
875
- const { sizes } = state;
876
- const previousSize = sizes.get(itemKey);
877
- const diff = previousSize !== void 0 ? size - previousSize : size;
878
- if (diff !== 0) {
879
- addTotalSize(ctx, state, itemKey, diff);
880
- }
881
- sizes.set(itemKey, size);
882
- }
883
-
884
- // src/utils/getItemSize.ts
885
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
886
- var _a3, _b;
887
- const {
888
- sizesKnown,
889
- sizes,
890
- averageSizes,
891
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
892
- } = state;
893
- const sizeKnown = sizesKnown.get(key);
894
- if (sizeKnown !== void 0) {
895
- return sizeKnown;
896
- }
897
- let size;
898
- const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
899
- const scrollingTo = peek$(ctx, "scrollingTo");
900
- if (preferCachedSize) {
901
- const cachedSize = sizes.get(key);
902
- if (cachedSize !== void 0) {
903
- return cachedSize;
904
- }
905
- }
906
- if (getFixedItemSize) {
907
- size = getFixedItemSize(index, data, itemType);
908
- if (size !== void 0) {
909
- sizesKnown.set(key, size);
910
- }
911
- }
912
- if (size === void 0 && useAverageSize && sizeKnown === void 0 && !scrollingTo) {
913
- const averageSizeForType = (_b = averageSizes[itemType]) == null ? void 0 : _b.avg;
914
- if (averageSizeForType !== void 0) {
915
- size = roundSize(averageSizeForType);
916
- }
917
- }
918
- if (size === void 0) {
919
- size = sizes.get(key);
920
- if (size !== void 0) {
921
- return size;
922
- }
923
- }
924
- if (size === void 0) {
925
- size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
926
- }
927
- setSize(ctx, state, key, size);
928
- return size;
929
- }
930
-
931
- // src/core/calculateOffsetWithOffsetPosition.ts
932
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
933
- const { index, viewOffset, viewPosition } = params;
934
- let offset = offsetParam;
935
- if (viewOffset) {
936
- offset -= viewOffset;
937
- }
938
- if (viewPosition !== void 0 && index !== void 0) {
939
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
940
- }
941
- return offset;
942
- }
943
-
944
- // src/core/finishScrollTo.ts
945
- function finishScrollTo(ctx, state) {
946
- var _a3, _b;
947
- if (state) {
948
- state.scrollHistory.length = 0;
949
- state.initialScroll = void 0;
950
- state.initialAnchor = void 0;
951
- set$(ctx, "scrollingTo", void 0);
952
- if (state.pendingTotalSize !== void 0) {
953
- addTotalSize(ctx, state, null, state.pendingTotalSize);
954
- }
955
- if ((_a3 = state.props) == null ? void 0 : _a3.data) {
956
- (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
957
- }
958
- }
959
- }
960
- var Platform2 = Platform;
961
-
962
- // src/core/scrollTo.ts
963
- function scrollTo(ctx, state, params) {
964
- var _a3;
965
- const { noScrollingTo, ...scrollTarget } = params;
966
- const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
967
- const {
968
- refScroller,
969
- props: { horizontal }
970
- } = state;
971
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
972
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
973
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
974
- offset = Math.min(offset, maxOffset);
975
- }
976
- state.scrollHistory.length = 0;
977
- if (!noScrollingTo) {
978
- set$(ctx, "scrollingTo", scrollTarget);
979
- }
980
- state.scrollPending = offset;
981
- if (!isInitialScroll || Platform2.OS === "android") {
982
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
983
- animated: !!animated,
984
- x: horizontal ? offset : 0,
985
- y: horizontal ? 0 : offset
986
- });
987
- }
988
- if (!animated) {
989
- state.scroll = offset;
990
- if (Platform2.OS === "web") {
991
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
992
- if (value && peek$(ctx, "scrollingTo")) {
993
- finishScrollTo(ctx, state);
994
- unlisten();
995
- }
996
- });
997
- } else {
998
- setTimeout(() => finishScrollTo(ctx, state), 100);
999
- }
1000
- if (isInitialScroll) {
1001
- setTimeout(() => {
1002
- state.initialScroll = void 0;
1003
- }, 500);
1004
- }
1005
- }
1006
- }
1007
-
1008
- // src/utils/checkThreshold.ts
1009
- var HYSTERESIS_MULTIPLIER = 1.3;
1010
- var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1011
- const absDistance = Math.abs(distance);
1012
- const within = atThreshold || threshold > 0 && absDistance <= threshold;
1013
- const updateSnapshot = () => {
1014
- setSnapshot == null ? void 0 : setSnapshot({
1015
- atThreshold,
1016
- contentSize: context.contentSize,
1017
- dataLength: context.dataLength,
1018
- scrollPosition: context.scrollPosition
1019
- });
1020
- };
1021
- if (!wasReached) {
1022
- if (!within) {
1023
- return false;
1024
- }
1025
- onReached == null ? void 0 : onReached(distance);
1026
- updateSnapshot();
1027
- return true;
1028
- }
1029
- const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1030
- if (reset) {
1031
- setSnapshot == null ? void 0 : setSnapshot(void 0);
1032
- return false;
1033
- }
1034
- if (within) {
1035
- const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
1036
- if (changed) {
1037
- onReached == null ? void 0 : onReached(distance);
1038
- updateSnapshot();
1039
- }
1040
- }
1041
- return true;
1042
- };
1043
-
1044
- // src/utils/checkAtBottom.ts
1045
- function checkAtBottom(ctx, state) {
1046
- var _a3;
1047
- if (!state) {
1048
- return;
1049
- }
1050
- const {
1051
- queuedInitialLayout,
1052
- scrollLength,
1053
- scroll,
1054
- maintainingScrollAtEnd,
1055
- props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1056
- } = state;
1057
- const contentSize = getContentSize(ctx);
1058
- if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1059
- const distanceFromEnd = contentSize - scroll - scrollLength;
1060
- const isContentLess = contentSize < scrollLength;
1061
- state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1062
- state.isEndReached = checkThreshold(
1063
- distanceFromEnd,
1064
- isContentLess,
1065
- onEndReachedThreshold * scrollLength,
1066
- state.isEndReached,
1067
- state.endReachedSnapshot,
1068
- {
1069
- contentSize,
1070
- dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1071
- scrollPosition: scroll
1072
- },
1073
- (distance) => {
1074
- var _a4, _b;
1075
- return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
1076
- },
1077
- (snapshot) => {
1078
- state.endReachedSnapshot = snapshot;
1079
- }
1080
- );
1081
- }
1082
- }
1083
-
1084
- // src/utils/checkAtTop.ts
1085
- function checkAtTop(state) {
1086
- var _a3;
1087
- if (!state) {
1088
- return;
1089
- }
1090
- const {
1091
- scrollLength,
1092
- scroll,
1093
- props: { onStartReachedThreshold }
1094
- } = state;
1095
- const distanceFromTop = scroll;
1096
- state.isAtStart = distanceFromTop <= 0;
1097
- state.isStartReached = checkThreshold(
1098
- distanceFromTop,
1099
- false,
1100
- onStartReachedThreshold * scrollLength,
1101
- state.isStartReached,
1102
- state.startReachedSnapshot,
1103
- {
1104
- contentSize: state.totalSize,
1105
- dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1106
- scrollPosition: scroll
1107
- },
1108
- (distance) => {
1109
- var _a4, _b;
1110
- return (_b = (_a4 = state.props).onStartReached) == null ? void 0 : _b.call(_a4, { distanceFromStart: distance });
1111
- },
1112
- (snapshot) => {
1113
- state.startReachedSnapshot = snapshot;
1114
- }
1115
- );
1116
- }
1117
-
1118
- // src/core/updateScroll.ts
1119
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1120
- var _a3;
1121
- const scrollingTo = peek$(ctx, "scrollingTo");
1122
- state.hasScrolled = true;
1123
- state.lastBatchingAction = Date.now();
1124
- const currentTime = Date.now();
1125
- const adjust = state.scrollAdjustHandler.getAdjust();
1126
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1127
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1128
- if (adjustChanged) {
1129
- state.scrollHistory.length = 0;
1130
- }
1131
- state.lastScrollAdjustForHistory = adjust;
1132
- if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1133
- if (!adjustChanged) {
1134
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1135
- }
1136
- }
1137
- if (state.scrollHistory.length > 5) {
1138
- state.scrollHistory.shift();
1139
- }
1140
- state.scrollPrev = state.scroll;
1141
- state.scrollPrevTime = state.scrollTime;
1142
- state.scroll = newScroll;
1143
- state.scrollTime = currentTime;
1144
- const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
1145
- if (ignoreScrollFromMVCP && !scrollingTo) {
1146
- const { lt, gt } = ignoreScrollFromMVCP;
1147
- if (lt && newScroll < lt || gt && newScroll > gt) {
1148
- state.ignoreScrollFromMVCPIgnored = true;
1149
- return;
1150
- }
1151
- }
1152
- if (forceUpdate || state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1153
- state.ignoreScrollFromMVCPIgnored = false;
1154
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1155
- checkAtBottom(ctx, state);
1156
- checkAtTop(state);
1157
- state.dataChangeNeedsScrollUpdate = false;
1158
- }
1159
- }
1160
-
1161
- // src/utils/requestAdjust.ts
1162
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1163
- if (Math.abs(positionDiff) > 0.1) {
1164
- const needsScrollWorkaround = Platform2.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
1165
- const doit = () => {
1166
- if (needsScrollWorkaround) {
1167
- scrollTo(ctx, state, {
1168
- noScrollingTo: true,
1169
- offset: state.scroll
1170
- });
1171
- } else {
1172
- state.scrollAdjustHandler.requestAdjust(positionDiff);
1173
- if (state.adjustingFromInitialMount) {
1174
- state.adjustingFromInitialMount--;
1175
- }
1176
- }
1177
- };
1178
- state.scroll += positionDiff;
1179
- state.scrollForNextCalculateItemsInView = void 0;
1180
- const didLayout = peek$(ctx, "containersDidLayout");
1181
- if (didLayout) {
1182
- doit();
1183
- if (Platform2.OS !== "web") {
1184
- const threshold = state.scroll - positionDiff / 2;
1185
- if (!state.ignoreScrollFromMVCP) {
1186
- state.ignoreScrollFromMVCP = {};
1187
- }
1188
- if (positionDiff > 0) {
1189
- state.ignoreScrollFromMVCP.lt = threshold;
1190
- } else {
1191
- state.ignoreScrollFromMVCP.gt = threshold;
1192
- }
1193
- if (state.ignoreScrollFromMVCPTimeout) {
1194
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1195
- }
1196
- const delay = needsScrollWorkaround ? 250 : 100;
1197
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
1198
- state.ignoreScrollFromMVCP = void 0;
1199
- const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
1200
- if (shouldForceUpdate) {
1201
- state.ignoreScrollFromMVCPIgnored = false;
1202
- state.scrollPending = state.scroll;
1203
- updateScroll(ctx, state, state.scroll, true);
1204
- }
1205
- }, delay);
1206
- }
1207
- } else {
1208
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
1209
- requestAnimationFrame(doit);
1210
- }
1211
- }
1212
- }
1213
-
1214
- // src/core/ensureInitialAnchor.ts
1215
- var INITIAL_ANCHOR_TOLERANCE = 0.5;
1216
- var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1217
- var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1218
- function ensureInitialAnchor(ctx, state) {
1219
- var _a3, _b, _c, _d, _e;
1220
- const anchor = state.initialAnchor;
1221
- const item = state.props.data[anchor.index];
1222
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1223
- if (!containersDidLayout) {
1224
- return;
1225
- }
1226
- const id = getId(state, anchor.index);
1227
- if (state.positions.get(id) === void 0) {
1228
- return;
1229
- }
1230
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1231
- if (size === void 0) {
1232
- return;
1233
- }
1234
- const availableSpace = Math.max(0, state.scrollLength - size);
1235
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1236
- const contentSize = getContentSize(ctx);
1237
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1238
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1239
- const delta = clampedDesiredOffset - state.scroll;
1240
- if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1241
- const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1242
- if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1243
- state.initialAnchor = void 0;
1244
- } else {
1245
- anchor.settledTicks = settledTicks;
1246
- }
1247
- return;
1248
- }
1249
- if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1250
- state.initialAnchor = void 0;
1251
- return;
1252
- }
1253
- const lastDelta = anchor.lastDelta;
1254
- if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1255
- state.initialAnchor = void 0;
1256
- return;
1257
- }
1258
- Object.assign(anchor, {
1259
- attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1260
- lastDelta: delta,
1261
- settledTicks: 0
1262
- });
1263
- requestAdjust(ctx, state, delta);
1264
- }
1265
-
1266
- // src/core/mvcp.ts
1267
- function prepareMVCP(ctx, state, dataChanged) {
1268
- const { idsInView, positions, props } = state;
1269
- const { maintainVisibleContentPosition } = props;
1270
- const scrollingTo = peek$(ctx, "scrollingTo");
1271
- let prevPosition;
1272
- let targetId;
1273
- const idsInViewWithPositions = [];
1274
- const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1275
- const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1276
- const indexByKey = state.indexByKey;
1277
- if (shouldMVCP) {
1278
- if (scrollTarget !== void 0) {
1279
- if (!IsNewArchitecture && (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll)) {
1280
- return void 0;
1281
- }
1282
- targetId = getId(state, scrollTarget);
1283
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1284
- if (dataChanged) {
1285
- for (let i = 0; i < idsInView.length; i++) {
1286
- const id = idsInView[i];
1287
- const index = indexByKey.get(id);
1288
- if (index !== void 0) {
1289
- idsInViewWithPositions.push({ id, position: positions.get(id) });
1290
- }
1291
- }
1292
- } else {
1293
- targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
1294
- }
1295
- }
1296
- if (targetId !== void 0) {
1297
- prevPosition = positions.get(targetId);
1298
- }
1299
- return () => {
1300
- let positionDiff;
1301
- if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1302
- for (let i = 0; i < idsInViewWithPositions.length; i++) {
1303
- const { id, position } = idsInViewWithPositions[i];
1304
- const newPosition = positions.get(id);
1305
- if (newPosition !== void 0) {
1306
- positionDiff = newPosition - position;
1307
- break;
1308
- }
1309
- }
1310
- }
1311
- if (targetId !== void 0 && prevPosition !== void 0) {
1312
- const newPosition = positions.get(targetId);
1313
- if (newPosition !== void 0) {
1314
- const totalSize = getContentSize(ctx);
1315
- let diff = newPosition - prevPosition;
1316
- if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1317
- if (diff > 0) {
1318
- diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
1319
- } else {
1320
- diff = 0;
1321
- }
1322
- }
1323
- positionDiff = diff;
1324
- }
1325
- }
1326
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1327
- requestAdjust(ctx, state, positionDiff, dataChanged && maintainVisibleContentPosition);
1328
- }
1329
- };
1330
- }
1331
- }
1332
-
1333
- // src/core/prepareColumnStartState.ts
1334
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1335
- var _a3;
1336
- const numColumns = peek$(ctx, "numColumns");
1337
- let rowStartIndex = startIndex;
1338
- const columnAtStart = state.columns.get(state.idCache[startIndex]);
1339
- if (columnAtStart !== 1) {
1340
- rowStartIndex = findRowStartIndex(state, numColumns, startIndex);
1341
- }
1342
- let currentRowTop = 0;
1343
- const curId = state.idCache[rowStartIndex];
1344
- const column = state.columns.get(curId);
1345
- if (rowStartIndex > 0) {
1346
- const prevIndex = rowStartIndex - 1;
1347
- const prevId = state.idCache[prevIndex];
1348
- const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1349
- const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1350
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1351
- currentRowTop = prevPosition + prevRowHeight;
1352
- }
1353
- return {
1354
- column,
1355
- currentRowTop,
1356
- startIndex: rowStartIndex
1357
- };
1358
- }
1359
- function findRowStartIndex(state, numColumns, index) {
1360
- if (numColumns <= 1) {
1361
- return Math.max(0, index);
1362
- }
1363
- let rowStart = Math.max(0, index);
1364
- while (rowStart > 0) {
1365
- const columnForIndex = state.columns.get(state.idCache[rowStart]);
1366
- if (columnForIndex === 1) {
1367
- break;
1368
- }
1369
- rowStart--;
1370
- }
1371
- return rowStart;
1372
- }
1373
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1374
- if (endIndex < startIndex) {
1375
- return 0;
1376
- }
1377
- const { data } = state.props;
1378
- if (!data) {
1379
- return 0;
1380
- }
1381
- let maxSize = 0;
1382
- for (let i = startIndex; i <= endIndex; i++) {
1383
- if (i < 0 || i >= data.length) {
1384
- continue;
1385
- }
1386
- const id = state.idCache[i];
1387
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1388
- if (size > maxSize) {
1389
- maxSize = size;
1390
- }
1391
- }
1392
- return maxSize;
1393
- }
1394
-
1395
- // src/core/updateTotalSize.ts
1396
- function updateTotalSize(ctx, state) {
1397
- const {
1398
- positions,
1399
- props: { data }
1400
- } = state;
1401
- if (data.length === 0) {
1402
- addTotalSize(ctx, state, null, 0);
1403
- } else {
1404
- const lastId = getId(state, data.length - 1);
1405
- if (lastId !== void 0) {
1406
- const lastPosition = positions.get(lastId);
1407
- if (lastPosition !== void 0) {
1408
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1409
- if (lastSize !== void 0) {
1410
- const totalSize = lastPosition + lastSize;
1411
- addTotalSize(ctx, state, null, totalSize);
1412
- }
1413
- }
1414
- }
1415
- }
1416
- }
1417
-
1418
- // src/utils/getScrollVelocity.ts
1419
- var getScrollVelocity = (state) => {
1420
- const { scrollHistory } = state;
1421
- let velocity = 0;
1422
- if (scrollHistory.length >= 1) {
1423
- const newest = scrollHistory[scrollHistory.length - 1];
1424
- let oldest;
1425
- let start = 0;
1426
- const now = Date.now();
1427
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1428
- const entry = scrollHistory[i];
1429
- const nextEntry = scrollHistory[i + 1];
1430
- if (i > 0) {
1431
- const prevEntry = scrollHistory[i - 1];
1432
- const prevDirection = entry.scroll - prevEntry.scroll;
1433
- const currentDirection = nextEntry.scroll - entry.scroll;
1434
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1435
- start = i;
1436
- break;
1437
- }
1438
- }
1439
- }
1440
- for (let i = start; i < scrollHistory.length - 1; i++) {
1441
- const entry = scrollHistory[i];
1442
- if (now - entry.time <= 1e3) {
1443
- oldest = entry;
1444
- break;
1445
- }
1446
- }
1447
- if (oldest && oldest !== newest) {
1448
- const scrollDiff = newest.scroll - oldest.scroll;
1449
- const timeDiff = newest.time - oldest.time;
1450
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1451
- }
1452
- }
1453
- return velocity;
1454
- };
1455
-
1456
- // src/utils/updateSnapToOffsets.ts
1457
- function updateSnapToOffsets(ctx, state) {
1458
- const {
1459
- positions,
1460
- props: { snapToIndices }
1461
- } = state;
1462
- const snapToOffsets = Array(snapToIndices.length);
1463
- for (let i = 0; i < snapToIndices.length; i++) {
1464
- const idx = snapToIndices[i];
1465
- const key = getId(state, idx);
1466
- snapToOffsets[i] = positions.get(key);
1467
- }
1468
- set$(ctx, "snapToOffsets", snapToOffsets);
1469
- }
1470
-
1471
- // src/core/updateItemPositions.ts
1472
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1473
- doMVCP: false,
1474
- forceFullUpdate: false,
1475
- scrollBottomBuffered: -1,
1476
- startIndex: 0
1477
- }) {
1478
- var _a3, _b, _c, _d, _e;
1479
- const {
1480
- columns,
1481
- indexByKey,
1482
- positions,
1483
- idCache,
1484
- sizesKnown,
1485
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1486
- } = state;
1487
- const data = state.props.data;
1488
- const dataLength = data.length;
1489
- const numColumns = peek$(ctx, "numColumns");
1490
- const scrollingTo = peek$(ctx, "scrollingTo");
1491
- const hasColumns = numColumns > 1;
1492
- const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1493
- const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1494
- const maxVisibleArea = scrollBottomBuffered + 1e3;
1495
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1496
- const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1497
- let currentRowTop = 0;
1498
- let column = 1;
1499
- let maxSizeInRow = 0;
1500
- if (startIndex > 0) {
1501
- if (hasColumns) {
1502
- const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1503
- ctx,
1504
- state,
1505
- startIndex,
1506
- useAverageSize
1507
- );
1508
- startIndex = processedStartIndex;
1509
- currentRowTop = initialRowTop;
1510
- } else if (startIndex < dataLength) {
1511
- const prevIndex = startIndex - 1;
1512
- const prevId = getId(state, prevIndex);
1513
- const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1514
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1515
- currentRowTop = prevPosition + prevSize;
1516
- }
1517
- }
1518
- const needsIndexByKey = dataChanged || indexByKey.size === 0;
1519
- let didBreakEarly = false;
1520
- let breakAt;
1521
- for (let i = startIndex; i < dataLength; i++) {
1522
- if (shouldOptimize && breakAt !== void 0 && i > breakAt) {
1523
- didBreakEarly = true;
1524
- break;
1525
- }
1526
- if (shouldOptimize && breakAt === void 0 && !scrollingTo && !dataChanged && currentRowTop > maxVisibleArea) {
1527
- const itemsPerRow = hasColumns ? numColumns : 1;
1528
- breakAt = i + itemsPerRow + 10;
1529
- }
1530
- const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1531
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1532
- if (IS_DEV && needsIndexByKey) {
1533
- if (indexByKeyForChecking.has(id)) {
1534
- console.error(
1535
- `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1536
- );
1537
- }
1538
- indexByKeyForChecking.set(id, i);
1539
- }
1540
- positions.set(id, currentRowTop);
1541
- if (needsIndexByKey) {
1542
- indexByKey.set(id, i);
1543
- }
1544
- columns.set(id, column);
1545
- if (hasColumns) {
1546
- if (size > maxSizeInRow) {
1547
- maxSizeInRow = size;
1548
- }
1549
- column++;
1550
- if (column > numColumns) {
1551
- currentRowTop += maxSizeInRow;
1552
- column = 1;
1553
- maxSizeInRow = 0;
1554
- }
1555
- } else {
1556
- currentRowTop += size;
1557
- }
1558
- }
1559
- if (!didBreakEarly) {
1560
- updateTotalSize(ctx, state);
1561
- }
1562
- if (snapToIndices) {
1563
- updateSnapToOffsets(ctx, state);
1564
- }
1565
- }
1566
-
1567
- // src/core/viewability.ts
1568
- function ensureViewabilityState(ctx, configId) {
1569
- let map = ctx.mapViewabilityConfigStates;
1570
- if (!map) {
1571
- map = /* @__PURE__ */ new Map();
1572
- ctx.mapViewabilityConfigStates = map;
1573
- }
1574
- let state = map.get(configId);
1575
- if (!state) {
1576
- state = { end: -1, previousEnd: -1, previousStart: -1, start: -1, viewableItems: [] };
1577
- map.set(configId, state);
1578
- }
1579
- return state;
1580
- }
1581
- function setupViewability(props) {
1582
- let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
1583
- if (viewabilityConfig || onViewableItemsChanged) {
1584
- viewabilityConfigCallbackPairs = [
1585
- ...viewabilityConfigCallbackPairs || [],
1586
- {
1587
- onViewableItemsChanged,
1588
- viewabilityConfig: viewabilityConfig || {
1589
- viewAreaCoveragePercentThreshold: 0
1590
- }
1591
- }
1592
- ];
1593
- }
1594
- return viewabilityConfigCallbackPairs;
1595
- }
1596
- function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
1597
- const {
1598
- timeouts,
1599
- props: { data }
1600
- } = state;
1601
- for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
1602
- const viewabilityState = ensureViewabilityState(ctx, viewabilityConfigCallbackPair.viewabilityConfig.id);
1603
- viewabilityState.start = start;
1604
- viewabilityState.end = end;
1605
- if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
1606
- const timer = setTimeout(() => {
1607
- timeouts.delete(timer);
1608
- updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
1609
- }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
1610
- timeouts.add(timer);
1611
- } else {
1612
- updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
1613
- }
1614
- }
1615
- }
1616
- function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize) {
1617
- const { viewabilityConfig, onViewableItemsChanged } = viewabilityConfigCallbackPair;
1618
- const configId = viewabilityConfig.id;
1619
- const viewabilityState = ensureViewabilityState(ctx, configId);
1620
- const { viewableItems: previousViewableItems, start, end } = viewabilityState;
1621
- const viewabilityTokens = /* @__PURE__ */ new Map();
1622
- for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
1623
- viewabilityTokens.set(
1624
- containerId,
1625
- computeViewability(
1626
- state,
1627
- ctx,
1628
- viewabilityConfig,
1629
- containerId,
1630
- value.key,
1631
- scrollSize,
1632
- value.item,
1633
- value.index
1634
- )
1635
- );
1636
- }
1637
- const changed = [];
1638
- if (previousViewableItems) {
1639
- for (const viewToken of previousViewableItems) {
1640
- const containerId = findContainerId(ctx, viewToken.key);
1641
- if (!isViewable(
1642
- state,
1643
- ctx,
1644
- viewabilityConfig,
1645
- containerId,
1646
- viewToken.key,
1647
- scrollSize,
1648
- viewToken.item,
1649
- viewToken.index
1650
- )) {
1651
- viewToken.isViewable = false;
1652
- changed.push(viewToken);
1653
- }
1654
- }
1655
- }
1656
- const viewableItems = [];
1657
- for (let i = start; i <= end; i++) {
1658
- const item = data[i];
1659
- if (item) {
1660
- const key = getId(state, i);
1661
- const containerId = findContainerId(ctx, key);
1662
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1663
- const viewToken = {
1664
- containerId,
1665
- index: i,
1666
- isViewable: true,
1667
- item,
1668
- key
1669
- };
1670
- viewableItems.push(viewToken);
1671
- if (!(previousViewableItems == null ? void 0 : previousViewableItems.find((v) => v.key === viewToken.key))) {
1672
- changed.push(viewToken);
1673
- }
1674
- }
1675
- }
1676
- }
1677
- Object.assign(viewabilityState, {
1678
- previousEnd: end,
1679
- previousStart: start,
1680
- viewableItems
1681
- });
1682
- if (changed.length > 0) {
1683
- viewabilityState.viewableItems = viewableItems;
1684
- for (let i = 0; i < changed.length; i++) {
1685
- const change = changed[i];
1686
- maybeUpdateViewabilityCallback(ctx, configId, change.containerId, change);
1687
- }
1688
- if (onViewableItemsChanged) {
1689
- onViewableItemsChanged({ changed, viewableItems });
1690
- }
1691
- }
1692
- for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
1693
- if (value.sizeVisible < 0) {
1694
- ctx.mapViewabilityAmountValues.delete(containerId);
1695
- }
1696
- }
1697
- }
1698
- function shallowEqual(prev, next) {
1699
- if (!prev) return false;
1700
- const keys = Object.keys(next);
1701
- for (let i = 0; i < keys.length; i++) {
1702
- const k = keys[i];
1703
- if (prev[k] !== next[k]) return false;
1704
- }
1705
- return true;
1706
- }
1707
- function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
1708
- const { sizes, positions, scroll: scrollState } = state;
1709
- const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
1710
- const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
1711
- const viewAreaMode = viewAreaCoveragePercentThreshold != null;
1712
- const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
1713
- const scroll = scrollState - topPad;
1714
- const top = positions.get(key) - scroll;
1715
- const size = sizes.get(key) || 0;
1716
- const bottom = top + size;
1717
- const isEntirelyVisible = top >= 0 && bottom <= scrollSize && bottom > top;
1718
- const sizeVisible = isEntirelyVisible ? size : Math.min(bottom, scrollSize) - Math.max(top, 0);
1719
- const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
1720
- const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
1721
- const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
1722
- const isViewable2 = percent >= viewablePercentThreshold;
1723
- const value = {
1724
- containerId,
1725
- index,
1726
- isViewable: isViewable2,
1727
- item,
1728
- key,
1729
- percentOfScroller,
1730
- percentVisible,
1731
- scrollSize,
1732
- size,
1733
- sizeVisible
1734
- };
1735
- const prev = ctx.mapViewabilityAmountValues.get(containerId);
1736
- if (!shallowEqual(prev, value)) {
1737
- ctx.mapViewabilityAmountValues.set(containerId, value);
1738
- const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
1739
- if (cb) {
1740
- cb(value);
1741
- }
1742
- }
1743
- return value;
1744
- }
1745
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
1746
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
1747
- return value.isViewable;
1748
- }
1749
- function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1750
- const key = containerId + configId;
1751
- ctx.mapViewabilityValues.set(key, viewToken);
1752
- const cb = ctx.mapViewabilityCallbacks.get(key);
1753
- cb == null ? void 0 : cb(viewToken);
1754
- }
1755
-
1756
- // src/utils/checkAllSizesKnown.ts
1757
- function isNullOrUndefined2(value) {
1758
- return value === null || value === void 0;
1759
- }
1760
- function checkAllSizesKnown(state) {
1761
- const { startBuffered, endBuffered, sizesKnown } = state;
1762
- if (!isNullOrUndefined2(endBuffered) && !isNullOrUndefined2(startBuffered) && startBuffered >= 0 && endBuffered >= 0) {
1763
- let areAllKnown = true;
1764
- for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1765
- const key = getId(state, i);
1766
- areAllKnown && (areAllKnown = sizesKnown.has(key));
1767
- }
1768
- return areAllKnown;
1769
- }
1770
- return false;
1771
- }
1772
-
1773
- // src/utils/findAvailableContainers.ts
1774
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
1775
- const numContainers = peek$(ctx, "numContainers");
1776
- const { stickyContainerPool, containerItemTypes } = state;
1777
- const result = [];
1778
- const availableContainers = [];
1779
- const pendingRemovalSet = new Set(pendingRemoval);
1780
- let pendingRemovalChanged = false;
1781
- const stickyIndicesSet = state.props.stickyIndicesSet;
1782
- const stickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => stickyIndicesSet.has(index))) || [];
1783
- const canReuseContainer = (containerIndex, requiredType) => {
1784
- if (!requiredType) return true;
1785
- const existingType = containerItemTypes.get(containerIndex);
1786
- if (!existingType) return true;
1787
- return existingType === requiredType;
1788
- };
1789
- const neededTypes = requiredItemTypes ? [...requiredItemTypes] : [];
1790
- let typeIndex = 0;
1791
- for (let i = 0; i < stickyItemIndices.length; i++) {
1792
- const requiredType = neededTypes[typeIndex];
1793
- let foundContainer = false;
1794
- for (const containerIndex of stickyContainerPool) {
1795
- const key = peek$(ctx, `containerItemKey${containerIndex}`);
1796
- const isPendingRemoval = pendingRemovalSet.has(containerIndex);
1797
- if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType) && !result.includes(containerIndex)) {
1798
- result.push(containerIndex);
1799
- if (isPendingRemoval && pendingRemovalSet.delete(containerIndex)) {
1800
- pendingRemovalChanged = true;
1801
- }
1802
- foundContainer = true;
1803
- if (requiredItemTypes) typeIndex++;
1804
- break;
1805
- }
1806
- }
1807
- if (!foundContainer) {
1808
- const newContainerIndex = numContainers + result.filter((index) => index >= numContainers).length;
1809
- result.push(newContainerIndex);
1810
- stickyContainerPool.add(newContainerIndex);
1811
- if (requiredItemTypes) typeIndex++;
1812
- }
1813
- }
1814
- for (let u = 0; u < numContainers && result.length < numNeeded; u++) {
1815
- if (stickyContainerPool.has(u)) {
1816
- continue;
1817
- }
1818
- const key = peek$(ctx, `containerItemKey${u}`);
1819
- const requiredType = neededTypes[typeIndex];
1820
- const isPending = key !== void 0 && pendingRemovalSet.has(u);
1821
- const canUse = key === void 0 || isPending && canReuseContainer(u, requiredType);
1822
- if (canUse) {
1823
- if (isPending) {
1824
- pendingRemovalSet.delete(u);
1825
- pendingRemovalChanged = true;
1826
- }
1827
- result.push(u);
1828
- if (requiredItemTypes) {
1829
- typeIndex++;
1830
- }
1831
- }
1832
- }
1833
- for (let u = 0; u < numContainers && result.length < numNeeded; u++) {
1834
- if (stickyContainerPool.has(u)) {
1835
- continue;
1836
- }
1837
- const key = peek$(ctx, `containerItemKey${u}`);
1838
- if (key === void 0) continue;
1839
- const index = state.indexByKey.get(key);
1840
- const isOutOfView = index < startBuffered || index > endBuffered;
1841
- if (isOutOfView) {
1842
- const distance = index < startBuffered ? startBuffered - index : index - endBuffered;
1843
- if (!requiredItemTypes || typeIndex < neededTypes.length && canReuseContainer(u, neededTypes[typeIndex])) {
1844
- availableContainers.push({ distance, index: u });
1845
- }
1846
- }
1847
- }
1848
- const remaining = numNeeded - result.length;
1849
- if (remaining > 0) {
1850
- if (availableContainers.length > 0) {
1851
- if (availableContainers.length > remaining) {
1852
- availableContainers.sort(comparatorByDistance);
1853
- availableContainers.length = remaining;
1854
- }
1855
- for (const container of availableContainers) {
1856
- result.push(container.index);
1857
- if (requiredItemTypes) {
1858
- typeIndex++;
1859
- }
1860
- }
1861
- }
1862
- const stillNeeded = numNeeded - result.length;
1863
- if (stillNeeded > 0) {
1864
- for (let i = 0; i < stillNeeded; i++) {
1865
- result.push(numContainers + i);
1866
- }
1867
- if (IS_DEV && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1868
- console.warn(
1869
- "[legend-list] No unused container available, so creating one on demand. This can be a minor performance issue and is likely caused by the estimatedItemSize being too large. Consider decreasing estimatedItemSize or increasing initialContainerPoolRatio.",
1870
- {
1871
- debugInfo: {
1872
- numContainers,
1873
- numContainersPooled: peek$(ctx, "numContainersPooled"),
1874
- numNeeded,
1875
- stillNeeded
1876
- }
1877
- }
1878
- );
1879
- }
1880
- }
1881
- }
1882
- if (pendingRemovalChanged) {
1883
- pendingRemoval.length = 0;
1884
- for (const value of pendingRemovalSet) {
1885
- pendingRemoval.push(value);
1886
- }
1887
- }
1888
- return result.sort(comparatorDefault);
1889
- }
1890
- function comparatorByDistance(a, b) {
1891
- return b.distance - a.distance;
1892
- }
1893
-
1894
- // src/core/scrollToIndex.ts
1895
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1896
- if (index >= state.props.data.length) {
1897
- index = state.props.data.length - 1;
1898
- } else if (index < 0) {
1899
- index = 0;
1900
- }
1901
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
1902
- const isLast = index === state.props.data.length - 1;
1903
- if (isLast && viewPosition === void 0) {
1904
- viewPosition = 1;
1905
- }
1906
- state.scrollForNextCalculateItemsInView = void 0;
1907
- scrollTo(ctx, state, {
1908
- animated,
1909
- index,
1910
- offset: firstIndexOffset,
1911
- viewOffset,
1912
- viewPosition: viewPosition != null ? viewPosition : 0
1913
- });
1914
- }
1915
-
1916
- // src/utils/setDidLayout.ts
1917
- function setDidLayout(ctx, state) {
1918
- const {
1919
- loadStartTime,
1920
- initialScroll,
1921
- props: { onLoad }
1922
- } = state;
1923
- state.queuedInitialLayout = true;
1924
- checkAtBottom(ctx, state);
1925
- const setIt = () => {
1926
- set$(ctx, "containersDidLayout", true);
1927
- if (onLoad) {
1928
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1929
- }
1930
- };
1931
- if (Platform2.OS === "android" && initialScroll) {
1932
- if (IsNewArchitecture) {
1933
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1934
- requestAnimationFrame(() => {
1935
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1936
- setIt();
1937
- });
1938
- } else {
1939
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1940
- setIt();
1941
- }
1942
- } else {
1943
- setIt();
1944
- }
1945
- }
1946
-
1947
- // src/core/calculateItemsInView.ts
1948
- function findCurrentStickyIndex(stickyArray, scroll, state) {
1949
- var _a3;
1950
- const idCache = state.idCache;
1951
- const positions = state.positions;
1952
- for (let i = stickyArray.length - 1; i >= 0; i--) {
1953
- const stickyIndex = stickyArray[i];
1954
- const stickyId = (_a3 = idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
1955
- const stickyPos = stickyId ? positions.get(stickyId) : void 0;
1956
- if (stickyPos !== void 0 && scroll >= stickyPos) {
1957
- return i;
1958
- }
1959
- }
1960
- return -1;
1961
- }
1962
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
1963
- return new Set(
1964
- Array.from(state.stickyContainerPool).map((i) => peek$(ctx, `containerItemKey${i}`)).map((key) => key ? state.indexByKey.get(key) : void 0).filter((idx) => idx !== void 0 && stickyHeaderIndices.has(idx))
1965
- );
1966
- }
1967
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
1968
- var _a3;
1969
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
1970
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
1971
- for (let offset = 0; offset <= 1; offset++) {
1972
- const idx = currentStickyIdx - offset;
1973
- if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
1974
- const stickyIndex = stickyArray[idx];
1975
- const stickyId = (_a3 = state.idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
1976
- if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
1977
- needNewContainers.push(stickyIndex);
1978
- }
1979
- }
1980
- }
1981
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
1982
- var _a3, _b, _c;
1983
- for (const containerIndex of state.stickyContainerPool) {
1984
- const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
1985
- const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
1986
- if (itemIndex === void 0) continue;
1987
- const arrayIdx = stickyArray.indexOf(itemIndex);
1988
- if (arrayIdx === -1) {
1989
- state.stickyContainerPool.delete(containerIndex);
1990
- set$(ctx, `containerSticky${containerIndex}`, false);
1991
- set$(ctx, `containerStickyOffset${containerIndex}`, void 0);
1992
- continue;
1993
- }
1994
- const isRecentSticky = arrayIdx >= currentStickyIdx - 1 && arrayIdx <= currentStickyIdx + 1;
1995
- if (isRecentSticky) continue;
1996
- const nextIndex = stickyArray[arrayIdx + 1];
1997
- let shouldRecycle = false;
1998
- if (nextIndex) {
1999
- const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
2000
- const nextPos = nextId ? state.positions.get(nextId) : void 0;
2001
- shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
2002
- } else {
2003
- const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2004
- if (currentId) {
2005
- const currentPos = state.positions.get(currentId);
2006
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2007
- shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2008
- }
2009
- }
2010
- if (shouldRecycle) {
2011
- pendingRemoval.push(containerIndex);
2012
- }
2013
- }
2014
- }
2015
- function calculateItemsInView(ctx, state, params = {}) {
2016
- unstable_batchedUpdates(() => {
2017
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2018
- const {
2019
- columns,
2020
- containerItemKeys,
2021
- enableScrollForNextCalculateItemsInView,
2022
- idCache,
2023
- indexByKey,
2024
- initialScroll,
2025
- minIndexSizeChanged,
2026
- positions,
2027
- props: { getItemType, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer },
2028
- scrollForNextCalculateItemsInView,
2029
- scrollLength,
2030
- sizes,
2031
- startBufferedId: startBufferedIdOrig,
2032
- viewabilityConfigCallbackPairs
2033
- } = state;
2034
- const { data } = state.props;
2035
- const stickyIndicesArr = state.props.stickyIndicesArr || [];
2036
- const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2037
- const prevNumContainers = peek$(ctx, "numContainers");
2038
- if (!data || scrollLength === 0 || !prevNumContainers) {
2039
- if (state.initialAnchor) {
2040
- ensureInitialAnchor(ctx, state);
2041
- }
2042
- return;
2043
- }
2044
- const totalSize = getContentSize(ctx);
2045
- const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
2046
- const numColumns = peek$(ctx, "numColumns");
2047
- const { dataChanged, doMVCP, forceFullItemPositions } = params;
2048
- const speed = getScrollVelocity(state);
2049
- const scrollExtra = 0;
2050
- const { queuedInitialLayout } = state;
2051
- let { scroll: scrollState } = state;
2052
- if (!queuedInitialLayout && initialScroll) {
2053
- const updatedOffset = calculateOffsetWithOffsetPosition(
2054
- ctx,
2055
- state,
2056
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2057
- initialScroll
2058
- );
2059
- scrollState = updatedOffset;
2060
- }
2061
- const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2062
- const scrollAdjustPad = scrollAdjustPending - topPad;
2063
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2064
- if (scroll + scrollLength > totalSize) {
2065
- scroll = Math.max(0, totalSize - scrollLength);
2066
- }
2067
- if (ENABLE_DEBUG_VIEW) {
2068
- set$(ctx, "debugRawScroll", scrollState);
2069
- set$(ctx, "debugComputedScroll", scroll);
2070
- }
2071
- const previousStickyIndex = state.activeStickyIndex;
2072
- const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2073
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2074
- state.activeStickyIndex = nextActiveStickyIndex;
2075
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2076
- let scrollBufferTop = scrollBuffer;
2077
- let scrollBufferBottom = scrollBuffer;
2078
- if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
2079
- scrollBufferTop = scrollBuffer * 0.5;
2080
- scrollBufferBottom = scrollBuffer * 1.5;
2081
- } else {
2082
- scrollBufferTop = scrollBuffer * 1.5;
2083
- scrollBufferBottom = scrollBuffer * 0.5;
2084
- }
2085
- const scrollTopBuffered = scroll - scrollBufferTop;
2086
- const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2087
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2088
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2089
- const { top, bottom } = scrollForNextCalculateItemsInView;
2090
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2091
- if (state.initialAnchor) {
2092
- ensureInitialAnchor(ctx, state);
2093
- }
2094
- return;
2095
- }
2096
- }
2097
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2098
- if (dataChanged) {
2099
- indexByKey.clear();
2100
- idCache.length = 0;
2101
- positions.clear();
2102
- }
2103
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2104
- updateItemPositions(ctx, state, dataChanged, {
2105
- doMVCP,
2106
- forceFullUpdate: !!forceFullItemPositions,
2107
- scrollBottomBuffered,
2108
- startIndex
2109
- });
2110
- if (minIndexSizeChanged !== void 0) {
2111
- state.minIndexSizeChanged = void 0;
2112
- }
2113
- checkMVCP == null ? void 0 : checkMVCP();
2114
- let startNoBuffer = null;
2115
- let startBuffered = null;
2116
- let startBufferedId = null;
2117
- let endNoBuffer = null;
2118
- let endBuffered = null;
2119
- let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2120
- for (let i = loopStart; i >= 0; i--) {
2121
- const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2122
- const top = positions.get(id);
2123
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2124
- const bottom = top + size;
2125
- if (bottom > scroll - scrollBuffer) {
2126
- loopStart = i;
2127
- } else {
2128
- break;
2129
- }
2130
- }
2131
- const loopStartMod = loopStart % numColumns;
2132
- if (loopStartMod > 0) {
2133
- loopStart -= loopStartMod;
2134
- }
2135
- let foundEnd = false;
2136
- let nextTop;
2137
- let nextBottom;
2138
- let maxIndexRendered = 0;
2139
- for (let i = 0; i < prevNumContainers; i++) {
2140
- const key = peek$(ctx, `containerItemKey${i}`);
2141
- if (key !== void 0) {
2142
- const index = indexByKey.get(key);
2143
- maxIndexRendered = Math.max(maxIndexRendered, index);
2144
- }
2145
- }
2146
- let firstFullyOnScreenIndex;
2147
- const dataLength = data.length;
2148
- for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2149
- const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2150
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2151
- const top = positions.get(id);
2152
- if (!foundEnd) {
2153
- if (startNoBuffer === null && top + size > scroll) {
2154
- startNoBuffer = i;
2155
- }
2156
- if (firstFullyOnScreenIndex === void 0 && top >= scroll - 10) {
2157
- firstFullyOnScreenIndex = i;
2158
- }
2159
- if (startBuffered === null && top + size > scrollTopBuffered) {
2160
- startBuffered = i;
2161
- startBufferedId = id;
2162
- nextTop = top;
2163
- }
2164
- if (startNoBuffer !== null) {
2165
- if (top <= scrollBottom) {
2166
- endNoBuffer = i;
2167
- }
2168
- if (top <= scrollBottomBuffered) {
2169
- endBuffered = i;
2170
- nextBottom = top + size;
2171
- } else {
2172
- foundEnd = true;
2173
- }
2174
- }
2175
- }
2176
- }
2177
- const idsInView = [];
2178
- for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
2179
- const id = (_g = idCache[i]) != null ? _g : getId(state, i);
2180
- idsInView.push(id);
2181
- }
2182
- Object.assign(state, {
2183
- endBuffered,
2184
- endNoBuffer,
2185
- firstFullyOnScreenIndex,
2186
- idsInView,
2187
- startBuffered,
2188
- startBufferedId,
2189
- startNoBuffer
2190
- });
2191
- if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
2192
- state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
2193
- bottom: nextBottom,
2194
- top: nextTop
2195
- } : void 0;
2196
- }
2197
- const numContainers = peek$(ctx, "numContainers");
2198
- const pendingRemoval = [];
2199
- if (dataChanged) {
2200
- for (let i = 0; i < numContainers; i++) {
2201
- const itemKey = peek$(ctx, `containerItemKey${i}`);
2202
- if (!keyExtractor || itemKey && indexByKey.get(itemKey) === void 0) {
2203
- pendingRemoval.push(i);
2204
- }
2205
- }
2206
- }
2207
- if (startBuffered !== null && endBuffered !== null) {
2208
- let numContainers2 = prevNumContainers;
2209
- const needNewContainers = [];
2210
- for (let i = startBuffered; i <= endBuffered; i++) {
2211
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2212
- if (!containerItemKeys.has(id)) {
2213
- needNewContainers.push(i);
2214
- }
2215
- }
2216
- if (stickyIndicesArr.length > 0) {
2217
- handleStickyActivation(
2218
- ctx,
2219
- state,
2220
- stickyIndicesSet,
2221
- stickyIndicesArr,
2222
- currentStickyIdx,
2223
- needNewContainers,
2224
- startBuffered,
2225
- endBuffered
2226
- );
2227
- } else {
2228
- state.activeStickyIndex = void 0;
2229
- set$(ctx, "activeStickyIndex", void 0);
2230
- }
2231
- if (needNewContainers.length > 0) {
2232
- const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2233
- const itemType = getItemType(data[i], i);
2234
- return itemType ? String(itemType) : "";
2235
- }) : void 0;
2236
- const availableContainers = findAvailableContainers(
2237
- ctx,
2238
- state,
2239
- needNewContainers.length,
2240
- startBuffered,
2241
- endBuffered,
2242
- pendingRemoval,
2243
- requiredItemTypes,
2244
- needNewContainers
2245
- );
2246
- for (let idx = 0; idx < needNewContainers.length; idx++) {
2247
- const i = needNewContainers[idx];
2248
- const containerIndex = availableContainers[idx];
2249
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
2250
- const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2251
- if (oldKey && oldKey !== id) {
2252
- containerItemKeys.delete(oldKey);
2253
- }
2254
- set$(ctx, `containerItemKey${containerIndex}`, id);
2255
- set$(ctx, `containerItemData${containerIndex}`, data[i]);
2256
- if (requiredItemTypes) {
2257
- state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2258
- }
2259
- containerItemKeys.add(id);
2260
- if (stickyIndicesSet.has(i)) {
2261
- set$(ctx, `containerSticky${containerIndex}`, true);
2262
- const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2263
- set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2264
- state.stickyContainerPool.add(containerIndex);
2265
- } else {
2266
- set$(ctx, `containerSticky${containerIndex}`, false);
2267
- state.stickyContainerPool.delete(containerIndex);
2268
- }
2269
- if (containerIndex >= numContainers2) {
2270
- numContainers2 = containerIndex + 1;
2271
- }
2272
- }
2273
- if (numContainers2 !== prevNumContainers) {
2274
- set$(ctx, "numContainers", numContainers2);
2275
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2276
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2277
- }
2278
- }
2279
- }
2280
- }
2281
- if (stickyIndicesArr.length > 0) {
2282
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2283
- }
2284
- let didChangePositions = false;
2285
- for (let i = 0; i < numContainers; i++) {
2286
- const itemKey = peek$(ctx, `containerItemKey${i}`);
2287
- if (pendingRemoval.includes(i)) {
2288
- if (itemKey !== void 0) {
2289
- containerItemKeys.delete(itemKey);
2290
- }
2291
- state.containerItemTypes.delete(i);
2292
- if (state.stickyContainerPool.has(i)) {
2293
- set$(ctx, `containerSticky${i}`, false);
2294
- set$(ctx, `containerStickyOffset${i}`, void 0);
2295
- state.stickyContainerPool.delete(i);
2296
- }
2297
- set$(ctx, `containerItemKey${i}`, void 0);
2298
- set$(ctx, `containerItemData${i}`, void 0);
2299
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2300
- set$(ctx, `containerColumn${i}`, -1);
2301
- } else {
2302
- const itemIndex = indexByKey.get(itemKey);
2303
- const item = data[itemIndex];
2304
- if (item !== void 0) {
2305
- const id = (_j = idCache[itemIndex]) != null ? _j : getId(state, itemIndex);
2306
- const positionValue = positions.get(id);
2307
- if (positionValue === void 0) {
2308
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2309
- } else {
2310
- const position = (positionValue || 0) - scrollAdjustPending;
2311
- const column = columns.get(id) || 1;
2312
- const prevPos = peek$(ctx, `containerPosition${i}`);
2313
- const prevColumn = peek$(ctx, `containerColumn${i}`);
2314
- const prevData = peek$(ctx, `containerItemData${i}`);
2315
- if (position > POSITION_OUT_OF_VIEW && position !== prevPos) {
2316
- set$(ctx, `containerPosition${i}`, position);
2317
- didChangePositions = true;
2318
- }
2319
- if (column >= 0 && column !== prevColumn) {
2320
- set$(ctx, `containerColumn${i}`, column);
2321
- }
2322
- if (prevData !== item && (itemsAreEqual ? !itemsAreEqual(prevData, item, itemIndex, data) : true)) {
2323
- set$(ctx, `containerItemData${i}`, item);
2324
- }
2325
- }
2326
- }
2327
- }
2328
- }
2329
- if (Platform2.OS === "web" && didChangePositions) {
2330
- set$(ctx, "lastPositionUpdate", Date.now());
2331
- }
2332
- if (!queuedInitialLayout && endBuffered !== null) {
2333
- if (checkAllSizesKnown(state)) {
2334
- setDidLayout(ctx, state);
2335
- }
2336
- }
2337
- if (viewabilityConfigCallbackPairs) {
2338
- updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollLength, startNoBuffer, endNoBuffer);
2339
- }
2340
- if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
2341
- const item = data[nextActiveStickyIndex];
2342
- if (item !== void 0) {
2343
- onStickyHeaderChange({ index: nextActiveStickyIndex, item });
2344
- }
2345
- }
2346
- });
2347
- if (state.initialAnchor) {
2348
- ensureInitialAnchor(ctx, state);
2349
- }
2350
- }
2351
-
2352
- // src/core/checkActualChange.ts
2353
- function checkActualChange(state, dataProp, previousData) {
2354
- if (!previousData || !dataProp || dataProp.length !== previousData.length) {
2355
- return true;
2356
- }
2357
- const {
2358
- idCache,
2359
- props: { keyExtractor }
2360
- } = state;
2361
- for (let i = 0; i < dataProp.length; i++) {
2362
- if (dataProp[i] !== previousData[i]) {
2363
- return true;
2364
- }
2365
- if (keyExtractor ? idCache[i] !== keyExtractor(previousData[i], i) : dataProp[i] !== previousData[i]) {
2366
- return true;
2367
- }
2368
- }
2369
- return false;
2370
- }
2371
-
2372
- // src/core/doMaintainScrollAtEnd.ts
2373
- function doMaintainScrollAtEnd(ctx, state, animated) {
2374
- const {
2375
- refScroller,
2376
- props: { maintainScrollAtEnd }
2377
- } = state;
2378
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2379
- const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2380
- if (paddingTop > 0) {
2381
- state.scroll = 0;
2382
- }
2383
- requestAnimationFrame(() => {
2384
- var _a3;
2385
- if (state == null ? void 0 : state.isAtEnd) {
2386
- state.maintainingScrollAtEnd = true;
2387
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2388
- animated
2389
- });
2390
- setTimeout(
2391
- () => {
2392
- state.maintainingScrollAtEnd = false;
2393
- },
2394
- 0
2395
- );
2396
- }
2397
- });
2398
- return true;
2399
- }
2400
- return false;
2401
- }
2402
-
2403
- // src/utils/updateAveragesOnDataChange.ts
2404
- function updateAveragesOnDataChange(state, oldData, newData) {
2405
- var _a3;
2406
- const {
2407
- averageSizes,
2408
- sizesKnown,
2409
- indexByKey,
2410
- props: { itemsAreEqual, getItemType, keyExtractor }
2411
- } = state;
2412
- if (!itemsAreEqual || !oldData.length || !newData.length) {
2413
- for (const key in averageSizes) {
2414
- delete averageSizes[key];
2415
- }
2416
- return;
2417
- }
2418
- const itemTypesToPreserve = {};
2419
- const newDataLength = newData.length;
2420
- const oldDataLength = oldData.length;
2421
- for (let newIndex = 0; newIndex < newDataLength; newIndex++) {
2422
- const newItem = newData[newIndex];
2423
- const id = keyExtractor ? keyExtractor(newItem, newIndex) : String(newIndex);
2424
- const oldIndex = indexByKey.get(id);
2425
- if (oldIndex !== void 0 && oldIndex < oldDataLength) {
2426
- const knownSize = sizesKnown.get(id);
2427
- if (knownSize === void 0) continue;
2428
- const oldItem = oldData[oldIndex];
2429
- const areEqual = itemsAreEqual(oldItem, newItem, newIndex, newData);
2430
- if (areEqual) {
2431
- const itemType = getItemType ? (_a3 = getItemType(newItem, newIndex)) != null ? _a3 : "" : "";
2432
- let typeData = itemTypesToPreserve[itemType];
2433
- if (!typeData) {
2434
- typeData = itemTypesToPreserve[itemType] = { count: 0, totalSize: 0 };
2435
- }
2436
- typeData.totalSize += knownSize;
2437
- typeData.count++;
2438
- }
2439
- }
2440
- }
2441
- for (const key in averageSizes) {
2442
- delete averageSizes[key];
2443
- }
2444
- for (const itemType in itemTypesToPreserve) {
2445
- const { totalSize, count } = itemTypesToPreserve[itemType];
2446
- if (count > 0) {
2447
- averageSizes[itemType] = {
2448
- avg: totalSize / count,
2449
- num: count
2450
- };
2451
- }
2452
- }
2453
- }
2454
-
2455
- // src/core/checkResetContainers.ts
2456
- function checkResetContainers(ctx, state, dataProp) {
2457
- const { previousData } = state;
2458
- if (previousData) {
2459
- updateAveragesOnDataChange(state, previousData, dataProp);
2460
- }
2461
- const { maintainScrollAtEnd } = state.props;
2462
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2463
- const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2464
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2465
- if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2466
- state.isEndReached = false;
2467
- }
2468
- if (!didMaintainScrollAtEnd) {
2469
- checkAtTop(state);
2470
- checkAtBottom(ctx, state);
2471
- }
2472
- delete state.previousData;
2473
- }
2474
-
2475
- // src/core/doInitialAllocateContainers.ts
2476
- function doInitialAllocateContainers(ctx, state) {
2477
- var _a3, _b, _c;
2478
- const {
2479
- scrollLength,
2480
- props: {
2481
- data,
2482
- getEstimatedItemSize,
2483
- getFixedItemSize,
2484
- getItemType,
2485
- scrollBuffer,
2486
- numColumns,
2487
- estimatedItemSize
2488
- }
2489
- } = state;
2490
- const hasContainers = peek$(ctx, "numContainers");
2491
- if (scrollLength > 0 && data.length > 0 && !hasContainers) {
2492
- let averageItemSize;
2493
- if (getFixedItemSize || getEstimatedItemSize) {
2494
- let totalSize = 0;
2495
- const num = Math.min(20, data.length);
2496
- for (let i = 0; i < num; i++) {
2497
- const item = data[i];
2498
- const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2499
- totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2500
- }
2501
- averageItemSize = totalSize / num;
2502
- } else {
2503
- averageItemSize = estimatedItemSize;
2504
- }
2505
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize * numColumns);
2506
- for (let i = 0; i < numContainers; i++) {
2507
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2508
- set$(ctx, `containerColumn${i}`, -1);
2509
- }
2510
- set$(ctx, "numContainers", numContainers);
2511
- set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
2512
- if (!IsNewArchitecture || state.lastLayout) {
2513
- if (state.initialScroll) {
2514
- requestAnimationFrame(() => {
2515
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2516
- });
2517
- } else {
2518
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2519
- }
2520
- }
2521
- return true;
2522
- }
2523
- }
2524
-
2525
- // src/core/handleLayout.ts
2526
- function handleLayout(ctx, state, layout, setCanRender) {
2527
- const { maintainScrollAtEnd } = state.props;
2528
- const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2529
- const previousLength = state.scrollLength;
2530
- const scrollLength = measuredLength > 0 ? measuredLength : previousLength;
2531
- const otherAxisSize = layout[state.props.horizontal ? "height" : "width"];
2532
- const needsCalculate = !state.lastLayout || scrollLength > state.scrollLength || state.lastLayout.x !== layout.x || state.lastLayout.y !== layout.y;
2533
- state.lastLayout = layout;
2534
- const prevOtherAxisSize = state.otherAxisSize;
2535
- const didChange = scrollLength !== state.scrollLength || otherAxisSize !== prevOtherAxisSize;
2536
- if (didChange) {
2537
- state.scrollLength = scrollLength;
2538
- state.otherAxisSize = otherAxisSize;
2539
- state.lastBatchingAction = Date.now();
2540
- state.scrollForNextCalculateItemsInView = void 0;
2541
- if (scrollLength > 0) {
2542
- doInitialAllocateContainers(ctx, state);
2543
- }
2544
- if (needsCalculate) {
2545
- calculateItemsInView(ctx, state, { doMVCP: true });
2546
- }
2547
- if (didChange || otherAxisSize !== prevOtherAxisSize) {
2548
- set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2549
- }
2550
- if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2551
- doMaintainScrollAtEnd(ctx, state, false);
2552
- }
2553
- updateAlignItemsPaddingTop(ctx, state);
2554
- checkAtBottom(ctx, state);
2555
- checkAtTop(state);
2556
- if (state) {
2557
- state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
2558
- }
2559
- if (IS_DEV && measuredLength === 0) {
2560
- warnDevOnce(
2561
- "height0",
2562
- `List ${state.props.horizontal ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
2563
- );
2564
- }
2565
- }
2566
- setCanRender(true);
2567
- }
2568
-
2569
- // src/core/onScroll.ts
2570
- function onScroll(ctx, state, event) {
2571
- var _a3, _b, _c;
2572
- const {
2573
- scrollProcessingEnabled,
2574
- props: { onScroll: onScrollProp }
2575
- } = state;
2576
- if (scrollProcessingEnabled === false) {
2577
- return;
2578
- }
2579
- if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2580
- return;
2581
- }
2582
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2583
- state.scrollPending = newScroll;
2584
- updateScroll(ctx, state, newScroll);
2585
- onScrollProp == null ? void 0 : onScrollProp(event);
2586
- }
2587
-
2588
- // src/core/ScrollAdjustHandler.ts
2589
- var ScrollAdjustHandler = class {
2590
- constructor(ctx) {
2591
- this.appliedAdjust = 0;
2592
- this.pendingAdjust = 0;
2593
- this.mounted = false;
2594
- this.context = ctx;
2595
- if (Platform2.OS === "web") {
2596
- const commitPendingAdjust = () => {
2597
- const state = this.context.internalState;
2598
- const pending = this.pendingAdjust;
2599
- if (pending !== 0) {
2600
- this.pendingAdjust = 0;
2601
- this.appliedAdjust += pending;
2602
- state.scroll += pending;
2603
- state.scrollForNextCalculateItemsInView = void 0;
2604
- set$(this.context, "scrollAdjustPending", 0);
2605
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2606
- calculateItemsInView(this.context, this.context.internalState);
2607
- }
2608
- };
2609
- listen$(this.context, "scrollingTo", (value) => {
2610
- if (value === void 0) {
2611
- commitPendingAdjust();
2612
- }
2613
- });
2614
- }
2615
- }
2616
- requestAdjust(add) {
2617
- const scrollingTo = peek$(this.context, "scrollingTo");
2618
- if (Platform2.OS === "web" && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2619
- this.pendingAdjust += add;
2620
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
2621
- } else {
2622
- this.appliedAdjust += add;
2623
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2624
- }
2625
- }
2626
- setMounted() {
2627
- this.mounted = true;
2628
- }
2629
- getAdjust() {
2630
- return this.appliedAdjust;
2631
- }
2632
- };
2633
-
2634
- // src/core/updateItemSize.ts
2635
- function updateItemSize(ctx, state, itemKey, sizeObj) {
2636
- var _a3;
2637
- const {
2638
- sizesKnown,
2639
- props: {
2640
- getFixedItemSize,
2641
- getItemType,
2642
- horizontal,
2643
- suggestEstimatedItemSize,
2644
- onItemSizeChanged,
2645
- data,
2646
- maintainScrollAtEnd
2647
- }
2648
- } = state;
2649
- if (!data) return;
2650
- const index = state.indexByKey.get(itemKey);
2651
- if (getFixedItemSize) {
2652
- if (index === void 0) {
2653
- return;
2654
- }
2655
- const itemData = state.props.data[index];
2656
- if (itemData === void 0) {
2657
- return;
2658
- }
2659
- const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
2660
- const size2 = getFixedItemSize(index, itemData, type);
2661
- if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
2662
- return;
2663
- }
2664
- }
2665
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2666
- let needsRecalculate = !containersDidLayout;
2667
- let shouldMaintainScrollAtEnd = false;
2668
- let minIndexSizeChanged;
2669
- let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2670
- const prevSizeKnown = state.sizesKnown.get(itemKey);
2671
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
2672
- const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2673
- if (diff !== 0) {
2674
- minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2675
- const { startBuffered, endBuffered } = state;
2676
- needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2677
- if (!needsRecalculate) {
2678
- const numContainers = ctx.values.get("numContainers");
2679
- for (let i = 0; i < numContainers; i++) {
2680
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2681
- needsRecalculate = true;
2682
- break;
2683
- }
2684
- }
2685
- }
2686
- if (state.needsOtherAxisSize) {
2687
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2688
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
2689
- }
2690
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2691
- shouldMaintainScrollAtEnd = true;
2692
- }
2693
- onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2694
- index,
2695
- itemData: state.props.data[index],
2696
- itemKey,
2697
- previous: size - diff,
2698
- size
2699
- });
2700
- }
2701
- if (minIndexSizeChanged !== void 0) {
2702
- state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
2703
- }
2704
- if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2705
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
2706
- state.timeoutSizeMessage = setTimeout(() => {
2707
- var _a4;
2708
- state.timeoutSizeMessage = void 0;
2709
- const num = state.sizesKnown.size;
2710
- const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
2711
- console.warn(
2712
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2713
- );
2714
- }, 1e3);
2715
- }
2716
- const cur = peek$(ctx, "otherAxisSize");
2717
- if (!cur || maxOtherAxisSize > cur) {
2718
- set$(ctx, "otherAxisSize", maxOtherAxisSize);
2719
- }
2720
- if (containersDidLayout || checkAllSizesKnown(state)) {
2721
- if (needsRecalculate) {
2722
- state.scrollForNextCalculateItemsInView = void 0;
2723
- calculateItemsInView(ctx, state, { doMVCP: true });
2724
- }
2725
- if (shouldMaintainScrollAtEnd) {
2726
- if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2727
- doMaintainScrollAtEnd(ctx, state, false);
2728
- }
2729
- }
2730
- }
2731
- }
2732
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2733
- var _a3;
2734
- const {
2735
- sizes,
2736
- indexByKey,
2737
- sizesKnown,
2738
- averageSizes,
2739
- props: { data, horizontal, getEstimatedItemSize, getItemType, getFixedItemSize }
2740
- } = state;
2741
- if (!data) return 0;
2742
- const index = indexByKey.get(itemKey);
2743
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
2744
- const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2745
- const size = Platform2.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
2746
- sizesKnown.set(itemKey, size);
2747
- if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2748
- const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
2749
- let averages = averageSizes[itemType];
2750
- if (!averages) {
2751
- averages = averageSizes[itemType] = { avg: 0, num: 0 };
2752
- }
2753
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2754
- averages.num++;
2755
- }
2756
- if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2757
- setSize(ctx, state, itemKey, size);
2758
- return size - prevSize;
2759
- }
2760
- return 0;
2761
- }
2762
- var useCombinedRef = (...refs) => {
2763
- const callback = useCallback((element) => {
2764
- for (const ref of refs) {
2765
- if (!ref) {
2766
- continue;
2767
- }
2768
- if (isFunction(ref)) {
2769
- ref(element);
2770
- } else {
2771
- ref.current = element;
2772
- }
2773
- }
2774
- }, refs);
2775
- return callback;
2776
- };
2777
- function getWindowSize() {
2778
- const screenSize = Dimensions.get("window");
2779
- return {
2780
- height: screenSize.height,
2781
- width: screenSize.width
2782
- };
2783
- }
2784
- var StyleSheet = StyleSheet$1;
2785
- function useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, onScroll2) {
2786
- return useMemo(() => {
2787
- if (stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.length) {
2788
- const { animatedScrollY } = ctx;
2789
- return Animated.event(
2790
- [
2791
- {
2792
- nativeEvent: {
2793
- contentOffset: { [horizontal ? "x" : "y"]: animatedScrollY }
2794
- }
2795
- }
2796
- ],
2797
- {
2798
- listener: onScroll2,
2799
- useNativeDriver: true
2800
- }
2801
- );
2802
- }
2803
- return onScroll2;
2804
- }, [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(","), horizontal]);
2805
- }
2806
-
2807
- // src/utils/createColumnWrapperStyle.ts
2808
- function createColumnWrapperStyle(contentContainerStyle) {
2809
- const { gap, columnGap, rowGap } = contentContainerStyle;
2810
- if (gap || columnGap || rowGap) {
2811
- contentContainerStyle.gap = void 0;
2812
- contentContainerStyle.columnGap = void 0;
2813
- contentContainerStyle.rowGap = void 0;
2814
- return {
2815
- columnGap,
2816
- gap,
2817
- rowGap
2818
- };
2819
- }
2820
- }
2821
-
2822
- // src/utils/createImperativeHandle.ts
2823
- function createImperativeHandle(ctx, state) {
2824
- const scrollIndexIntoView = (options) => {
2825
- if (state) {
2826
- const { index, ...rest } = options;
2827
- const { startNoBuffer, endNoBuffer } = state;
2828
- if (index < startNoBuffer || index > endNoBuffer) {
2829
- const viewPosition = index < startNoBuffer ? 0 : 1;
2830
- scrollToIndex(ctx, state, {
2831
- ...rest,
2832
- index,
2833
- viewPosition
2834
- });
2835
- }
2836
- }
2837
- };
2838
- const refScroller = state.refScroller;
2839
- return {
2840
- flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
2841
- getNativeScrollRef: () => refScroller.current,
2842
- getScrollableNode: () => refScroller.current.getScrollableNode(),
2843
- getScrollResponder: () => refScroller.current.getScrollResponder(),
2844
- getState: () => ({
2845
- activeStickyIndex: state.activeStickyIndex,
2846
- contentLength: state.totalSize,
2847
- data: state.props.data,
2848
- elementAtIndex: (index) => {
2849
- var _a3;
2850
- return (_a3 = ctx.viewRefs.get(findContainerId(ctx, getId(state, index)))) == null ? void 0 : _a3.current;
2851
- },
2852
- end: state.endNoBuffer,
2853
- endBuffered: state.endBuffered,
2854
- isAtEnd: state.isAtEnd,
2855
- isAtStart: state.isAtStart,
2856
- positionAtIndex: (index) => state.positions.get(getId(state, index)),
2857
- positions: state.positions,
2858
- scroll: state.scroll,
2859
- scrollLength: state.scrollLength,
2860
- sizeAtIndex: (index) => state.sizesKnown.get(getId(state, index)),
2861
- sizes: state.sizesKnown,
2862
- start: state.startNoBuffer,
2863
- startBuffered: state.startBuffered
2864
- }),
2865
- scrollIndexIntoView,
2866
- scrollItemIntoView: ({ item, ...props }) => {
2867
- const data = state.props.data;
2868
- const index = data.indexOf(item);
2869
- if (index !== -1) {
2870
- scrollIndexIntoView({ index, ...props });
2871
- }
2872
- },
2873
- scrollToEnd: (options) => {
2874
- const data = state.props.data;
2875
- const stylePaddingBottom = state.props.stylePaddingBottom;
2876
- const index = data.length - 1;
2877
- if (index !== -1) {
2878
- const paddingBottom = stylePaddingBottom || 0;
2879
- const footerSize = peek$(ctx, "footerSize") || 0;
2880
- scrollToIndex(ctx, state, {
2881
- index,
2882
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
2883
- viewPosition: 1,
2884
- ...options
2885
- });
2886
- }
2887
- },
2888
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
2889
- scrollToItem: ({ item, ...props }) => {
2890
- const data = state.props.data;
2891
- const index = data.indexOf(item);
2892
- if (index !== -1) {
2893
- scrollToIndex(ctx, state, { index, ...props });
2894
- }
2895
- },
2896
- scrollToOffset: (params) => scrollTo(ctx, state, params),
2897
- setScrollProcessingEnabled: (enabled) => {
2898
- state.scrollProcessingEnabled = enabled;
2899
- },
2900
- setVisibleContentAnchorOffset: (value) => {
2901
- const val = isFunction(value) ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
2902
- set$(ctx, "scrollAdjustUserOffset", val);
2903
- }
2904
- };
2905
- }
2906
- function getRenderedItem(ctx, state, key) {
2907
- var _a3;
2908
- if (!state) {
2909
- return null;
2910
- }
2911
- const {
2912
- indexByKey,
2913
- props: { data, getItemType, renderItem }
2914
- } = state;
2915
- const index = indexByKey.get(key);
2916
- if (index === void 0) {
2917
- return null;
2918
- }
2919
- let renderedItem = null;
2920
- const extraData = peek$(ctx, "extraData");
2921
- const item = data[index];
2922
- if (renderItem && !isNullOrUndefined(item)) {
2923
- const itemProps = {
2924
- data,
2925
- extraData,
2926
- index,
2927
- item,
2928
- type: getItemType ? (_a3 = getItemType(item, index)) != null ? _a3 : "" : ""
2929
- };
2930
- renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React2__default.createElement(renderItem, itemProps);
2931
- }
2932
- return { index, item: data[index], renderedItem };
2933
- }
2934
- function useThrottleDebounce(mode) {
2935
- const timeoutRef = useRef(null);
2936
- const lastCallTimeRef = useRef(0);
2937
- const lastArgsRef = useRef(null);
2938
- const clearTimeoutRef = () => {
2939
- if (timeoutRef.current) {
2940
- clearTimeout(timeoutRef.current);
2941
- timeoutRef.current = null;
2942
- }
2943
- };
2944
- const execute = useCallback(
2945
- (callback, delay, ...args) => {
2946
- {
2947
- const now = Date.now();
2948
- lastArgsRef.current = args;
2949
- if (now - lastCallTimeRef.current >= delay) {
2950
- lastCallTimeRef.current = now;
2951
- callback(...args);
2952
- clearTimeoutRef();
2953
- } else {
2954
- clearTimeoutRef();
2955
- timeoutRef.current = setTimeout(
2956
- () => {
2957
- if (lastArgsRef.current) {
2958
- lastCallTimeRef.current = Date.now();
2959
- callback(...lastArgsRef.current);
2960
- timeoutRef.current = null;
2961
- lastArgsRef.current = null;
2962
- }
2963
- },
2964
- delay - (now - lastCallTimeRef.current)
2965
- );
2966
- }
2967
- }
2968
- },
2969
- [mode]
2970
- );
2971
- return execute;
2972
- }
2973
-
2974
- // src/utils/throttledOnScroll.ts
2975
- function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
2976
- const throttle = useThrottleDebounce("throttle");
2977
- return (event) => throttle(originalHandler, scrollEventThrottle, { nativeEvent: event.nativeEvent });
2978
- }
2979
-
2980
- // src/components/LegendList.tsx
2981
- var DEFAULT_DRAW_DISTANCE = 250;
2982
- var DEFAULT_ITEM_SIZE = 100;
2983
- var LegendList = typedMemo(
2984
- typedForwardRef(function LegendList2(props, forwardedRef) {
2985
- const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
2986
- const isChildrenMode = children !== void 0 && dataProp === void 0;
2987
- const processedProps = isChildrenMode ? {
2988
- ...restProps,
2989
- childrenMode: true,
2990
- data: (isArray(children) ? children : React2.Children.toArray(children)).flat(1),
2991
- renderItem: ({ item }) => item
2992
- } : {
2993
- ...restProps,
2994
- data: dataProp || [],
2995
- renderItem: renderItemProp
2996
- };
2997
- return /* @__PURE__ */ React2.createElement(StateProvider, null, /* @__PURE__ */ React2.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
2998
- })
2999
- );
3000
- var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3001
- var _a3, _b;
3002
- const {
3003
- alignItemsAtEnd = false,
3004
- columnWrapperStyle,
3005
- contentContainerStyle: contentContainerStyleProp,
3006
- data: dataProp = [],
3007
- dataVersion,
3008
- drawDistance = 250,
3009
- enableAverages = true,
3010
- estimatedItemSize: estimatedItemSizeProp,
3011
- estimatedListSize,
3012
- extraData,
3013
- getEstimatedItemSize,
3014
- getFixedItemSize,
3015
- getItemType,
3016
- horizontal,
3017
- initialContainerPoolRatio = 2,
3018
- initialScrollAtEnd = false,
3019
- initialScrollIndex: initialScrollIndexProp,
3020
- initialScrollOffset: initialScrollOffsetProp,
3021
- itemsAreEqual,
3022
- keyExtractor: keyExtractorProp,
3023
- ListEmptyComponent,
3024
- ListHeaderComponent,
3025
- maintainScrollAtEnd = false,
3026
- maintainScrollAtEndThreshold = 0.1,
3027
- maintainVisibleContentPosition = false,
3028
- numColumns: numColumnsProp = 1,
3029
- onEndReached,
3030
- onEndReachedThreshold = 0.5,
3031
- onItemSizeChanged,
3032
- onLayout: onLayoutProp,
3033
- onLoad,
3034
- onMomentumScrollEnd,
3035
- onRefresh,
3036
- onScroll: onScrollProp,
3037
- onStartReached,
3038
- onStartReachedThreshold = 0.5,
3039
- onStickyHeaderChange,
3040
- onViewableItemsChanged,
3041
- progressViewOffset,
3042
- recycleItems = false,
3043
- refreshControl,
3044
- refreshing,
3045
- refScrollView,
3046
- renderItem,
3047
- scrollEventThrottle,
3048
- snapToIndices,
3049
- stickyHeaderIndices: stickyHeaderIndicesProp,
3050
- stickyIndices: stickyIndicesDeprecated,
3051
- style: styleProp,
3052
- suggestEstimatedItemSize,
3053
- viewabilityConfig,
3054
- viewabilityConfigCallbackPairs,
3055
- waitForInitialLayout = true,
3056
- ...rest
3057
- } = props;
3058
- const { childrenMode } = rest;
3059
- const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3060
- const style = { ...StyleSheet.flatten(styleProp) };
3061
- const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
3062
- const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
3063
- const [renderNum, setRenderNum] = useState(0);
3064
- const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState } : initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3065
- const [canRender, setCanRender] = React2.useState(!IsNewArchitecture);
3066
- const ctx = useStateContext();
3067
- ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
3068
- const refScroller = useRef(null);
3069
- const combinedRef = useCombinedRef(refScroller, refScrollView);
3070
- const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
3071
- const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
3072
- const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
3073
- const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
3074
- if (IS_DEV && stickyIndicesDeprecated && !stickyHeaderIndicesProp) {
3075
- warnDevOnce(
3076
- "stickyIndices",
3077
- "stickyIndices has been renamed to stickyHeaderIndices. Please update your props to use stickyHeaderIndices."
3078
- );
3079
- }
3080
- const refState = useRef();
3081
- if (!refState.current) {
3082
- if (!ctx.internalState) {
3083
- const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : getWindowSize())[horizontal ? "width" : "height"];
3084
- ctx.internalState = {
3085
- activeStickyIndex: void 0,
3086
- averageSizes: {},
3087
- columns: /* @__PURE__ */ new Map(),
3088
- containerItemKeys: /* @__PURE__ */ new Set(),
3089
- containerItemTypes: /* @__PURE__ */ new Map(),
3090
- dataChangeNeedsScrollUpdate: false,
3091
- didColumnsChange: false,
3092
- didDataChange: false,
3093
- enableScrollForNextCalculateItemsInView: true,
3094
- endBuffered: -1,
3095
- endNoBuffer: -1,
3096
- endReachedSnapshot: void 0,
3097
- firstFullyOnScreenIndex: -1,
3098
- idCache: [],
3099
- idsInView: [],
3100
- indexByKey: /* @__PURE__ */ new Map(),
3101
- initialAnchor: (initialScrollProp == null ? void 0 : initialScrollProp.index) !== void 0 && (initialScrollProp == null ? void 0 : initialScrollProp.viewPosition) !== void 0 ? {
3102
- attempts: 0,
3103
- index: initialScrollProp.index,
3104
- settledTicks: 0,
3105
- viewOffset: (_a3 = initialScrollProp.viewOffset) != null ? _a3 : 0,
3106
- viewPosition: initialScrollProp.viewPosition
3107
- } : void 0,
3108
- initialScroll: initialScrollProp,
3109
- isAtEnd: false,
3110
- isAtStart: false,
3111
- isEndReached: false,
3112
- isFirst: true,
3113
- isStartReached: false,
3114
- lastBatchingAction: Date.now(),
3115
- lastLayout: void 0,
3116
- loadStartTime: Date.now(),
3117
- minIndexSizeChanged: 0,
3118
- nativeMarginTop: 0,
3119
- positions: /* @__PURE__ */ new Map(),
3120
- props: {},
3121
- queuedCalculateItemsInView: 0,
3122
- refScroller: void 0,
3123
- scroll: 0,
3124
- scrollAdjustHandler: new ScrollAdjustHandler(ctx),
3125
- scrollForNextCalculateItemsInView: void 0,
3126
- scrollHistory: [],
3127
- scrollLength: initialScrollLength,
3128
- scrollPending: 0,
3129
- scrollPrev: 0,
3130
- scrollPrevTime: 0,
3131
- scrollProcessingEnabled: true,
3132
- scrollTime: 0,
3133
- sizes: /* @__PURE__ */ new Map(),
3134
- sizesKnown: /* @__PURE__ */ new Map(),
3135
- startBuffered: -1,
3136
- startNoBuffer: -1,
3137
- startReachedSnapshot: void 0,
3138
- stickyContainerPool: /* @__PURE__ */ new Set(),
3139
- stickyContainers: /* @__PURE__ */ new Map(),
3140
- timeoutSizeMessage: 0,
3141
- timeouts: /* @__PURE__ */ new Set(),
3142
- totalSize: 0,
3143
- viewabilityConfigCallbackPairs: void 0
3144
- };
3145
- const internalState = ctx.internalState;
3146
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3147
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3148
- set$(ctx, "extraData", extraData);
3149
- }
3150
- refState.current = ctx.internalState;
3151
- }
3152
- const state = refState.current;
3153
- const isFirstLocal = state.isFirst;
3154
- state.didColumnsChange = numColumnsProp !== state.props.numColumns;
3155
- const didDataChangeLocal = state.props.dataVersion !== dataVersion || state.props.data !== dataProp && checkActualChange(state, dataProp, state.props.data);
3156
- if (didDataChangeLocal) {
3157
- state.dataChangeNeedsScrollUpdate = true;
3158
- state.didDataChange = true;
3159
- state.previousData = state.props.data;
3160
- }
3161
- const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3162
- state.props = {
3163
- alignItemsAtEnd,
3164
- data: dataProp,
3165
- dataVersion,
3166
- enableAverages,
3167
- estimatedItemSize,
3168
- getEstimatedItemSize,
3169
- getFixedItemSize,
3170
- getItemType,
3171
- horizontal: !!horizontal,
3172
- initialContainerPoolRatio,
3173
- itemsAreEqual,
3174
- keyExtractor,
3175
- maintainScrollAtEnd,
3176
- maintainScrollAtEndThreshold,
3177
- maintainVisibleContentPosition,
3178
- numColumns: numColumnsProp,
3179
- onEndReached,
3180
- onEndReachedThreshold,
3181
- onItemSizeChanged,
3182
- onLoad,
3183
- onScroll: throttleScrollFn,
3184
- onStartReached,
3185
- onStartReachedThreshold,
3186
- onStickyHeaderChange,
3187
- recycleItems: !!recycleItems,
3188
- renderItem,
3189
- scrollBuffer,
3190
- snapToIndices,
3191
- stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
3192
- stickyIndicesSet: useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
3193
- stylePaddingBottom: stylePaddingBottomState,
3194
- stylePaddingTop: stylePaddingTopState,
3195
- suggestEstimatedItemSize: !!suggestEstimatedItemSize
3196
- };
3197
- state.refScroller = refScroller;
3198
- const memoizedLastItemKeys = useMemo(() => {
3199
- if (!dataProp.length) return [];
3200
- return Array.from(
3201
- { length: Math.min(numColumnsProp, dataProp.length) },
3202
- (_, i) => getId(state, dataProp.length - 1 - i)
3203
- );
3204
- }, [dataProp, dataVersion, numColumnsProp]);
3205
- const initializeStateVars = () => {
3206
- set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3207
- set$(ctx, "numColumns", numColumnsProp);
3208
- const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3209
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3210
- refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3211
- let paddingDiff = stylePaddingTopState - prevPaddingTop;
3212
- if (paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3213
- if (state.scroll < 0) {
3214
- paddingDiff += state.scroll;
3215
- }
3216
- requestAdjust(ctx, state, paddingDiff);
3217
- }
3218
- };
3219
- if (isFirstLocal) {
3220
- initializeStateVars();
3221
- updateItemPositions(
3222
- ctx,
3223
- state,
3224
- /*dataChanged*/
3225
- true
3226
- );
3227
- }
3228
- const initialContentOffset = useMemo(() => {
3229
- var _a4, _b2;
3230
- const { initialScroll } = refState.current;
3231
- if (!initialScroll) {
3232
- refState.current.initialAnchor = void 0;
3233
- return 0;
3234
- }
3235
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3236
- refState.current.initialAnchor = {
3237
- attempts: 0,
3238
- index: initialScroll.index,
3239
- settledTicks: 0,
3240
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3241
- viewPosition: initialScroll.viewPosition
3242
- };
3243
- }
3244
- if (initialScroll.contentOffset !== void 0) {
3245
- return initialScroll.contentOffset;
3246
- }
3247
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3248
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3249
- let clampedOffset = resolvedOffset;
3250
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3251
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3252
- clampedOffset = Math.min(clampedOffset, maxOffset);
3253
- }
3254
- clampedOffset = Math.max(0, clampedOffset);
3255
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3256
- refState.current.initialScroll = updatedInitialScroll;
3257
- state.initialScroll = updatedInitialScroll;
3258
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3259
- return clampedOffset;
3260
- }, [renderNum]);
3261
- if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3262
- refState.current.lastBatchingAction = Date.now();
3263
- if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3264
- IS_DEV && !childrenMode && warnDevOnce(
3265
- "keyExtractor",
3266
- "Changing data without a keyExtractor can cause slow performance and resetting scroll. If your list data can change you should use a keyExtractor with a unique id for best performance and behavior."
3267
- );
3268
- refState.current.sizes.clear();
3269
- refState.current.positions.clear();
3270
- refState.current.totalSize = 0;
3271
- set$(ctx, "totalSize", 0);
3272
- }
3273
- }
3274
- const onLayoutHeader = useCallback((rect, fromLayoutEffect) => {
3275
- const { initialScroll } = refState.current;
3276
- const size = rect[horizontal ? "width" : "height"];
3277
- set$(ctx, "headerSize", size);
3278
- if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
3279
- if (IsNewArchitecture && Platform2.OS !== "android") {
3280
- if (fromLayoutEffect) {
3281
- setRenderNum((v) => v + 1);
3282
- }
3283
- } else {
3284
- setTimeout(doInitialScroll, 17);
3285
- }
3286
- }
3287
- }, []);
3288
- const doInitialScroll = useCallback(() => {
3289
- var _a4;
3290
- const initialScroll = state.initialScroll;
3291
- if (initialScroll) {
3292
- scrollTo(ctx, state, {
3293
- animated: false,
3294
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3295
- isInitialScroll: true,
3296
- offset: initialContentOffset,
3297
- precomputedWithViewOffset: true
3298
- });
3299
- }
3300
- }, [initialContentOffset]);
3301
- const onLayoutChange = useCallback((layout) => {
3302
- doInitialScroll();
3303
- handleLayout(ctx, state, layout, setCanRender);
3304
- }, []);
3305
- const { onLayout } = useOnLayoutSync({
3306
- onLayoutChange,
3307
- onLayoutProp,
3308
- ref: refScroller
3309
- // the type of ScrollView doesn't include measure?
3310
- });
3311
- useLayoutEffect(() => {
3312
- if (snapToIndices) {
3313
- updateSnapToOffsets(ctx, state);
3314
- }
3315
- }, [snapToIndices]);
3316
- useLayoutEffect(() => {
3317
- const {
3318
- didColumnsChange,
3319
- didDataChange,
3320
- isFirst,
3321
- props: { data }
3322
- } = state;
3323
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3324
- if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3325
- checkResetContainers(ctx, state, data);
3326
- }
3327
- state.didColumnsChange = false;
3328
- state.didDataChange = false;
3329
- state.isFirst = false;
3330
- }, [dataProp, dataVersion, numColumnsProp]);
3331
- useLayoutEffect(() => {
3332
- set$(ctx, "extraData", extraData);
3333
- }, [extraData]);
3334
- useLayoutEffect(initializeStateVars, [
3335
- dataVersion,
3336
- memoizedLastItemKeys.join(","),
3337
- numColumnsProp,
3338
- stylePaddingBottomState,
3339
- stylePaddingTopState
3340
- ]);
3341
- useEffect(() => {
3342
- const viewability = setupViewability({
3343
- onViewableItemsChanged,
3344
- viewabilityConfig,
3345
- viewabilityConfigCallbackPairs
3346
- });
3347
- state.viewabilityConfigCallbackPairs = viewability;
3348
- state.enableScrollForNextCalculateItemsInView = !viewability;
3349
- }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3350
- if (!IsNewArchitecture) {
3351
- useInit(() => {
3352
- doInitialAllocateContainers(ctx, state);
3353
- });
3354
- }
3355
- useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3356
- if (Platform2.OS === "web") {
3357
- useEffect(doInitialScroll, []);
3358
- }
3359
- const fns = useMemo(
3360
- () => ({
3361
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3362
- onScroll: (event) => onScroll(ctx, state, event),
3363
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3364
- }),
3365
- []
3366
- );
3367
- const onScrollHandler = useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, fns.onScroll);
3368
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(
3369
- ListComponent,
3370
- {
3371
- ...rest,
3372
- alignItemsAtEnd,
3373
- canRender,
3374
- contentContainerStyle,
3375
- getRenderedItem: fns.getRenderedItem,
3376
- horizontal,
3377
- initialContentOffset,
3378
- ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
3379
- ListHeaderComponent,
3380
- maintainVisibleContentPosition,
3381
- onLayout,
3382
- onLayoutHeader,
3383
- onMomentumScrollEnd: (event) => {
3384
- if (IsNewArchitecture) {
3385
- requestAnimationFrame(() => {
3386
- finishScrollTo(ctx, refState.current);
3387
- });
3388
- } else {
3389
- setTimeout(() => {
3390
- finishScrollTo(ctx, refState.current);
3391
- }, 1e3);
3392
- }
3393
- if (onMomentumScrollEnd) {
3394
- onMomentumScrollEnd(event);
3395
- }
3396
- },
3397
- onScroll: onScrollHandler,
3398
- recycleItems,
3399
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControl, {
3400
- progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
3401
- }) : refreshControl : onRefresh && /* @__PURE__ */ React2.createElement(
3402
- RefreshControl,
3403
- {
3404
- onRefresh,
3405
- progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState,
3406
- refreshing: !!refreshing
3407
- }
3408
- ),
3409
- refScrollView: combinedRef,
3410
- scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3411
- scrollEventThrottle: Platform2.OS === "web" ? 16 : void 0,
3412
- snapToIndices,
3413
- stickyHeaderIndices,
3414
- style,
3415
- updateItemSize: fns.updateItemSize,
3416
- waitForInitialLayout
3417
- }
3418
- ), IS_DEV && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React2.createElement(DebugView, { state: refState.current }));
3419
- });
3420
6
 
3421
7
  // src/section-list/flattenSections.ts
3422
8
  var defaultKeyExtractor = (item, index) => {
3423
- var _a3;
3424
- const key = (_a3 = item == null ? void 0 : item.key) != null ? _a3 : item == null ? void 0 : item.id;
9
+ var _a;
10
+ const key = (_a = item == null ? void 0 : item.key) != null ? _a : item == null ? void 0 : item.id;
3425
11
  return key != null ? String(key) : String(index);
3426
12
  };
3427
13
  var getSectionKey = (section, sectionIndex) => {
3428
- var _a3;
3429
- return (_a3 = section.key) != null ? _a3 : `section-${sectionIndex}`;
14
+ var _a;
15
+ return (_a = section.key) != null ? _a : `section-${sectionIndex}`;
3430
16
  };
3431
17
  function buildSectionListData({
3432
18
  sections,
@@ -3437,14 +23,14 @@ function buildSectionListData({
3437
23
  stickySectionHeadersEnabled,
3438
24
  keyExtractor = defaultKeyExtractor
3439
25
  }) {
3440
- var _a3, _b;
26
+ var _a, _b;
3441
27
  const data = [];
3442
28
  const sectionMeta = [];
3443
29
  const stickyHeaderIndices = [];
3444
30
  let absoluteItemIndex = 0;
3445
31
  for (let sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) {
3446
32
  const section = sections[sectionIndex];
3447
- const items = (_a3 = section.data) != null ? _a3 : [];
33
+ const items = (_a = section.data) != null ? _a : [];
3448
34
  const meta = { items: [] };
3449
35
  const sectionKey = getSectionKey(section, sectionIndex);
3450
36
  const hasHeader = typeof renderSectionHeader === "function";
@@ -3454,8 +40,8 @@ function buildSectionListData({
3454
40
  if (hasHeader) {
3455
41
  const headerIndex = data.length;
3456
42
  data.push({
3457
- kind: "header",
3458
43
  key: `${sectionKey}:header`,
44
+ kind: "header",
3459
45
  section,
3460
46
  sectionIndex
3461
47
  });
@@ -3469,31 +55,31 @@ function buildSectionListData({
3469
55
  const itemKeyExtractor = (_b = section.keyExtractor) != null ? _b : keyExtractor;
3470
56
  const itemKey = itemKeyExtractor(item, itemIndex);
3471
57
  data.push({
3472
- kind: "item",
3473
- key: `${sectionKey}:item:${itemKey}`,
3474
- section,
3475
- sectionIndex,
58
+ absoluteItemIndex: absoluteItemIndex++,
3476
59
  item,
3477
60
  itemIndex,
3478
- absoluteItemIndex: absoluteItemIndex++
61
+ key: `${sectionKey}:item:${itemKey}`,
62
+ kind: "item",
63
+ section,
64
+ sectionIndex
3479
65
  });
3480
66
  meta.items.push(data.length - 1);
3481
67
  if (hasItemSeparator && itemIndex < items.length - 1) {
3482
68
  data.push({
3483
- kind: "item-separator",
3484
69
  key: `${sectionKey}:separator:${itemIndex}`,
3485
- section,
3486
- sectionIndex,
70
+ kind: "item-separator",
3487
71
  leadingItem: item,
3488
72
  leadingItemIndex: itemIndex,
73
+ section,
74
+ sectionIndex,
3489
75
  trailingItem: items[itemIndex + 1]
3490
76
  });
3491
77
  }
3492
78
  }
3493
79
  if (hasFooter) {
3494
80
  data.push({
3495
- kind: "footer",
3496
81
  key: `${sectionKey}:footer`,
82
+ kind: "footer",
3497
83
  section,
3498
84
  sectionIndex
3499
85
  });
@@ -3502,8 +88,8 @@ function buildSectionListData({
3502
88
  const isLastSection = sectionIndex === sections.length - 1;
3503
89
  if (hasSectionSeparator && !isLastSection) {
3504
90
  data.push({
3505
- kind: "section-separator",
3506
91
  key: `${sectionKey}:section-separator`,
92
+ kind: "section-separator",
3507
93
  leadingSection: section,
3508
94
  leadingSectionIndex: sectionIndex,
3509
95
  trailingSection: sections[sectionIndex + 1]
@@ -3525,11 +111,11 @@ var defaultSeparators = {
3525
111
  };
3526
112
  function resolveSeparatorComponent(component, props) {
3527
113
  if (!component) return null;
3528
- if (React2.isValidElement(component)) {
114
+ if (React.isValidElement(component)) {
3529
115
  return component;
3530
116
  }
3531
117
  const Component = component;
3532
- return /* @__PURE__ */ React2.createElement(Component, { ...props });
118
+ return /* @__PURE__ */ React.createElement(Component, { ...props });
3533
119
  }
3534
120
  var SectionList = typedMemo(
3535
121
  typedForwardRef(function SectionListInner(props, ref) {
@@ -3547,8 +133,8 @@ var SectionList = typedMemo(
3547
133
  horizontal,
3548
134
  ...restProps
3549
135
  } = props;
3550
- const legendListRef = React2.useRef(null);
3551
- const flattened = React2.useMemo(
136
+ const legendListRef = React.useRef(null);
137
+ const flattened = React.useMemo(
3552
138
  () => buildSectionListData({
3553
139
  ItemSeparatorComponent,
3554
140
  keyExtractor,
@@ -3571,7 +157,7 @@ var SectionList = typedMemo(
3571
157
  ]
3572
158
  );
3573
159
  const { data, sectionMeta, stickyHeaderIndices } = flattened;
3574
- const handleViewableItemsChanged = React2.useMemo(() => {
160
+ const handleViewableItemsChanged = React.useMemo(() => {
3575
161
  if (!onViewableItemsChanged) return void 0;
3576
162
  return ({
3577
163
  viewableItems,
@@ -3592,16 +178,16 @@ var SectionList = typedMemo(
3592
178
  onViewableItemsChanged({ changed: mappedChanged, viewableItems: mappedViewable });
3593
179
  };
3594
180
  }, [onViewableItemsChanged]);
3595
- const renderItem = React2.useCallback(
181
+ const renderItem = React.useCallback(
3596
182
  ({ item }) => {
3597
- var _a3, _b;
183
+ var _a, _b;
3598
184
  switch (item.kind) {
3599
185
  case "header":
3600
186
  return renderSectionHeader ? renderSectionHeader({ section: item.section }) : null;
3601
187
  case "footer":
3602
188
  return renderSectionFooter ? renderSectionFooter({ section: item.section }) : null;
3603
189
  case "item": {
3604
- const render = (_a3 = item.section.renderItem) != null ? _a3 : renderItemProp;
190
+ const render = (_a = item.section.renderItem) != null ? _a : renderItemProp;
3605
191
  if (!render) return null;
3606
192
  return render({
3607
193
  index: item.itemIndex,
@@ -3640,12 +226,12 @@ var SectionList = typedMemo(
3640
226
  renderSectionHeader
3641
227
  ]
3642
228
  );
3643
- const scrollToLocation = React2.useCallback(
229
+ const scrollToLocation = React.useCallback(
3644
230
  ({ sectionIndex, itemIndex, viewOffset, viewPosition, animated }) => {
3645
- var _a3, _b, _c;
231
+ var _a, _b, _c;
3646
232
  const meta = sectionMeta[sectionIndex];
3647
233
  if (!meta) return;
3648
- const target = itemIndex === -1 ? (_b = (_a3 = meta.header) != null ? _a3 : meta.items[0]) != null ? _b : meta.footer : meta.items[itemIndex];
234
+ const target = itemIndex === -1 ? (_b = (_a = meta.header) != null ? _a : meta.items[0]) != null ? _b : meta.footer : meta.items[itemIndex];
3649
235
  if (target === void 0) return;
3650
236
  (_c = legendListRef.current) == null ? void 0 : _c.scrollToIndex({
3651
237
  animated,
@@ -3656,7 +242,7 @@ var SectionList = typedMemo(
3656
242
  },
3657
243
  [sectionMeta]
3658
244
  );
3659
- React2.useImperativeHandle(
245
+ React.useImperativeHandle(
3660
246
  ref,
3661
247
  () => ({
3662
248
  ...legendListRef.current,
@@ -3664,7 +250,7 @@ var SectionList = typedMemo(
3664
250
  }),
3665
251
  [scrollToLocation]
3666
252
  );
3667
- return /* @__PURE__ */ React2.createElement(
253
+ return /* @__PURE__ */ React.createElement(
3668
254
  LegendList,
3669
255
  {
3670
256
  ...restProps,