@legendapp/list 3.0.0-beta.5 → 3.0.0-beta.50

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