@legendapp/list 3.0.0-beta.9 → 3.0.1

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