@legendapp/list 2.0.0-next.0 → 2.0.0-next.10

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.
package/index.mjs CHANGED
@@ -1,45 +1,36 @@
1
- import * as React2 from 'react';
2
- import { useReducer, useEffect, createContext, useMemo, useState, useRef, useCallback, useLayoutEffect, useImperativeHandle, useContext, forwardRef, memo } from 'react';
3
- import { View, Text, Platform, Animated, ScrollView, StyleSheet, Dimensions, RefreshControl } from 'react-native';
1
+ import * as React3 from 'react';
2
+ import React3__default, { useReducer, useEffect, createContext, useRef, useState, useMemo, useLayoutEffect, useCallback, useImperativeHandle, useContext, forwardRef, memo } from 'react';
3
+ import { View, Text, Platform, Animated, ScrollView, StyleSheet, Dimensions, RefreshControl, unstable_batchedUpdates } from 'react-native';
4
4
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
5
5
 
6
- // src/LegendList.tsx
7
- var ContextState = React2.createContext(null);
6
+ // src/components/LazyLegendList.tsx
7
+ var ContextState = React3.createContext(null);
8
8
  function StateProvider({ children }) {
9
- const [value] = React2.useState(() => ({
9
+ const [value] = React3.useState(() => ({
10
+ columnWrapperStyle: void 0,
10
11
  listeners: /* @__PURE__ */ new Map(),
12
+ mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
13
+ mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
14
+ mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
15
+ mapViewabilityValues: /* @__PURE__ */ new Map(),
11
16
  values: /* @__PURE__ */ new Map([
12
17
  ["alignItemsPaddingTop", 0],
13
18
  ["stylePaddingTop", 0],
14
- ["headerSize", 0]
19
+ ["headerSize", 0],
20
+ ["numContainers", 0],
21
+ ["totalSize", 0]
15
22
  ]),
16
- mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
17
- mapViewabilityValues: /* @__PURE__ */ new Map(),
18
- mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
19
- mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
20
- columnWrapperStyle: void 0,
21
23
  viewRefs: /* @__PURE__ */ new Map()
22
24
  }));
23
- return /* @__PURE__ */ React2.createElement(ContextState.Provider, { value }, children);
25
+ return /* @__PURE__ */ React3.createElement(ContextState.Provider, { value }, children);
24
26
  }
25
27
  function useStateContext() {
26
- return React2.useContext(ContextState);
28
+ return React3.useContext(ContextState);
27
29
  }
28
30
  function createSelectorFunctionsArr(ctx, signalNames) {
29
31
  let lastValues = [];
30
32
  let lastSignalValues = [];
31
33
  return {
32
- subscribe: (cb) => {
33
- const listeners = [];
34
- for (const signalName of signalNames) {
35
- listeners.push(listen$(ctx, signalName, cb));
36
- }
37
- return () => {
38
- for (const listener of listeners) {
39
- listener();
40
- }
41
- };
42
- },
43
34
  get: () => {
44
35
  const currentValues = [];
45
36
  let hasChanged = false;
@@ -55,6 +46,17 @@ function createSelectorFunctionsArr(ctx, signalNames) {
55
46
  lastValues = currentValues;
56
47
  }
57
48
  return lastValues;
49
+ },
50
+ subscribe: (cb) => {
51
+ const listeners = [];
52
+ for (const signalName of signalNames) {
53
+ listeners.push(listen$(ctx, signalName, cb));
54
+ }
55
+ return () => {
56
+ for (const listener of listeners) {
57
+ listener();
58
+ }
59
+ };
58
60
  }
59
61
  };
60
62
  }
@@ -89,29 +91,29 @@ function getContentSize(ctx) {
89
91
  const stylePaddingTop = values.get("stylePaddingTop") || 0;
90
92
  const headerSize = values.get("headerSize") || 0;
91
93
  const footerSize = values.get("footerSize") || 0;
92
- const totalSize = values.get("totalSize") || 0;
94
+ const totalSize = values.get("totalSize");
93
95
  return headerSize + footerSize + totalSize + stylePaddingTop;
94
96
  }
95
97
  function useArr$(signalNames) {
96
- const ctx = React2.useContext(ContextState);
97
- const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
98
+ const ctx = React3.useContext(ContextState);
99
+ const { subscribe, get } = React3.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
98
100
  const value = useSyncExternalStore(subscribe, get);
99
101
  return value;
100
102
  }
101
103
  function useSelector$(signalName, selector) {
102
- const ctx = React2.useContext(ContextState);
103
- const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
104
+ const ctx = React3.useContext(ContextState);
105
+ const { subscribe, get } = React3.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
104
106
  const value = useSyncExternalStore(subscribe, () => selector(get()[0]));
105
107
  return value;
106
108
  }
107
109
 
108
- // src/DebugView.tsx
110
+ // src/components/DebugView.tsx
109
111
  var DebugRow = ({ children }) => {
110
- return /* @__PURE__ */ React2.createElement(View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" } }, children);
112
+ return /* @__PURE__ */ React3.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
111
113
  };
112
- var DebugView = React2.memo(function DebugView2({ state }) {
114
+ var DebugView = React3.memo(function DebugView2({ state }) {
113
115
  const ctx = useStateContext();
114
- const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, numContainers = 0, numContainersPooled = 0] = useArr$([
116
+ const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
115
117
  "totalSize",
116
118
  "scrollAdjust",
117
119
  "debugRawScroll",
@@ -124,30 +126,30 @@ var DebugView = React2.memo(function DebugView2({ state }) {
124
126
  useInterval(() => {
125
127
  forceUpdate();
126
128
  }, 100);
127
- return /* @__PURE__ */ React2.createElement(
129
+ return /* @__PURE__ */ React3.createElement(
128
130
  View,
129
131
  {
132
+ pointerEvents: "none",
130
133
  style: {
131
- position: "absolute",
132
- top: 0,
133
- right: 0,
134
- paddingLeft: 4,
135
- paddingBottom: 4,
136
134
  // height: 100,
137
135
  backgroundColor: "#FFFFFFCC",
136
+ borderRadius: 4,
138
137
  padding: 4,
139
- borderRadius: 4
140
- },
141
- pointerEvents: "none"
138
+ paddingBottom: 4,
139
+ paddingLeft: 4,
140
+ position: "absolute",
141
+ right: 0,
142
+ top: 0
143
+ }
142
144
  },
143
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React2.createElement(Text, null, totalSize.toFixed(2))),
144
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React2.createElement(Text, null, contentSize.toFixed(2))),
145
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "At end:"), /* @__PURE__ */ React2.createElement(Text, null, String(state.isAtEnd))),
146
- /* @__PURE__ */ React2.createElement(Text, null),
147
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React2.createElement(Text, null, scrollAdjust.toFixed(2))),
148
- /* @__PURE__ */ React2.createElement(Text, null),
149
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React2.createElement(Text, null, rawScroll.toFixed(2))),
150
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React2.createElement(Text, null, scroll.toFixed(2)))
145
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React3.createElement(Text, null, totalSize.toFixed(2))),
146
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React3.createElement(Text, null, contentSize.toFixed(2))),
147
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "At end:"), /* @__PURE__ */ React3.createElement(Text, null, String(state.isAtEnd))),
148
+ /* @__PURE__ */ React3.createElement(Text, null),
149
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React3.createElement(Text, null, scrollAdjust.toFixed(2))),
150
+ /* @__PURE__ */ React3.createElement(Text, null),
151
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React3.createElement(Text, null, rawScroll.toFixed(2))),
152
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React3.createElement(Text, null, scroll.toFixed(2)))
151
153
  );
152
154
  });
153
155
  function useInterval(callback, delay) {
@@ -156,8 +158,34 @@ function useInterval(callback, delay) {
156
158
  return () => clearInterval(interval);
157
159
  }, [delay]);
158
160
  }
161
+ var LeanViewComponent = React3.forwardRef((props, ref) => {
162
+ return React3.createElement("RCTView", { ...props, ref });
163
+ });
164
+ LeanViewComponent.displayName = "RCTView";
165
+ var LeanView = Platform.OS === "android" || Platform.OS === "ios" ? LeanViewComponent : View;
166
+
167
+ // src/components/Separator.tsx
168
+ function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
169
+ const [lastItemKeys] = useArr$(["lastItemKeys"]);
170
+ const isALastItem = lastItemKeys.includes(itemKey);
171
+ return isALastItem ? null : /* @__PURE__ */ React.createElement(ItemSeparatorComponent, { leadingItem });
172
+ }
159
173
 
160
- // src/helpers.ts
174
+ // src/constants.ts
175
+ var POSITION_OUT_OF_VIEW = -1e7;
176
+ var ENABLE_DEVMODE = __DEV__ && false;
177
+ var ENABLE_DEBUG_VIEW = __DEV__ && false;
178
+ var IsNewArchitecture = global.nativeFabricUIManager != null;
179
+ var symbolFirst = Symbol();
180
+ function useInit(cb) {
181
+ const refValue = useRef(symbolFirst);
182
+ if (refValue.current === symbolFirst) {
183
+ refValue.current = cb();
184
+ }
185
+ return refValue.current;
186
+ }
187
+
188
+ // src/utils/helpers.ts
161
189
  function isFunction(obj) {
162
190
  return typeof obj === "function";
163
191
  }
@@ -171,12 +199,12 @@ function warnDevOnce(id, text) {
171
199
  console.warn(`[legend-list] ${text}`);
172
200
  }
173
201
  }
202
+ function roundSize(size) {
203
+ return Math.floor(size * 8) / 8;
204
+ }
174
205
  function isNullOrUndefined(value) {
175
206
  return value === null || value === void 0;
176
207
  }
177
- function comparatorByDistance(a, b) {
178
- return b.distance - a.distance;
179
- }
180
208
  function comparatorDefault(a, b) {
181
209
  return a - b;
182
210
  }
@@ -187,16 +215,8 @@ function getPadding(s, type) {
187
215
  function extractPadding(style, contentContainerStyle, type) {
188
216
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
189
217
  }
190
- var symbolFirst = Symbol();
191
- function useInit(cb) {
192
- const refValue = useRef(symbolFirst);
193
- if (refValue.current === symbolFirst) {
194
- refValue.current = cb();
195
- }
196
- return refValue.current;
197
- }
198
218
 
199
- // src/ContextContainer.ts
219
+ // src/state/ContextContainer.ts
200
220
  var ContextContainer = createContext(null);
201
221
  function useViewability(callback, configId) {
202
222
  const ctx = useStateContext();
@@ -240,7 +260,7 @@ function useRecyclingEffect(effect) {
240
260
  prevItem: void 0
241
261
  });
242
262
  useEffect(() => {
243
- let ret = void 0;
263
+ let ret;
244
264
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
245
265
  ret = effect({
246
266
  index,
@@ -254,7 +274,7 @@ function useRecyclingEffect(effect) {
254
274
  prevItem: value
255
275
  };
256
276
  return ret;
257
- }, [index, value]);
277
+ }, [index, value, effect]);
258
278
  }
259
279
  function useRecyclingState(valueOrFun) {
260
280
  const { index, value, itemKey, triggerLayout } = useContext(ContextContainer);
@@ -263,9 +283,10 @@ function useRecyclingState(valueOrFun) {
263
283
  value: null
264
284
  });
265
285
  const [_, setRenderNum] = useState(0);
266
- if (refState.current.itemKey !== itemKey) {
267
- refState.current.itemKey = itemKey;
268
- refState.current.value = isFunction(valueOrFun) ? valueOrFun({
286
+ const state = refState.current;
287
+ if (state.itemKey !== itemKey) {
288
+ state.itemKey = itemKey;
289
+ state.value = isFunction(valueOrFun) ? valueOrFun({
269
290
  index,
270
291
  item: value,
271
292
  prevIndex: void 0,
@@ -274,13 +295,13 @@ function useRecyclingState(valueOrFun) {
274
295
  }
275
296
  const setState = useCallback(
276
297
  (newState) => {
277
- refState.current.value = isFunction(newState) ? newState(refState.current.value) : newState;
298
+ state.value = isFunction(newState) ? newState(state.value) : newState;
278
299
  setRenderNum((v) => v + 1);
279
300
  triggerLayout();
280
301
  },
281
- [triggerLayout]
302
+ [triggerLayout, state]
282
303
  );
283
- return [refState.current.value, setState];
304
+ return [state.value, setState];
284
305
  }
285
306
  function useIsLastItem() {
286
307
  const { itemKey } = useContext(ContextContainer);
@@ -291,36 +312,26 @@ function useListScrollSize() {
291
312
  const [scrollSize] = useArr$(["scrollSize"]);
292
313
  return scrollSize;
293
314
  }
294
- var LeanViewComponent = React2.forwardRef((props, ref) => {
295
- return React2.createElement("RCTView", { ...props, ref });
296
- });
297
- LeanViewComponent.displayName = "RCTView";
298
- var LeanView = Platform.OS === "android" || Platform.OS === "ios" ? LeanViewComponent : View;
299
-
300
- // src/constants.ts
301
- var POSITION_OUT_OF_VIEW = -1e7;
302
- var ENABLE_DEVMODE = __DEV__ && false;
303
- var ENABLE_DEBUG_VIEW = __DEV__ && false;
304
- var IsNewArchitecture = global.nativeFabricUIManager != null;
315
+ var typedForwardRef = forwardRef;
316
+ var typedMemo = memo;
305
317
 
306
- // src/Container.tsx
307
- var Container = ({
318
+ // src/components/Container.tsx
319
+ var Container = typedMemo(function Container2({
308
320
  id,
309
321
  recycleItems,
310
322
  horizontal,
311
- getRenderedItem,
312
- updateItemSize,
323
+ getRenderedItem: getRenderedItem2,
324
+ updateItemSize: updateItemSize2,
313
325
  ItemSeparatorComponent
314
- }) => {
326
+ }) {
315
327
  const ctx = useStateContext();
316
328
  const columnWrapperStyle = ctx.columnWrapperStyle;
317
- const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, lastItemKeys, extraData] = useArr$([
329
+ const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, extraData] = useArr$([
318
330
  `containerColumn${id}`,
319
331
  `containerItemData${id}`,
320
332
  `containerItemKey${id}`,
321
333
  `containerPosition${id}`,
322
334
  "numColumns",
323
- "lastItemKeys",
324
335
  "extraData"
325
336
  ]);
326
337
  const refLastSize = useRef();
@@ -328,49 +339,53 @@ var Container = ({
328
339
  const [layoutRenderCount, forceLayoutRender] = useState(0);
329
340
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
330
341
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
331
- const isALastItem = lastItemKeys.includes(itemKey);
332
342
  let didLayout = false;
333
343
  let paddingStyles;
334
344
  if (columnWrapperStyle) {
335
345
  const { columnGap, rowGap, gap } = columnWrapperStyle;
336
346
  if (horizontal) {
337
347
  paddingStyles = {
338
- paddingRight: !isALastItem ? columnGap || gap || void 0 : void 0,
348
+ paddingRight: columnGap || gap || void 0,
339
349
  paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
340
350
  };
341
351
  } else {
342
352
  paddingStyles = {
343
- paddingBottom: !isALastItem ? rowGap || gap || void 0 : void 0,
353
+ paddingBottom: rowGap || gap || void 0,
344
354
  paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
345
355
  };
346
356
  }
347
357
  }
348
358
  const style = horizontal ? {
349
359
  flexDirection: ItemSeparatorComponent ? "row" : void 0,
350
- position: "absolute",
351
- top: otherAxisPos,
352
360
  height: otherAxisSize,
353
361
  left: position,
362
+ position: "absolute",
363
+ top: otherAxisPos,
354
364
  ...paddingStyles || {}
355
365
  } : {
356
- position: "absolute",
357
366
  left: otherAxisPos,
367
+ position: "absolute",
358
368
  right: numColumns > 1 ? null : 0,
359
- width: otherAxisSize,
360
369
  top: position,
370
+ width: otherAxisSize,
361
371
  ...paddingStyles || {}
362
372
  };
363
373
  const renderedItemInfo = useMemo(
364
- () => itemKey !== void 0 ? getRenderedItem(itemKey) : null,
374
+ () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
365
375
  [itemKey, data, extraData]
366
376
  );
367
377
  const { index, renderedItem } = renderedItemInfo || {};
368
- const triggerLayout = useCallback(() => {
369
- forceLayoutRender((v) => v + 1);
370
- }, []);
371
378
  const contextValue = useMemo(() => {
372
379
  ctx.viewRefs.set(id, ref);
373
- return { containerId: id, itemKey, index, value: data, triggerLayout };
380
+ return {
381
+ containerId: id,
382
+ index,
383
+ itemKey,
384
+ triggerLayout: () => {
385
+ forceLayoutRender((v) => v + 1);
386
+ },
387
+ value: data
388
+ };
374
389
  }, [id, itemKey, index, data]);
375
390
  const onLayout = (event) => {
376
391
  var _a, _b;
@@ -379,14 +394,14 @@ var Container = ({
379
394
  let layout = event.nativeEvent.layout;
380
395
  const size = layout[horizontal ? "width" : "height"];
381
396
  const doUpdate = () => {
382
- refLastSize.current = { width: layout.width, height: layout.height };
383
- updateItemSize(itemKey, layout);
397
+ refLastSize.current = { height: layout.height, width: layout.width };
398
+ updateItemSize2(itemKey, layout);
384
399
  };
385
400
  if (IsNewArchitecture || size > 0) {
386
401
  doUpdate();
387
402
  } else {
388
- (_b = (_a = ref.current) == null ? void 0 : _a.measure) == null ? void 0 : _b.call(_a, (x, y, width, height) => {
389
- layout = { width, height };
403
+ (_b = (_a = ref.current) == null ? void 0 : _a.measure) == null ? void 0 : _b.call(_a, (_x, _y, width, height) => {
404
+ layout = { height, width };
390
405
  doUpdate();
391
406
  });
392
407
  }
@@ -400,17 +415,17 @@ var Container = ({
400
415
  if (measured) {
401
416
  const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
402
417
  if (size) {
403
- updateItemSize(itemKey, measured);
418
+ updateItemSize2(itemKey, measured);
404
419
  }
405
420
  }
406
421
  }
407
- }, [itemKey, layoutRenderCount, isALastItem]);
422
+ }, [itemKey, layoutRenderCount]);
408
423
  } else {
409
424
  useEffect(() => {
410
425
  if (!isNullOrUndefined(itemKey)) {
411
426
  const timeout = setTimeout(() => {
412
427
  if (!didLayout && refLastSize.current) {
413
- updateItemSize(itemKey, refLastSize.current);
428
+ updateItemSize2(itemKey, refLastSize.current);
414
429
  }
415
430
  }, 16);
416
431
  return () => {
@@ -419,23 +434,28 @@ var Container = ({
419
434
  }
420
435
  }, [itemKey]);
421
436
  }
422
- return /* @__PURE__ */ React2.createElement(LeanView, { style, onLayout, ref, key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React2.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && !isALastItem && /* @__PURE__ */ React2.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
423
- };
424
- var typedForwardRef = forwardRef;
425
- var typedMemo = memo;
437
+ return /* @__PURE__ */ React3.createElement(LeanView, { key: recycleItems ? void 0 : itemKey, onLayout, ref, style }, /* @__PURE__ */ React3.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3.createElement(
438
+ Separator,
439
+ {
440
+ ItemSeparatorComponent,
441
+ itemKey,
442
+ leadingItem: renderedItemInfo.item
443
+ }
444
+ )));
445
+ });
426
446
  var useAnimatedValue = (initialValue) => {
427
447
  return useRef(new Animated.Value(initialValue)).current;
428
448
  };
429
449
 
430
- // src/useValue$.ts
450
+ // src/hooks/useValue$.ts
431
451
  function useValue$(key, params) {
432
452
  var _a;
433
453
  const { getValue, delay } = params || {};
434
454
  const ctx = useStateContext();
435
455
  const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
436
456
  useMemo(() => {
437
- let newValue = void 0;
438
- let prevValue = void 0;
457
+ let newValue;
458
+ let prevValue;
439
459
  let didQueueTask = false;
440
460
  listen$(ctx, key, (v) => {
441
461
  newValue = getValue ? getValue(v) : v;
@@ -464,14 +484,14 @@ function useValue$(key, params) {
464
484
  return animValue;
465
485
  }
466
486
 
467
- // src/Containers.tsx
487
+ // src/components/Containers.tsx
468
488
  var Containers = typedMemo(function Containers2({
469
489
  horizontal,
470
490
  recycleItems,
471
491
  ItemSeparatorComponent,
472
492
  waitForInitialLayout,
473
- updateItemSize,
474
- getRenderedItem
493
+ updateItemSize: updateItemSize2,
494
+ getRenderedItem: getRenderedItem2
475
495
  }) {
476
496
  const ctx = useStateContext();
477
497
  const columnWrapperStyle = ctx.columnWrapperStyle;
@@ -485,54 +505,66 @@ var Containers = typedMemo(function Containers2({
485
505
  const containers = [];
486
506
  for (let i = 0; i < numContainers; i++) {
487
507
  containers.push(
488
- /* @__PURE__ */ React2.createElement(
508
+ /* @__PURE__ */ React3.createElement(
489
509
  Container,
490
510
  {
511
+ getRenderedItem: getRenderedItem2,
512
+ horizontal,
513
+ ItemSeparatorComponent,
491
514
  id: i,
492
515
  key: i,
493
516
  recycleItems,
494
- horizontal,
495
- getRenderedItem,
496
- updateItemSize,
497
- ItemSeparatorComponent
517
+ updateItemSize: updateItemSize2
498
518
  }
499
519
  )
500
520
  );
501
521
  }
502
- const style = horizontal ? { width: animSize, opacity: animOpacity, minHeight: otherAxisSize } : { height: animSize, opacity: animOpacity, minWidth: otherAxisSize };
522
+ const style = horizontal ? { minHeight: otherAxisSize, opacity: animOpacity, width: animSize } : { height: animSize, minWidth: otherAxisSize, opacity: animOpacity };
503
523
  if (columnWrapperStyle && numColumns > 1) {
504
524
  const { columnGap, rowGap, gap } = columnWrapperStyle;
525
+ const gapX = columnGap || gap || 0;
526
+ const gapY = rowGap || gap || 0;
505
527
  if (horizontal) {
506
- const my = (rowGap || gap || 0) / 2;
507
- if (my) {
508
- style.marginVertical = -my;
528
+ if (gapY) {
529
+ style.marginVertical = -gapY / 2;
530
+ }
531
+ if (gapX) {
532
+ style.marginRight = -gapX;
509
533
  }
510
534
  } else {
511
- const mx = (columnGap || gap || 0) / 2;
512
- if (mx) {
513
- style.marginHorizontal = -mx;
535
+ if (gapX) {
536
+ style.marginHorizontal = -gapX;
537
+ }
538
+ if (gapY) {
539
+ style.marginBottom = -gapY;
514
540
  }
515
541
  }
516
542
  }
517
- return /* @__PURE__ */ React2.createElement(Animated.View, { style }, containers);
543
+ return /* @__PURE__ */ React3.createElement(Animated.View, { style }, containers);
518
544
  });
519
545
  function ScrollAdjust() {
520
546
  const bias = 1e7;
521
547
  const [scrollAdjust, scrollAdjustUserOffset] = useArr$(["scrollAdjust", "scrollAdjustUserOffset"]);
522
548
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0) + bias;
523
- return /* @__PURE__ */ React2.createElement(
549
+ return /* @__PURE__ */ React3.createElement(
524
550
  View,
525
551
  {
526
552
  style: {
527
- position: "absolute",
528
553
  height: 0,
529
- width: 0,
554
+ left: 0,
555
+ position: "absolute",
530
556
  top: scrollOffset,
531
- left: 0
557
+ width: 0
532
558
  }
533
559
  }
534
560
  );
535
561
  }
562
+
563
+ // src/components/SnapWrapper.tsx
564
+ function SnapWrapper({ ScrollComponent, ...props }) {
565
+ const [snapToOffsets] = useArr$(["snapToOffsets"]);
566
+ return /* @__PURE__ */ React.createElement(ScrollComponent, { ...props, snapToOffsets });
567
+ }
536
568
  function useSyncLayout({
537
569
  onChange
538
570
  }) {
@@ -543,42 +575,44 @@ function useSyncLayout({
543
575
  },
544
576
  [onChange]
545
577
  );
546
- useLayoutEffect(() => {
547
- if (ref.current) {
548
- ref.current.measure((x, y, width, height) => {
549
- onChange({ x, y, width, height }, true);
550
- });
551
- }
552
- }, []);
578
+ if (IsNewArchitecture) {
579
+ useLayoutEffect(() => {
580
+ if (ref.current) {
581
+ ref.current.measure((x, y, width, height) => {
582
+ onChange({ height, width, x, y }, true);
583
+ });
584
+ }
585
+ }, []);
586
+ }
553
587
  return { onLayout, ref };
554
588
  }
555
589
 
556
- // src/ListComponent.tsx
590
+ // src/components/ListComponent.tsx
557
591
  var getComponent = (Component) => {
558
- if (React2.isValidElement(Component)) {
592
+ if (React3.isValidElement(Component)) {
559
593
  return Component;
560
594
  }
561
595
  if (Component) {
562
- return /* @__PURE__ */ React2.createElement(Component, null);
596
+ return /* @__PURE__ */ React3.createElement(Component, null);
563
597
  }
564
598
  return null;
565
599
  };
566
600
  var Padding = () => {
567
601
  const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
568
- return /* @__PURE__ */ React2.createElement(Animated.View, { style: { paddingTop: animPaddingTop } });
602
+ return /* @__PURE__ */ React3.createElement(Animated.View, { style: { paddingTop: animPaddingTop } });
569
603
  };
570
604
  var PaddingDevMode = () => {
571
605
  const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
572
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React2.createElement(
606
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React3.createElement(
573
607
  Animated.View,
574
608
  {
575
609
  style: {
576
- position: "absolute",
577
- top: 0,
610
+ backgroundColor: "green",
578
611
  height: animPaddingTop,
579
612
  left: 0,
613
+ position: "absolute",
580
614
  right: 0,
581
- backgroundColor: "green"
615
+ top: 0
582
616
  }
583
617
  }
584
618
  ));
@@ -593,20 +627,21 @@ var ListComponent = typedMemo(function ListComponent2({
593
627
  ItemSeparatorComponent,
594
628
  alignItemsAtEnd,
595
629
  waitForInitialLayout,
596
- handleScroll,
630
+ onScroll: onScroll2,
597
631
  onLayout,
598
632
  ListHeaderComponent,
599
633
  ListHeaderComponentStyle,
600
634
  ListFooterComponent,
601
635
  ListFooterComponentStyle,
602
636
  ListEmptyComponent,
603
- getRenderedItem,
604
- updateItemSize,
637
+ getRenderedItem: getRenderedItem2,
638
+ updateItemSize: updateItemSize2,
605
639
  refScrollView,
606
640
  maintainVisibleContentPosition,
607
641
  renderScrollComponent,
608
642
  scrollAdjustHandler,
609
643
  onLayoutHeader,
644
+ snapToIndices,
610
645
  ...rest
611
646
  }) {
612
647
  const ctx = useStateContext();
@@ -614,156 +649,486 @@ var ListComponent = typedMemo(function ListComponent2({
614
649
  onChange: onLayoutHeader
615
650
  });
616
651
  const ScrollComponent = renderScrollComponent ? useMemo(
617
- () => React2.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
652
+ () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
618
653
  [renderScrollComponent]
619
654
  ) : ScrollView;
620
- React2.useEffect(() => {
655
+ React3.useEffect(() => {
621
656
  if (canRender) {
622
657
  setTimeout(() => {
623
658
  scrollAdjustHandler.setMounted();
624
659
  }, 0);
625
660
  }
626
661
  }, [canRender]);
627
- return /* @__PURE__ */ React2.createElement(
628
- ScrollComponent,
662
+ const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
663
+ return /* @__PURE__ */ React3.createElement(
664
+ SnapOrScroll,
629
665
  {
630
666
  ...rest,
631
- style,
632
- maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
633
667
  contentContainerStyle: [
634
668
  contentContainerStyle,
635
669
  horizontal ? {
636
670
  height: "100%"
637
671
  } : {}
638
672
  ],
639
- onScroll: handleScroll,
640
- onLayout,
641
- horizontal,
642
673
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
643
- ref: refScrollView
674
+ horizontal,
675
+ maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
676
+ onLayout,
677
+ onScroll: onScroll2,
678
+ ref: refScrollView,
679
+ ScrollComponent: snapToIndices ? ScrollComponent : void 0,
680
+ style
644
681
  },
645
- maintainVisibleContentPosition && /* @__PURE__ */ React2.createElement(ScrollAdjust, null),
646
- ENABLE_DEVMODE ? /* @__PURE__ */ React2.createElement(PaddingDevMode, null) : /* @__PURE__ */ React2.createElement(Padding, null),
647
- ListHeaderComponent && /* @__PURE__ */ React2.createElement(View, { style: ListHeaderComponentStyle, onLayout: onLayoutHeaderSync, ref: refHeader }, getComponent(ListHeaderComponent)),
682
+ maintainVisibleContentPosition && /* @__PURE__ */ React3.createElement(ScrollAdjust, null),
683
+ ENABLE_DEVMODE ? /* @__PURE__ */ React3.createElement(PaddingDevMode, null) : /* @__PURE__ */ React3.createElement(Padding, null),
684
+ ListHeaderComponent && /* @__PURE__ */ React3.createElement(View, { onLayout: onLayoutHeaderSync, ref: refHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
648
685
  ListEmptyComponent && getComponent(ListEmptyComponent),
649
- canRender && /* @__PURE__ */ React2.createElement(
686
+ canRender && /* @__PURE__ */ React3.createElement(
650
687
  Containers,
651
688
  {
689
+ getRenderedItem: getRenderedItem2,
652
690
  horizontal,
653
- recycleItems,
654
- waitForInitialLayout,
655
- getRenderedItem,
656
691
  ItemSeparatorComponent,
657
- updateItemSize
692
+ recycleItems,
693
+ updateItemSize: updateItemSize2,
694
+ waitForInitialLayout
658
695
  }
659
696
  ),
660
- ListFooterComponent && /* @__PURE__ */ React2.createElement(
697
+ ListFooterComponent && /* @__PURE__ */ React3.createElement(
661
698
  View,
662
699
  {
663
- style: ListFooterComponentStyle,
664
700
  onLayout: (event) => {
665
701
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
666
702
  set$(ctx, "footerSize", size);
667
- }
703
+ },
704
+ style: ListFooterComponentStyle
668
705
  },
669
706
  getComponent(ListFooterComponent)
670
707
  )
671
708
  );
672
709
  });
673
710
 
674
- // src/ScrollAdjustHandler.ts
675
- var ScrollAdjustHandler = class {
676
- constructor(ctx) {
677
- this.appliedAdjust = 0;
678
- this.mounted = false;
679
- this.context = ctx;
711
+ // src/utils/getId.ts
712
+ function getId(state, index) {
713
+ const { data, keyExtractor } = state.props;
714
+ if (!data) {
715
+ return "";
680
716
  }
681
- requestAdjust(add) {
682
- const oldAdjustTop = peek$(this.context, "scrollAdjust") || 0;
683
- this.appliedAdjust = add + oldAdjustTop;
684
- const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
685
- if (this.mounted) {
686
- set();
687
- } else {
688
- requestAnimationFrame(set);
717
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
718
+ const id = ret;
719
+ state.idCache.set(index, id);
720
+ return id;
721
+ }
722
+
723
+ // src/core/calculateOffsetForIndex.ts
724
+ function calculateOffsetForIndex(ctx, state, index) {
725
+ let position = 0;
726
+ if (index !== void 0) {
727
+ position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
728
+ }
729
+ const paddingTop = peek$(ctx, "stylePaddingTop");
730
+ if (paddingTop) {
731
+ position += paddingTop;
732
+ }
733
+ const headerSize = peek$(ctx, "headerSize");
734
+ if (headerSize) {
735
+ position += headerSize;
736
+ }
737
+ return position;
738
+ }
739
+
740
+ // src/utils/getItemSize.ts
741
+ function getItemSize(state, key, index, data, useAverageSize) {
742
+ const {
743
+ sizesKnown,
744
+ sizes,
745
+ scrollingTo,
746
+ props: { estimatedItemSize, getEstimatedItemSize }
747
+ } = state;
748
+ const sizeKnown = sizesKnown.get(key);
749
+ if (sizeKnown !== void 0) {
750
+ return sizeKnown;
751
+ }
752
+ let size;
753
+ if (useAverageSize !== void 0 && sizeKnown === void 0 && !getEstimatedItemSize && !scrollingTo) {
754
+ size = useAverageSize;
755
+ }
756
+ if (size === void 0) {
757
+ size = sizes.get(key);
758
+ if (size !== void 0) {
759
+ return size;
689
760
  }
690
761
  }
691
- setMounted() {
692
- this.mounted = true;
762
+ if (size === void 0) {
763
+ size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
693
764
  }
694
- };
695
- var useCombinedRef = (...refs) => {
696
- const callback = useCallback((element) => {
697
- for (const ref of refs) {
698
- if (!ref) {
699
- continue;
765
+ sizes.set(key, size);
766
+ return size;
767
+ }
768
+
769
+ // src/core/calculateOffsetWithOffsetPosition.ts
770
+ function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
771
+ const { index, viewOffset, viewPosition } = params;
772
+ let offset = offsetParam;
773
+ if (viewOffset) {
774
+ offset -= viewOffset;
775
+ }
776
+ if (viewPosition !== void 0 && index !== void 0) {
777
+ offset -= viewPosition * (state.scrollLength - getItemSize(state, getId(state, index), index, state.props.data[index]));
778
+ }
779
+ return offset;
780
+ }
781
+
782
+ // src/utils/requestAdjust.ts
783
+ function requestAdjust(ctx, state, positionDiff) {
784
+ if (Math.abs(positionDiff) > 0.1) {
785
+ const doit = () => {
786
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
787
+ };
788
+ state.scroll += positionDiff;
789
+ state.scrollForNextCalculateItemsInView = void 0;
790
+ const didLayout = peek$(ctx, "containersDidLayout");
791
+ if (didLayout) {
792
+ doit();
793
+ const threshold = state.scroll - positionDiff / 2;
794
+ if (!state.ignoreScrollFromMVCP) {
795
+ state.ignoreScrollFromMVCP = {};
700
796
  }
701
- if (isFunction(ref)) {
702
- ref(element);
797
+ if (positionDiff > 0) {
798
+ state.ignoreScrollFromMVCP.lt = threshold;
703
799
  } else {
704
- ref.current = element;
800
+ state.ignoreScrollFromMVCP.gt = threshold;
801
+ }
802
+ if (state.ignoreScrollFromMVCPTimeout) {
803
+ clearTimeout(state.ignoreScrollFromMVCPTimeout);
705
804
  }
805
+ state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
806
+ state.ignoreScrollFromMVCP = void 0;
807
+ }, 100);
808
+ } else {
809
+ requestAnimationFrame(doit);
706
810
  }
707
- }, refs);
708
- return callback;
709
- };
811
+ }
812
+ }
710
813
 
711
- // src/viewability.ts
712
- var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
713
- function setupViewability(props) {
714
- let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
715
- if (viewabilityConfig || onViewableItemsChanged) {
716
- viewabilityConfigCallbackPairs = [
717
- ...viewabilityConfigCallbackPairs || [],
718
- {
719
- viewabilityConfig: viewabilityConfig || {
720
- viewAreaCoveragePercentThreshold: 0
721
- },
722
- onViewableItemsChanged
814
+ // src/core/prepareMVCP.ts
815
+ function prepareMVCP(ctx, state) {
816
+ const {
817
+ positions,
818
+ scrollingTo,
819
+ props: { maintainVisibleContentPosition }
820
+ } = state;
821
+ let prevPosition;
822
+ let targetId;
823
+ let targetIndex;
824
+ const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
825
+ if (maintainVisibleContentPosition) {
826
+ const indexByKey = state.indexByKey;
827
+ if (scrollTarget !== void 0) {
828
+ targetId = getId(state, scrollTarget);
829
+ targetIndex = scrollTarget;
830
+ } else if (state.idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
831
+ targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
832
+ targetIndex = indexByKey.get(targetId);
833
+ }
834
+ if (targetId !== void 0 && targetIndex !== void 0) {
835
+ prevPosition = positions.get(targetId);
836
+ }
837
+ }
838
+ return () => {
839
+ if (targetId !== void 0 && prevPosition !== void 0) {
840
+ const newPosition = positions.get(targetId);
841
+ if (newPosition !== void 0) {
842
+ const positionDiff = newPosition - prevPosition;
843
+ if (Math.abs(positionDiff) > 0.1) {
844
+ requestAdjust(ctx, state, positionDiff);
845
+ }
723
846
  }
724
- ];
847
+ }
848
+ };
849
+ }
850
+
851
+ // src/utils/setPaddingTop.ts
852
+ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
853
+ if (stylePaddingTop !== void 0) {
854
+ const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
855
+ if (stylePaddingTop < prevStylePaddingTop) {
856
+ let prevTotalSize = peek$(ctx, "totalSize");
857
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
858
+ state.timeoutSetPaddingTop = setTimeout(() => {
859
+ prevTotalSize = peek$(ctx, "totalSize");
860
+ set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
861
+ }, 16);
862
+ }
863
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
725
864
  }
726
- if (viewabilityConfigCallbackPairs) {
727
- for (const pair of viewabilityConfigCallbackPairs) {
728
- mapViewabilityConfigCallbackPairs.set(pair.viewabilityConfig.id, {
729
- viewableItems: [],
730
- start: -1,
731
- end: -1,
732
- previousStart: -1,
733
- previousEnd: -1
734
- });
865
+ if (alignItemsPaddingTop !== void 0) {
866
+ set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
867
+ }
868
+ }
869
+
870
+ // src/utils/updateAlignItemsPaddingTop.ts
871
+ function updateAlignItemsPaddingTop(ctx, state) {
872
+ const {
873
+ scrollLength,
874
+ props: { alignItemsAtEnd, data }
875
+ } = state;
876
+ if (alignItemsAtEnd) {
877
+ let alignItemsPaddingTop = 0;
878
+ if ((data == null ? void 0 : data.length) > 0) {
879
+ const contentSize = getContentSize(ctx);
880
+ alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
881
+ }
882
+ setPaddingTop(ctx, state, { alignItemsPaddingTop });
883
+ }
884
+ }
885
+
886
+ // src/core/updateTotalSize.ts
887
+ function updateTotalSize(ctx, state) {
888
+ const {
889
+ positions,
890
+ props: { data }
891
+ } = state;
892
+ if (data.length === 0) {
893
+ addTotalSize(ctx, state, null, 0);
894
+ } else {
895
+ const lastId = getId(state, data.length - 1);
896
+ if (lastId !== void 0) {
897
+ const lastPosition = positions.get(lastId);
898
+ if (lastPosition !== void 0) {
899
+ const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
900
+ if (lastSize !== void 0) {
901
+ const totalSize = lastPosition + lastSize;
902
+ addTotalSize(ctx, state, null, totalSize);
903
+ }
904
+ }
735
905
  }
736
906
  }
737
- return viewabilityConfigCallbackPairs;
738
907
  }
739
- function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, getId, scrollSize, start, end) {
740
- for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
741
- const viewabilityState = mapViewabilityConfigCallbackPairs.get(
742
- viewabilityConfigCallbackPair.viewabilityConfig.id
743
- );
744
- viewabilityState.start = start;
745
- viewabilityState.end = end;
746
- if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
747
- const timer = setTimeout(() => {
748
- state.timeouts.delete(timer);
749
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
750
- }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
751
- state.timeouts.add(timer);
752
- } else {
753
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
908
+ function addTotalSize(ctx, state, key, add) {
909
+ const { alignItemsAtEnd } = state.props;
910
+ {
911
+ state.totalSize = add;
912
+ if (state.timeoutSetPaddingTop) {
913
+ clearTimeout(state.timeoutSetPaddingTop);
914
+ state.timeoutSetPaddingTop = void 0;
754
915
  }
755
916
  }
917
+ set$(ctx, "totalSize", state.totalSize);
918
+ if (alignItemsAtEnd) {
919
+ updateAlignItemsPaddingTop(ctx, state);
920
+ }
756
921
  }
757
- function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize) {
758
- const { viewabilityConfig, onViewableItemsChanged } = viewabilityConfigCallbackPair;
759
- const configId = viewabilityConfig.id;
760
- const viewabilityState = mapViewabilityConfigCallbackPairs.get(configId);
761
- const { viewableItems: previousViewableItems, start, end } = viewabilityState;
762
- const viewabilityTokens = /* @__PURE__ */ new Map();
763
- for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
764
- viewabilityTokens.set(
765
- containerId,
766
- computeViewability(
922
+
923
+ // src/utils/getScrollVelocity.ts
924
+ var getScrollVelocity = (state) => {
925
+ const { scrollHistory } = state;
926
+ let velocity = 0;
927
+ if (scrollHistory.length >= 1) {
928
+ const newest = scrollHistory[scrollHistory.length - 1];
929
+ let oldest;
930
+ let start = 0;
931
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
932
+ const entry = scrollHistory[i];
933
+ const nextEntry = scrollHistory[i + 1];
934
+ if (i > 0) {
935
+ const prevEntry = scrollHistory[i - 1];
936
+ const prevDirection = entry.scroll - prevEntry.scroll;
937
+ const currentDirection = nextEntry.scroll - entry.scroll;
938
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
939
+ start = i;
940
+ break;
941
+ }
942
+ }
943
+ }
944
+ for (let i = start; i < scrollHistory.length - 1; i++) {
945
+ const entry = scrollHistory[i];
946
+ if (newest.time - entry.time <= 1e3) {
947
+ oldest = entry;
948
+ break;
949
+ }
950
+ }
951
+ if (oldest) {
952
+ const scrollDiff = newest.scroll - oldest.scroll;
953
+ const timeDiff = newest.time - oldest.time;
954
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
955
+ }
956
+ }
957
+ return velocity;
958
+ };
959
+
960
+ // src/utils/updateSnapToOffsets.ts
961
+ function updateSnapToOffsets(ctx, state) {
962
+ const {
963
+ positions,
964
+ props: { snapToIndices }
965
+ } = state;
966
+ const snapToOffsets = Array(snapToIndices.length);
967
+ for (let i = 0; i < snapToIndices.length; i++) {
968
+ const idx = snapToIndices[i];
969
+ const key = getId(state, idx);
970
+ snapToOffsets[i] = positions.get(key);
971
+ }
972
+ set$(ctx, "snapToOffsets", snapToOffsets);
973
+ }
974
+
975
+ // src/core/updateAllPositions.ts
976
+ function updateAllPositions(ctx, state, dataChanged) {
977
+ var _a, _b, _c, _d, _e;
978
+ const {
979
+ averageSizes,
980
+ columns,
981
+ indexByKey,
982
+ positions,
983
+ firstFullyOnScreenIndex,
984
+ idCache,
985
+ sizesKnown,
986
+ props: { snapToIndices }
987
+ } = state;
988
+ const data = state.props.data;
989
+ const numColumns = peek$(ctx, "numColumns");
990
+ const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
991
+ const scrollVelocity = getScrollVelocity(state);
992
+ if (dataChanged) {
993
+ indexByKey.clear();
994
+ idCache.clear();
995
+ }
996
+ const itemType = "";
997
+ let averageSize = (_a = averageSizes[itemType]) == null ? void 0 : _a.avg;
998
+ if (averageSize !== void 0) {
999
+ averageSize = roundSize(averageSize);
1000
+ }
1001
+ const shouldUseBackwards = !dataChanged && scrollVelocity < 0 && firstFullyOnScreenIndex > 5 && firstFullyOnScreenIndex < data.length;
1002
+ if (shouldUseBackwards && firstFullyOnScreenIndex !== void 0) {
1003
+ const anchorId = getId(state, firstFullyOnScreenIndex);
1004
+ const anchorPosition = positions.get(anchorId);
1005
+ if (anchorPosition !== void 0) {
1006
+ let currentRowTop2 = anchorPosition;
1007
+ let maxSizeInRow2 = 0;
1008
+ let bailout = false;
1009
+ for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1010
+ const id = (_b = idCache.get(i)) != null ? _b : getId(state, i);
1011
+ const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(state, id, i, data[i], averageSize);
1012
+ const itemColumn = columns.get(id);
1013
+ maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1014
+ if (itemColumn === 1) {
1015
+ currentRowTop2 -= maxSizeInRow2;
1016
+ maxSizeInRow2 = 0;
1017
+ }
1018
+ if (currentRowTop2 < -2e3) {
1019
+ bailout = true;
1020
+ break;
1021
+ }
1022
+ positions.set(id, currentRowTop2);
1023
+ }
1024
+ if (!bailout) {
1025
+ updateTotalSize(ctx, state);
1026
+ return;
1027
+ }
1028
+ }
1029
+ }
1030
+ let currentRowTop = 0;
1031
+ let column = 1;
1032
+ let maxSizeInRow = 0;
1033
+ const hasColumns = numColumns > 1;
1034
+ const needsIndexByKey = dataChanged || indexByKey.size === 0;
1035
+ const dataLength = data.length;
1036
+ for (let i = 0; i < dataLength; i++) {
1037
+ const id = (_d = idCache.get(i)) != null ? _d : getId(state, i);
1038
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(state, id, i, data[i], averageSize);
1039
+ if (__DEV__ && needsIndexByKey) {
1040
+ if (indexByKeyForChecking.has(id)) {
1041
+ console.error(
1042
+ `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1043
+ );
1044
+ }
1045
+ indexByKeyForChecking.set(id, i);
1046
+ }
1047
+ positions.set(id, currentRowTop);
1048
+ if (needsIndexByKey) {
1049
+ indexByKey.set(id, i);
1050
+ }
1051
+ columns.set(id, column);
1052
+ if (hasColumns) {
1053
+ if (size > maxSizeInRow) {
1054
+ maxSizeInRow = size;
1055
+ }
1056
+ column++;
1057
+ if (column > numColumns) {
1058
+ currentRowTop += maxSizeInRow;
1059
+ column = 1;
1060
+ maxSizeInRow = 0;
1061
+ }
1062
+ } else {
1063
+ currentRowTop += size;
1064
+ }
1065
+ }
1066
+ updateTotalSize(ctx, state);
1067
+ if (snapToIndices) {
1068
+ updateSnapToOffsets(ctx, state);
1069
+ }
1070
+ }
1071
+
1072
+ // src/core/viewability.ts
1073
+ var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
1074
+ function setupViewability(props) {
1075
+ let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
1076
+ if (viewabilityConfig || onViewableItemsChanged) {
1077
+ viewabilityConfigCallbackPairs = [
1078
+ ...viewabilityConfigCallbackPairs || [],
1079
+ {
1080
+ onViewableItemsChanged,
1081
+ viewabilityConfig: viewabilityConfig || {
1082
+ viewAreaCoveragePercentThreshold: 0
1083
+ }
1084
+ }
1085
+ ];
1086
+ }
1087
+ if (viewabilityConfigCallbackPairs) {
1088
+ for (const pair of viewabilityConfigCallbackPairs) {
1089
+ mapViewabilityConfigCallbackPairs.set(pair.viewabilityConfig.id, {
1090
+ end: -1,
1091
+ previousEnd: -1,
1092
+ previousStart: -1,
1093
+ start: -1,
1094
+ viewableItems: []
1095
+ });
1096
+ }
1097
+ }
1098
+ return viewabilityConfigCallbackPairs;
1099
+ }
1100
+ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
1101
+ const {
1102
+ timeouts,
1103
+ props: { data }
1104
+ } = state;
1105
+ for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
1106
+ const viewabilityState = mapViewabilityConfigCallbackPairs.get(
1107
+ viewabilityConfigCallbackPair.viewabilityConfig.id
1108
+ );
1109
+ viewabilityState.start = start;
1110
+ viewabilityState.end = end;
1111
+ if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
1112
+ const timer = setTimeout(() => {
1113
+ timeouts.delete(timer);
1114
+ updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
1115
+ }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
1116
+ timeouts.add(timer);
1117
+ } else {
1118
+ updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
1119
+ }
1120
+ }
1121
+ }
1122
+ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize) {
1123
+ const { viewabilityConfig, onViewableItemsChanged } = viewabilityConfigCallbackPair;
1124
+ const configId = viewabilityConfig.id;
1125
+ const viewabilityState = mapViewabilityConfigCallbackPairs.get(configId);
1126
+ const { viewableItems: previousViewableItems, start, end } = viewabilityState;
1127
+ const viewabilityTokens = /* @__PURE__ */ new Map();
1128
+ for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
1129
+ viewabilityTokens.set(
1130
+ containerId,
1131
+ computeViewability(
767
1132
  state,
768
1133
  ctx,
769
1134
  viewabilityConfig,
@@ -798,15 +1163,15 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
798
1163
  for (let i = start; i <= end; i++) {
799
1164
  const item = data[i];
800
1165
  if (item) {
801
- const key = getId(i);
1166
+ const key = getId(state, i);
802
1167
  const containerId = findContainerId(ctx, key);
803
1168
  if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
804
1169
  const viewToken = {
805
- item,
806
- key,
1170
+ containerId,
807
1171
  index: i,
808
1172
  isViewable: true,
809
- containerId
1173
+ item,
1174
+ key
810
1175
  };
811
1176
  viewableItems.push(viewToken);
812
1177
  if (!(previousViewableItems == null ? void 0 : previousViewableItems.find((v) => v.key === viewToken.key))) {
@@ -816,9 +1181,9 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
816
1181
  }
817
1182
  }
818
1183
  Object.assign(viewabilityState, {
819
- viewableItems,
1184
+ previousEnd: end,
820
1185
  previousStart: start,
821
- previousEnd: end
1186
+ viewableItems
822
1187
  });
823
1188
  if (changed.length > 0) {
824
1189
  viewabilityState.viewableItems = viewableItems;
@@ -827,7 +1192,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
827
1192
  maybeUpdateViewabilityCallback(ctx, configId, change.containerId, change);
828
1193
  }
829
1194
  if (onViewableItemsChanged) {
830
- onViewableItemsChanged({ viewableItems, changed });
1195
+ onViewableItemsChanged({ changed, viewableItems });
831
1196
  }
832
1197
  }
833
1198
  for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
@@ -853,16 +1218,16 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
853
1218
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
854
1219
  const isViewable2 = percent >= viewablePercentThreshold;
855
1220
  const value = {
1221
+ containerId,
856
1222
  index,
857
1223
  isViewable: isViewable2,
858
1224
  item,
859
1225
  key,
860
- percentVisible,
861
1226
  percentOfScroller,
862
- sizeVisible,
863
- size,
1227
+ percentVisible,
864
1228
  scrollSize,
865
- containerId
1229
+ size,
1230
+ sizeVisible
866
1231
  };
867
1232
  if (JSON.stringify(value) !== JSON.stringify(ctx.mapViewabilityAmountValues.get(containerId))) {
868
1233
  ctx.mapViewabilityAmountValues.set(containerId, value);
@@ -894,427 +1259,221 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
894
1259
  cb == null ? void 0 : cb(viewToken);
895
1260
  }
896
1261
 
897
- // src/LegendList.tsx
898
- var DEFAULT_DRAW_DISTANCE = 250;
899
- var DEFAULT_ITEM_SIZE = 100;
900
- function createColumnWrapperStyle(contentContainerStyle) {
901
- const { gap, columnGap, rowGap } = contentContainerStyle;
902
- if (gap || columnGap || rowGap) {
903
- contentContainerStyle.gap = void 0;
904
- contentContainerStyle.columnGap = void 0;
905
- contentContainerStyle.rowGap = void 0;
906
- return {
907
- gap,
908
- columnGap,
909
- rowGap
910
- };
1262
+ // src/utils/checkAllSizesKnown.ts
1263
+ function checkAllSizesKnown(state) {
1264
+ const { startBuffered, endBuffered, sizesKnown } = state;
1265
+ if (endBuffered !== null) {
1266
+ let areAllKnown = true;
1267
+ for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1268
+ const key = getId(state, i);
1269
+ areAllKnown && (areAllKnown = sizesKnown.has(key));
1270
+ }
1271
+ return areAllKnown;
911
1272
  }
1273
+ return false;
912
1274
  }
913
- var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
914
- return /* @__PURE__ */ React2.createElement(StateProvider, null, /* @__PURE__ */ React2.createElement(LegendListInner, { ...props, ref: forwardedRef }));
915
- });
916
- var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
917
- var _a;
918
- const {
919
- data: dataProp = [],
920
- initialScrollIndex: initialScrollIndexProp,
921
- initialScrollOffset,
922
- horizontal,
923
- drawDistance = 250,
924
- recycleItems = false,
925
- onEndReachedThreshold = 0.5,
926
- onStartReachedThreshold = 0.5,
927
- maintainScrollAtEnd = false,
928
- maintainScrollAtEndThreshold = 0.1,
929
- alignItemsAtEnd = false,
930
- maintainVisibleContentPosition = false,
931
- onScroll: onScrollProp,
932
- onMomentumScrollEnd,
933
- numColumns: numColumnsProp = 1,
934
- columnWrapperStyle,
935
- keyExtractor: keyExtractorProp,
936
- renderItem: renderItem2,
937
- estimatedListSize,
938
- estimatedItemSize: estimatedItemSizeProp,
939
- getEstimatedItemSize,
940
- suggestEstimatedItemSize,
941
- ListHeaderComponent,
942
- ListEmptyComponent,
943
- onItemSizeChanged,
944
- refScrollView,
945
- waitForInitialLayout = true,
946
- extraData,
947
- contentContainerStyle: contentContainerStyleProp,
948
- style: styleProp,
949
- onLayout: onLayoutProp,
950
- onRefresh,
951
- refreshing,
952
- progressViewOffset,
953
- refreshControl,
954
- initialContainerPoolRatio = 2,
955
- viewabilityConfig,
956
- viewabilityConfigCallbackPairs,
957
- onViewableItemsChanged,
958
- ...rest
959
- } = props;
960
- const [renderNum, setRenderNum] = useState(0);
961
- const initialScroll = typeof initialScrollIndexProp === "number" ? { index: initialScrollIndexProp } : initialScrollIndexProp;
962
- const initialScrollIndex = initialScroll == null ? void 0 : initialScroll.index;
963
- const refLoadStartTime = useRef(Date.now());
964
- const [canRender, setCanRender] = React2.useState(!IsNewArchitecture);
965
- const callbacks = useRef({
966
- onStartReached: rest.onStartReached,
967
- onEndReached: rest.onEndReached
968
- });
969
- callbacks.current.onStartReached = rest.onStartReached;
970
- callbacks.current.onEndReached = rest.onEndReached;
971
- const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
972
- const style = { ...StyleSheet.flatten(styleProp) };
973
- const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
974
- const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
975
- const ctx = useStateContext();
976
- ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
977
- const refScroller = useRef(null);
978
- const combinedRef = useCombinedRef(refScroller, refScrollView);
979
- const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
980
- const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
981
- const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
982
- const refState = useRef();
983
- const getId = (index) => {
984
- const state = refState.current;
985
- if (!(state == null ? void 0 : state.data)) {
986
- return "";
987
- }
988
- const data = state.data;
989
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
990
- const id = ret;
991
- state.idCache.set(index, id);
992
- return id;
993
- };
994
- const getItemSize = (key, index, data, useAverageSize = false) => {
995
- const state = refState.current;
996
- const sizeKnown = state.sizesKnown.get(key);
997
- if (sizeKnown !== void 0) {
998
- return sizeKnown;
999
- }
1000
- const sizePrevious = state.sizes.get(key);
1001
- if (sizePrevious !== void 0) {
1002
- return sizePrevious;
1003
- }
1004
- const size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
1005
- state.sizes.set(key, size);
1006
- return size;
1007
- };
1008
- const calculateOffsetForIndex = (index) => {
1009
- var _a2;
1010
- let position = 0;
1011
- if (index !== void 0) {
1012
- position = ((_a2 = refState.current) == null ? void 0 : _a2.positions.get(getId(index))) || 0;
1013
- }
1014
- const paddingTop = peek$(ctx, "stylePaddingTop");
1015
- if (paddingTop) {
1016
- position += paddingTop;
1017
- }
1018
- const headerSize = peek$(ctx, "headerSize");
1019
- if (headerSize) {
1020
- position += headerSize;
1021
- }
1022
- return position;
1023
- };
1024
- const calculateOffsetWithOffsetPosition = (offsetParam, params) => {
1025
- const { index, viewOffset, viewPosition } = params;
1026
- let offset = offsetParam;
1027
- const state = refState.current;
1028
- if (viewOffset) {
1029
- offset -= viewOffset;
1275
+
1276
+ // src/utils/findAvailableContainers.ts
1277
+ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval) {
1278
+ const numContainers = peek$(ctx, "numContainers");
1279
+ const result = [];
1280
+ const availableContainers = [];
1281
+ for (let u = 0; u < numContainers; u++) {
1282
+ const key = peek$(ctx, `containerItemKey${u}`);
1283
+ let isOk = key === void 0;
1284
+ if (!isOk) {
1285
+ const index = pendingRemoval.indexOf(u);
1286
+ if (index !== -1) {
1287
+ pendingRemoval.splice(index, 1);
1288
+ isOk = true;
1289
+ }
1030
1290
  }
1031
- if (viewPosition !== void 0 && index !== void 0) {
1032
- offset -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1291
+ if (isOk) {
1292
+ result.push(u);
1293
+ if (result.length >= numNeeded) {
1294
+ return result;
1295
+ }
1033
1296
  }
1034
- return offset;
1035
- };
1036
- if (!refState.current) {
1037
- const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { width: 0, height: 0 } : Dimensions.get("window"))[horizontal ? "width" : "height"];
1038
- refState.current = {
1039
- sizes: /* @__PURE__ */ new Map(),
1040
- positions: /* @__PURE__ */ new Map(),
1041
- columns: /* @__PURE__ */ new Map(),
1042
- pendingAdjust: 0,
1043
- isStartReached: false,
1044
- isEndReached: false,
1045
- isAtEnd: false,
1046
- isAtStart: false,
1047
- data: dataProp,
1048
- scrollLength: initialScrollLength,
1049
- startBuffered: -1,
1050
- startNoBuffer: -1,
1051
- endBuffered: -1,
1052
- endNoBuffer: -1,
1053
- firstFullyOnScreenIndex: -1,
1054
- scroll: 0,
1055
- totalSize: 0,
1056
- timeouts: /* @__PURE__ */ new Set(),
1057
- viewabilityConfigCallbackPairs: void 0,
1058
- renderItem: void 0,
1059
- scrollAdjustHandler: new ScrollAdjustHandler(ctx),
1060
- nativeMarginTop: 0,
1061
- scrollPrev: 0,
1062
- scrollPrevTime: 0,
1063
- scrollTime: 0,
1064
- scrollPending: 0,
1065
- indexByKey: /* @__PURE__ */ new Map(),
1066
- scrollHistory: [],
1067
- sizesKnown: /* @__PURE__ */ new Map(),
1068
- timeoutSizeMessage: 0,
1069
- startReachedBlockedByTimer: false,
1070
- endReachedBlockedByTimer: false,
1071
- scrollForNextCalculateItemsInView: void 0,
1072
- enableScrollForNextCalculateItemsInView: true,
1073
- minIndexSizeChanged: 0,
1074
- queuedCalculateItemsInView: 0,
1075
- lastBatchingAction: Date.now(),
1076
- averageSizes: {},
1077
- onScroll: onScrollProp,
1078
- idsInView: [],
1079
- containerItemKeys: /* @__PURE__ */ new Set(),
1080
- idCache: /* @__PURE__ */ new Map()
1081
- };
1082
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
1083
- set$(ctx, "extraData", extraData);
1084
1297
  }
1085
- const didDataChange = refState.current.data !== dataProp;
1086
- refState.current.data = dataProp;
1087
- refState.current.onScroll = onScrollProp;
1088
- const getScrollVelocity = () => {
1089
- const { scrollHistory } = refState.current;
1090
- let velocity = 0;
1091
- if (scrollHistory.length >= 1) {
1092
- const newest = scrollHistory[scrollHistory.length - 1];
1093
- let oldest;
1094
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1095
- const entry = scrollHistory[i];
1096
- const nextEntry = scrollHistory[i + 1];
1097
- if (i > 0) {
1098
- const prevEntry = scrollHistory[i - 1];
1099
- const prevDirection = entry.scroll - prevEntry.scroll;
1100
- const currentDirection = nextEntry.scroll - entry.scroll;
1101
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1102
- break;
1103
- }
1104
- }
1105
- }
1106
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1107
- const entry = scrollHistory[i];
1108
- if (newest.time - entry.time <= 1e3) {
1109
- oldest = entry;
1110
- break;
1111
- }
1112
- }
1113
- if (oldest) {
1114
- const scrollDiff = newest.scroll - oldest.scroll;
1115
- const timeDiff = newest.time - oldest.time;
1116
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1117
- }
1298
+ for (let u = 0; u < numContainers; u++) {
1299
+ const key = peek$(ctx, `containerItemKey${u}`);
1300
+ if (key === void 0) continue;
1301
+ const index = state.indexByKey.get(key);
1302
+ if (index < startBuffered) {
1303
+ availableContainers.push({ distance: startBuffered - index, index: u });
1304
+ } else if (index > endBuffered) {
1305
+ availableContainers.push({ distance: index - endBuffered, index: u });
1118
1306
  }
1119
- return velocity;
1120
- };
1121
- const updateAllPositions = (dataChanged) => {
1122
- var _a2, _b, _c;
1123
- const { columns, data, indexByKey, positions, firstFullyOnScreenIndex, idCache, sizes } = refState.current;
1124
- const numColumns = (_a2 = peek$(ctx, "numColumns")) != null ? _a2 : numColumnsProp;
1125
- const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1126
- const scrollVelocity = getScrollVelocity();
1127
- if (dataChanged) {
1128
- indexByKey.clear();
1129
- idCache.clear();
1130
- }
1131
- const shouldUseBackwards = !dataChanged && scrollVelocity < 0 && firstFullyOnScreenIndex > 5 && firstFullyOnScreenIndex < data.length;
1132
- if (shouldUseBackwards && firstFullyOnScreenIndex !== void 0) {
1133
- const anchorId = getId(firstFullyOnScreenIndex);
1134
- const anchorPosition = positions.get(anchorId);
1135
- if (anchorPosition !== void 0) {
1136
- let currentRowTop2 = anchorPosition;
1137
- let maxSizeInRow2 = 0;
1138
- let bailout = false;
1139
- for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1140
- const id = getId(i);
1141
- const size = getItemSize(id, i, data[i], false);
1142
- const itemColumn = columns.get(id);
1143
- maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1144
- if (itemColumn === 1) {
1145
- currentRowTop2 -= maxSizeInRow2;
1146
- maxSizeInRow2 = 0;
1147
- }
1148
- if (currentRowTop2 < -2e3) {
1149
- bailout = true;
1150
- break;
1307
+ }
1308
+ const remaining = numNeeded - result.length;
1309
+ if (remaining > 0) {
1310
+ if (availableContainers.length > 0) {
1311
+ if (availableContainers.length > remaining) {
1312
+ availableContainers.sort(comparatorByDistance);
1313
+ availableContainers.length = remaining;
1314
+ }
1315
+ for (const container of availableContainers) {
1316
+ result.push(container.index);
1317
+ }
1318
+ }
1319
+ const stillNeeded = numNeeded - result.length;
1320
+ if (stillNeeded > 0) {
1321
+ for (let i = 0; i < stillNeeded; i++) {
1322
+ result.push(numContainers + i);
1323
+ }
1324
+ if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1325
+ console.warn(
1326
+ "[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.",
1327
+ {
1328
+ debugInfo: {
1329
+ numContainers,
1330
+ numContainersPooled: peek$(ctx, "numContainersPooled"),
1331
+ numNeeded,
1332
+ stillNeeded
1333
+ }
1151
1334
  }
1152
- positions.set(id, currentRowTop2);
1153
- }
1154
- if (!bailout) {
1155
- updateTotalSize();
1156
- return;
1157
- }
1158
- }
1159
- }
1160
- let currentRowTop = 0;
1161
- let column = 1;
1162
- let maxSizeInRow = 0;
1163
- const hasColumns = numColumns > 1;
1164
- const needsIndexByKey = dataChanged || indexByKey.size === 0;
1165
- const dataLength = data.length;
1166
- for (let i = 0; i < dataLength; i++) {
1167
- const id = (_b = idCache.get(i)) != null ? _b : getId(i);
1168
- const size = (_c = sizes.get(id)) != null ? _c : getItemSize(id, i, data[i], false);
1169
- if (__DEV__ && needsIndexByKey) {
1170
- if (indexByKeyForChecking.has(id)) {
1171
- console.error(
1172
- `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1173
- );
1174
- }
1175
- indexByKeyForChecking.set(id, i);
1176
- }
1177
- positions.set(id, currentRowTop);
1178
- if (needsIndexByKey) {
1179
- indexByKey.set(id, i);
1180
- }
1181
- columns.set(id, column);
1182
- if (hasColumns) {
1183
- if (size > maxSizeInRow) {
1184
- maxSizeInRow = size;
1185
- }
1186
- column++;
1187
- if (column > numColumns) {
1188
- currentRowTop += maxSizeInRow;
1189
- column = 1;
1190
- maxSizeInRow = 0;
1191
- }
1192
- } else {
1193
- currentRowTop += size;
1335
+ );
1194
1336
  }
1195
1337
  }
1196
- updateTotalSize();
1197
- };
1198
- const scrollToIndex = ({
1338
+ }
1339
+ return result.sort(comparatorDefault);
1340
+ }
1341
+ function comparatorByDistance(a, b) {
1342
+ return b.distance - a.distance;
1343
+ }
1344
+
1345
+ // src/core/finishScrollTo.ts
1346
+ var finishScrollTo = (state) => {
1347
+ if (state) {
1348
+ state.scrollingTo = void 0;
1349
+ state.scrollHistory.length = 0;
1350
+ }
1351
+ };
1352
+
1353
+ // src/core/scrollTo.ts
1354
+ function scrollTo(state, params = {}) {
1355
+ var _a;
1356
+ const { animated } = params;
1357
+ const {
1358
+ refScroller,
1359
+ props: { horizontal }
1360
+ } = state;
1361
+ const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1362
+ state.scrollHistory.length = 0;
1363
+ state.scrollingTo = params;
1364
+ state.scrollPending = offset;
1365
+ (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1366
+ animated: !!animated,
1367
+ x: horizontal ? offset : 0,
1368
+ y: horizontal ? 0 : offset
1369
+ });
1370
+ if (!animated) {
1371
+ state.scroll = offset;
1372
+ setTimeout(() => finishScrollTo(state), 100);
1373
+ }
1374
+ }
1375
+
1376
+ // src/core/scrollToIndex.ts
1377
+ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1378
+ if (index >= state.props.data.length) {
1379
+ index = state.props.data.length - 1;
1380
+ } else if (index < 0) {
1381
+ index = 0;
1382
+ }
1383
+ const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
1384
+ const isLast = index === state.props.data.length - 1;
1385
+ if (isLast && viewPosition === void 0) {
1386
+ viewPosition = 1;
1387
+ }
1388
+ const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1389
+ state.scrollForNextCalculateItemsInView = void 0;
1390
+ scrollTo(state, {
1391
+ animated,
1199
1392
  index,
1200
- viewOffset = 0,
1201
- animated = true,
1202
- viewPosition
1203
- }) => {
1204
- const state = refState.current;
1205
- if (index >= state.data.length) {
1206
- index = state.data.length - 1;
1207
- } else if (index < 0) {
1208
- index = 0;
1209
- }
1210
- const firstIndexOffset = calculateOffsetForIndex(index);
1211
- const isLast = index === state.data.length - 1;
1212
- if (isLast && viewPosition === void 0) {
1213
- viewPosition = 1;
1214
- }
1215
- const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1216
- state.scrollForNextCalculateItemsInView = void 0;
1217
- scrollTo({ offset: firstIndexScrollPostion, animated, index, viewPosition: viewPosition != null ? viewPosition : 0, viewOffset });
1218
- };
1219
- const setDidLayout = () => {
1220
- refState.current.queuedInitialLayout = true;
1221
- checkAtBottom();
1222
- set$(ctx, "containersDidLayout", true);
1223
- if (props.onLoad) {
1224
- props.onLoad({ elapsedTimeInMs: Date.now() - refLoadStartTime.current });
1225
- }
1226
- };
1227
- const addTotalSize = useCallback((key, add) => {
1228
- const state = refState.current;
1229
- if (key === null) {
1230
- state.totalSize = add;
1231
- } else {
1232
- state.totalSize += add;
1233
- }
1234
- set$(ctx, "totalSize", state.totalSize);
1235
- if (alignItemsAtEnd) {
1236
- updateAlignItemsPaddingTop();
1237
- }
1238
- }, []);
1239
- const checkAllSizesKnown = useCallback(() => {
1240
- const { startBuffered, endBuffered, sizesKnown } = refState.current;
1241
- if (endBuffered !== null) {
1242
- let areAllKnown = true;
1243
- for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1244
- const key = getId(i);
1245
- areAllKnown && (areAllKnown = sizesKnown.has(key));
1246
- }
1247
- return areAllKnown;
1248
- }
1249
- return false;
1250
- }, []);
1251
- const requestAdjust = (positionDiff) => {
1252
- if (Math.abs(positionDiff) > 0.1) {
1253
- const state = refState.current;
1254
- const doit = () => {
1255
- state.scrollAdjustHandler.requestAdjust(positionDiff);
1256
- };
1257
- state.scroll += positionDiff;
1258
- state.scrollForNextCalculateItemsInView = void 0;
1259
- if (peek$(ctx, "containersDidLayout")) {
1260
- doit();
1261
- } else {
1262
- requestAnimationFrame(doit);
1263
- }
1264
- const threshold = state.scroll - positionDiff / 2;
1265
- if (!state.ignoreScrollFromMVCP) {
1266
- state.ignoreScrollFromMVCP = {};
1267
- }
1268
- if (positionDiff > 0) {
1269
- state.ignoreScrollFromMVCP.lt = threshold;
1270
- } else {
1271
- state.ignoreScrollFromMVCP.gt = threshold;
1272
- }
1273
- if (state.ignoreScrollFromMVCPTimeout) {
1274
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1275
- }
1276
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
1277
- state.ignoreScrollFromMVCP = void 0;
1278
- }, 100);
1393
+ offset: firstIndexScrollPostion,
1394
+ viewOffset,
1395
+ viewPosition: viewPosition != null ? viewPosition : 0
1396
+ });
1397
+ }
1398
+
1399
+ // src/utils/checkThreshold.ts
1400
+ var checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1401
+ const distanceAbs = Math.abs(distance);
1402
+ const isAtThreshold = atThreshold || distanceAbs < threshold;
1403
+ if (!isReached && !isBlockedByTimer) {
1404
+ if (isAtThreshold) {
1405
+ onReached == null ? void 0 : onReached(distance);
1406
+ blockTimer == null ? void 0 : blockTimer(true);
1407
+ setTimeout(() => {
1408
+ blockTimer == null ? void 0 : blockTimer(false);
1409
+ }, 700);
1410
+ return true;
1279
1411
  }
1280
- };
1281
- const prepareMVCP = useCallback(() => {
1282
- const state = refState.current;
1283
- const { positions, scrollingTo } = state;
1284
- let prevPosition;
1285
- let targetId;
1286
- let targetIndex;
1287
- const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1288
- if (maintainVisibleContentPosition) {
1289
- const indexByKey = state.indexByKey;
1290
- if (scrollTarget !== void 0) {
1291
- targetId = getId(scrollTarget);
1292
- targetIndex = scrollTarget;
1293
- } else if (state.idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1294
- targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
1295
- targetIndex = indexByKey.get(targetId);
1296
- }
1297
- if (targetId !== void 0 && targetIndex !== void 0) {
1298
- prevPosition = positions.get(targetId);
1299
- }
1412
+ } else {
1413
+ if (distance >= 1.3 * threshold) {
1414
+ return false;
1300
1415
  }
1301
- return () => {
1302
- if (targetId !== void 0 && prevPosition !== void 0) {
1303
- const newPosition = positions.get(targetId);
1304
- if (newPosition !== void 0) {
1305
- const positionDiff = newPosition - prevPosition;
1306
- if (Math.abs(positionDiff) > 0.1) {
1307
- requestAdjust(positionDiff);
1308
- }
1309
- }
1416
+ }
1417
+ return isReached;
1418
+ };
1419
+
1420
+ // src/utils/checkAtBottom.ts
1421
+ function checkAtBottom(ctx, state) {
1422
+ if (!state) {
1423
+ return;
1424
+ }
1425
+ const {
1426
+ queuedInitialLayout,
1427
+ scrollLength,
1428
+ scroll,
1429
+ maintainingScrollAtEnd,
1430
+ props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1431
+ } = state;
1432
+ const contentSize = getContentSize(ctx);
1433
+ if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1434
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1435
+ const isContentLess = contentSize < scrollLength;
1436
+ state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1437
+ state.isEndReached = checkThreshold(
1438
+ distanceFromEnd,
1439
+ isContentLess,
1440
+ onEndReachedThreshold * scrollLength,
1441
+ state.isEndReached,
1442
+ state.endReachedBlockedByTimer,
1443
+ (distance) => {
1444
+ var _a, _b;
1445
+ return (_b = (_a = state.props).onEndReached) == null ? void 0 : _b.call(_a, { distanceFromEnd: distance });
1446
+ },
1447
+ (block) => {
1448
+ state.endReachedBlockedByTimer = block;
1310
1449
  }
1311
- };
1312
- }, []);
1313
- const calculateItemsInView = useCallback((params = {}) => {
1314
- var _a2, _b, _c, _d, _e, _f, _g, _h;
1315
- const state = refState.current;
1450
+ );
1451
+ }
1452
+ }
1453
+
1454
+ // src/utils/setDidLayout.ts
1455
+ function setDidLayout(ctx, state) {
1456
+ const {
1457
+ loadStartTime,
1458
+ initialScroll,
1459
+ props: { onLoad }
1460
+ } = state;
1461
+ state.queuedInitialLayout = true;
1462
+ checkAtBottom(ctx, state);
1463
+ if (!IsNewArchitecture && initialScroll) {
1464
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1465
+ }
1466
+ set$(ctx, "containersDidLayout", true);
1467
+ if (onLoad) {
1468
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1469
+ }
1470
+ }
1471
+
1472
+ // src/core/calculateItemsInView.ts
1473
+ function calculateItemsInView(ctx, state, params = {}) {
1474
+ unstable_batchedUpdates(() => {
1475
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1316
1476
  const {
1317
- data,
1318
1477
  scrollLength,
1319
1478
  startBufferedId: startBufferedIdOrig,
1320
1479
  positions,
@@ -1327,7 +1486,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1327
1486
  enableScrollForNextCalculateItemsInView,
1328
1487
  minIndexSizeChanged
1329
1488
  } = state;
1330
- if (!data || scrollLength === 0) {
1489
+ const data = state.props.data;
1490
+ const prevNumContainers = peek$(ctx, "numContainers");
1491
+ if (!data || scrollLength === 0 || !prevNumContainers) {
1331
1492
  return;
1332
1493
  }
1333
1494
  const totalSize = peek$(ctx, "totalSize");
@@ -1335,19 +1496,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1335
1496
  const numColumns = peek$(ctx, "numColumns");
1336
1497
  const previousScrollAdjust = 0;
1337
1498
  const { dataChanged, doMVCP } = params;
1338
- const speed = getScrollVelocity();
1499
+ const speed = getScrollVelocity(state);
1339
1500
  if (doMVCP || dataChanged) {
1340
- const checkMVCP = doMVCP ? prepareMVCP() : void 0;
1341
- updateAllPositions(dataChanged);
1501
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, state) : void 0;
1502
+ updateAllPositions(ctx, state, dataChanged);
1342
1503
  checkMVCP == null ? void 0 : checkMVCP();
1343
1504
  }
1344
1505
  const scrollExtra = 0;
1345
- const useAverageSize = false;
1346
1506
  const { queuedInitialLayout } = state;
1347
1507
  let { scroll: scrollState } = state;
1508
+ const initialScroll = state.props.initialScroll;
1348
1509
  if (!queuedInitialLayout && initialScroll) {
1349
1510
  const updatedOffset = calculateOffsetWithOffsetPosition(
1350
- calculateOffsetForIndex(initialScroll.index),
1511
+ state,
1512
+ calculateOffsetForIndex(ctx, state, initialScroll.index),
1351
1513
  initialScroll
1352
1514
  );
1353
1515
  scrollState = updatedOffset;
@@ -1361,6 +1523,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1361
1523
  set$(ctx, "debugRawScroll", scrollState);
1362
1524
  set$(ctx, "debugComputedScroll", scroll);
1363
1525
  }
1526
+ const scrollBuffer = state.props.scrollBuffer;
1364
1527
  let scrollBufferTop = scrollBuffer;
1365
1528
  let scrollBufferBottom = scrollBuffer;
1366
1529
  if (speed > 0) {
@@ -1390,9 +1553,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1390
1553
  state.minIndexSizeChanged = void 0;
1391
1554
  }
1392
1555
  for (let i = loopStart; i >= 0; i--) {
1393
- const id = (_a2 = idCache.get(i)) != null ? _a2 : getId(i);
1556
+ const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1394
1557
  const top = positions.get(id);
1395
- const size = (_b = sizes.get(id)) != null ? _b : getItemSize(id, i, data[i], useAverageSize);
1558
+ const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
1396
1559
  const bottom = top + size;
1397
1560
  if (bottom > scroll - scrollBuffer) {
1398
1561
  loopStart = i;
@@ -1407,7 +1570,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1407
1570
  let foundEnd = false;
1408
1571
  let nextTop;
1409
1572
  let nextBottom;
1410
- const prevNumContainers = ctx.values.get("numContainers");
1411
1573
  let maxIndexRendered = 0;
1412
1574
  for (let i = 0; i < prevNumContainers; i++) {
1413
1575
  const key = peek$(ctx, `containerItemKey${i}`);
@@ -1419,8 +1581,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1419
1581
  let firstFullyOnScreenIndex;
1420
1582
  const dataLength = data.length;
1421
1583
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
1422
- const id = (_c = idCache.get(i)) != null ? _c : getId(i);
1423
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(id, i, data[i], useAverageSize);
1584
+ const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
1585
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
1424
1586
  const top = positions.get(id);
1425
1587
  if (!foundEnd) {
1426
1588
  if (startNoBuffer === null && top + size > scroll) {
@@ -1449,22 +1611,22 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1449
1611
  }
1450
1612
  const idsInView = [];
1451
1613
  for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
1452
- const id = (_e = idCache.get(i)) != null ? _e : getId(i);
1614
+ const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
1453
1615
  idsInView.push(id);
1454
1616
  }
1455
1617
  Object.assign(state, {
1456
- startBuffered,
1457
- startBufferedId,
1458
- startNoBuffer,
1459
1618
  endBuffered,
1460
1619
  endNoBuffer,
1620
+ firstFullyOnScreenIndex,
1461
1621
  idsInView,
1462
- firstFullyOnScreenIndex
1622
+ startBuffered,
1623
+ startBufferedId,
1624
+ startNoBuffer
1463
1625
  });
1464
1626
  if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
1465
1627
  state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
1466
- top: nextTop,
1467
- bottom: nextBottom
1628
+ bottom: nextBottom,
1629
+ top: nextTop
1468
1630
  } : void 0;
1469
1631
  }
1470
1632
  const numContainers = peek$(ctx, "numContainers");
@@ -1472,7 +1634,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1472
1634
  if (dataChanged) {
1473
1635
  for (let i = 0; i < numContainers; i++) {
1474
1636
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1475
- if (!keyExtractorProp || itemKey && indexByKey.get(itemKey) === void 0) {
1637
+ if (!state.props.keyExtractor || itemKey && indexByKey.get(itemKey) === void 0) {
1476
1638
  pendingRemoval.push(i);
1477
1639
  }
1478
1640
  }
@@ -1481,13 +1643,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1481
1643
  let numContainers2 = prevNumContainers;
1482
1644
  const needNewContainers = [];
1483
1645
  for (let i = startBuffered; i <= endBuffered; i++) {
1484
- const id = (_f = idCache.get(i)) != null ? _f : getId(i);
1646
+ const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
1485
1647
  if (!containerItemKeys.has(id)) {
1486
1648
  needNewContainers.push(i);
1487
1649
  }
1488
1650
  }
1489
1651
  if (needNewContainers.length > 0) {
1490
1652
  const availableContainers = findAvailableContainers(
1653
+ ctx,
1654
+ state,
1491
1655
  needNewContainers.length,
1492
1656
  startBuffered,
1493
1657
  endBuffered,
@@ -1496,7 +1660,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1496
1660
  for (let idx = 0; idx < needNewContainers.length; idx++) {
1497
1661
  const i = needNewContainers[idx];
1498
1662
  const containerIndex = availableContainers[idx];
1499
- const id = (_g = idCache.get(i)) != null ? _g : getId(i);
1663
+ const id = (_g = idCache.get(i)) != null ? _g : getId(state, i);
1500
1664
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
1501
1665
  if (oldKey && oldKey !== id) {
1502
1666
  containerItemKeys.delete(oldKey);
@@ -1515,334 +1679,629 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1515
1679
  }
1516
1680
  }
1517
1681
  }
1518
- for (let i = 0; i < numContainers2; i++) {
1519
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1520
- if (pendingRemoval.includes(i)) {
1521
- if (itemKey) {
1522
- containerItemKeys.delete(itemKey);
1523
- }
1524
- set$(ctx, `containerItemKey${i}`, void 0);
1525
- set$(ctx, `containerItemData${i}`, void 0);
1526
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1527
- set$(ctx, `containerColumn${i}`, -1);
1528
- } else {
1529
- const itemIndex = indexByKey.get(itemKey);
1530
- const item = data[itemIndex];
1531
- if (item !== void 0) {
1532
- const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(itemIndex);
1533
- const position = positions.get(id);
1534
- if (position === void 0) {
1535
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1536
- } else {
1537
- const pos = positions.get(id);
1538
- const column = columns.get(id) || 1;
1539
- const prevPos = peek$(ctx, `containerPosition${i}`);
1540
- const prevColumn = peek$(ctx, `containerColumn${i}`);
1541
- const prevData = peek$(ctx, `containerItemData${i}`);
1542
- if (!prevPos || pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
1543
- set$(ctx, `containerPosition${i}`, pos);
1544
- }
1545
- if (column >= 0 && column !== prevColumn) {
1546
- set$(ctx, `containerColumn${i}`, column);
1547
- }
1548
- if (prevData !== item) {
1549
- set$(ctx, `containerItemData${i}`, data[itemIndex]);
1550
- }
1682
+ }
1683
+ for (let i = 0; i < numContainers; i++) {
1684
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
1685
+ if (pendingRemoval.includes(i)) {
1686
+ if (itemKey) {
1687
+ containerItemKeys.delete(itemKey);
1688
+ }
1689
+ set$(ctx, `containerItemKey${i}`, void 0);
1690
+ set$(ctx, `containerItemData${i}`, void 0);
1691
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1692
+ set$(ctx, `containerColumn${i}`, -1);
1693
+ } else {
1694
+ const itemIndex = indexByKey.get(itemKey);
1695
+ const item = data[itemIndex];
1696
+ if (item !== void 0) {
1697
+ const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
1698
+ const position = positions.get(id);
1699
+ if (position === void 0) {
1700
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1701
+ } else {
1702
+ const column = columns.get(id) || 1;
1703
+ const prevPos = peek$(ctx, `containerPosition${i}`);
1704
+ const prevColumn = peek$(ctx, `containerColumn${i}`);
1705
+ const prevData = peek$(ctx, `containerItemData${i}`);
1706
+ if (position > POSITION_OUT_OF_VIEW && position !== prevPos) {
1707
+ set$(ctx, `containerPosition${i}`, position);
1708
+ }
1709
+ if (column >= 0 && column !== prevColumn) {
1710
+ set$(ctx, `containerColumn${i}`, column);
1711
+ }
1712
+ if (prevData !== item) {
1713
+ set$(ctx, `containerItemData${i}`, data[itemIndex]);
1551
1714
  }
1552
1715
  }
1553
1716
  }
1554
1717
  }
1555
1718
  }
1556
1719
  if (!queuedInitialLayout && endBuffered !== null) {
1557
- if (checkAllSizesKnown()) {
1558
- setDidLayout();
1720
+ if (checkAllSizesKnown(state)) {
1721
+ setDidLayout(ctx, state);
1559
1722
  }
1560
1723
  }
1561
- if (viewabilityConfigCallbackPairs) {
1724
+ if (state.viewabilityConfigCallbackPairs) {
1562
1725
  updateViewableItems(
1563
1726
  state,
1564
1727
  ctx,
1565
- viewabilityConfigCallbackPairs,
1566
- getId,
1728
+ state.viewabilityConfigCallbackPairs,
1567
1729
  scrollLength,
1568
1730
  startNoBuffer,
1569
1731
  endNoBuffer
1570
1732
  );
1571
1733
  }
1572
- }, []);
1573
- const setPaddingTop = ({
1574
- stylePaddingTop,
1575
- alignItemsPaddingTop
1576
- }) => {
1577
- if (stylePaddingTop !== void 0) {
1578
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1579
- if (stylePaddingTop < prevStylePaddingTop) {
1580
- const prevTotalSize = peek$(ctx, "totalSize") || 0;
1581
- set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1582
- setTimeout(() => {
1583
- set$(ctx, "totalSize", prevTotalSize);
1584
- }, 16);
1734
+ });
1735
+ }
1736
+
1737
+ // src/core/doInitialAllocateContainers.ts
1738
+ function doInitialAllocateContainers(ctx, state) {
1739
+ const { scrollLength } = state;
1740
+ const data = state.props.data;
1741
+ if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1742
+ const averageItemSize = state.props.getEstimatedItemSize ? state.props.getEstimatedItemSize(0, data[0]) : state.props.estimatedItemSize;
1743
+ const Extra = 1.5;
1744
+ const numContainers = Math.ceil(
1745
+ (scrollLength + state.props.scrollBuffer * 2) / averageItemSize * state.props.numColumns * Extra
1746
+ );
1747
+ for (let i = 0; i < numContainers; i++) {
1748
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1749
+ set$(ctx, `containerColumn${i}`, -1);
1750
+ }
1751
+ set$(ctx, "numContainers", numContainers);
1752
+ set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
1753
+ if (!IsNewArchitecture) {
1754
+ if (state.props.initialScroll) {
1755
+ requestAnimationFrame(() => {
1756
+ calculateItemsInView(ctx, state);
1757
+ });
1758
+ } else {
1759
+ calculateItemsInView(ctx, state);
1585
1760
  }
1586
- set$(ctx, "stylePaddingTop", stylePaddingTop);
1587
1761
  }
1588
- if (alignItemsPaddingTop !== void 0) {
1589
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1590
- }
1591
- };
1592
- const updateAlignItemsPaddingTop = () => {
1593
- if (alignItemsAtEnd) {
1594
- const { data, scrollLength } = refState.current;
1595
- let alignItemsPaddingTop = 0;
1596
- if ((data == null ? void 0 : data.length) > 0) {
1597
- const contentSize = getContentSize(ctx);
1598
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1599
- }
1600
- setPaddingTop({ alignItemsPaddingTop });
1762
+ return true;
1763
+ }
1764
+ }
1765
+
1766
+ // src/core/doMaintainScrollAtEnd.ts
1767
+ function doMaintainScrollAtEnd(ctx, state, animated) {
1768
+ const {
1769
+ refScroller,
1770
+ props: { maintainScrollAtEnd }
1771
+ } = state;
1772
+ if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1773
+ const paddingTop = peek$(ctx, "alignItemsPaddingTop");
1774
+ if (paddingTop > 0) {
1775
+ state.scroll = 0;
1776
+ }
1777
+ requestAnimationFrame(() => {
1778
+ var _a;
1779
+ state.maintainingScrollAtEnd = true;
1780
+ (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
1781
+ animated
1782
+ });
1783
+ setTimeout(
1784
+ () => {
1785
+ state.maintainingScrollAtEnd = false;
1786
+ },
1787
+ 0
1788
+ );
1789
+ });
1790
+ return true;
1791
+ }
1792
+ }
1793
+
1794
+ // src/utils/checkAtTop.ts
1795
+ function checkAtTop(state) {
1796
+ if (!state) {
1797
+ return;
1798
+ }
1799
+ const {
1800
+ scrollLength,
1801
+ scroll,
1802
+ props: { onStartReachedThreshold }
1803
+ } = state;
1804
+ const distanceFromTop = scroll;
1805
+ state.isAtStart = distanceFromTop <= 0;
1806
+ state.isStartReached = checkThreshold(
1807
+ distanceFromTop,
1808
+ false,
1809
+ onStartReachedThreshold * scrollLength,
1810
+ state.isStartReached,
1811
+ state.startReachedBlockedByTimer,
1812
+ (distance) => {
1813
+ var _a, _b;
1814
+ return (_b = (_a = state.props).onStartReached) == null ? void 0 : _b.call(_a, { distanceFromStart: distance });
1815
+ },
1816
+ (block) => {
1817
+ state.startReachedBlockedByTimer = block;
1601
1818
  }
1602
- };
1603
- const finishScrollTo = () => {
1604
- const state = refState.current;
1605
- if (state) {
1606
- state.scrollingTo = void 0;
1607
- state.scrollHistory.length = 0;
1819
+ );
1820
+ }
1821
+
1822
+ // src/core/handleLayout.ts
1823
+ function handleLayout(ctx, state, layout, setCanRender) {
1824
+ const { maintainScrollAtEnd } = state.props;
1825
+ const scrollLength = layout[state.props.horizontal ? "width" : "height"];
1826
+ const otherAxisSize = layout[state.props.horizontal ? "height" : "width"];
1827
+ const needsCalculate = !state.lastLayout || scrollLength > state.scrollLength || state.lastLayout.x !== layout.x || state.lastLayout.y !== layout.y;
1828
+ state.lastLayout = layout;
1829
+ const didChange = scrollLength !== state.scrollLength;
1830
+ const prevOtherAxisSize = state.otherAxisSize;
1831
+ state.scrollLength = scrollLength;
1832
+ state.otherAxisSize = otherAxisSize;
1833
+ state.lastBatchingAction = Date.now();
1834
+ state.scrollForNextCalculateItemsInView = void 0;
1835
+ doInitialAllocateContainers(ctx, state);
1836
+ if (needsCalculate) {
1837
+ calculateItemsInView(ctx, state, { doMVCP: true });
1838
+ }
1839
+ if (didChange || otherAxisSize !== prevOtherAxisSize) {
1840
+ set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
1841
+ }
1842
+ if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
1843
+ doMaintainScrollAtEnd(ctx, state, false);
1844
+ }
1845
+ updateAlignItemsPaddingTop(ctx, state);
1846
+ checkAtBottom(ctx, state);
1847
+ checkAtTop(state);
1848
+ if (state) {
1849
+ state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
1850
+ }
1851
+ if (__DEV__ && scrollLength === 0) {
1852
+ warnDevOnce(
1853
+ "height0",
1854
+ `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.`
1855
+ );
1856
+ }
1857
+ setCanRender(true);
1858
+ }
1859
+
1860
+ // src/core/onScroll.ts
1861
+ function onScroll(ctx, state, event) {
1862
+ var _a, _b, _c, _d, _e;
1863
+ if (((_b = (_a = event.nativeEvent) == null ? void 0 : _a.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
1864
+ return;
1865
+ }
1866
+ const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
1867
+ const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
1868
+ if (ignoreScrollFromMVCP && !state.scrollingTo) {
1869
+ const { lt, gt } = ignoreScrollFromMVCP;
1870
+ if (lt && newScroll < lt || gt && newScroll > gt) {
1871
+ return;
1608
1872
  }
1609
- };
1610
- const scrollTo = (params = {}) => {
1611
- var _a2;
1612
- const state = refState.current;
1613
- const { animated } = params;
1614
- const offset = calculateOffsetWithOffsetPosition(params.offset, params);
1615
- state.scrollHistory.length = 0;
1616
- state.scrollingTo = params;
1617
- state.scrollPending = offset;
1618
- (_a2 = refScroller.current) == null ? void 0 : _a2.scrollTo({
1619
- x: horizontal ? offset : 0,
1620
- y: horizontal ? 0 : offset,
1621
- animated: !!animated
1622
- });
1623
- if (!animated) {
1624
- refState.current.scroll = offset;
1625
- setTimeout(finishScrollTo, 100);
1873
+ }
1874
+ state.scrollPending = newScroll;
1875
+ updateScroll(ctx, state, newScroll);
1876
+ (_e = (_d = state.props).onScroll) == null ? void 0 : _e.call(_d, event);
1877
+ }
1878
+ function updateScroll(ctx, state, newScroll) {
1879
+ const scrollingTo = state.scrollingTo;
1880
+ state.hasScrolled = true;
1881
+ state.lastBatchingAction = Date.now();
1882
+ const currentTime = performance.now();
1883
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1884
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1885
+ }
1886
+ if (state.scrollHistory.length > 5) {
1887
+ state.scrollHistory.shift();
1888
+ }
1889
+ state.scrollPrev = state.scroll;
1890
+ state.scrollPrevTime = state.scrollTime;
1891
+ state.scroll = newScroll;
1892
+ state.scrollTime = currentTime;
1893
+ calculateItemsInView(ctx, state);
1894
+ checkAtBottom(ctx, state);
1895
+ checkAtTop(state);
1896
+ }
1897
+
1898
+ // src/core/ScrollAdjustHandler.ts
1899
+ var ScrollAdjustHandler = class {
1900
+ constructor(ctx) {
1901
+ this.appliedAdjust = 0;
1902
+ this.mounted = false;
1903
+ this.context = ctx;
1904
+ }
1905
+ requestAdjust(add) {
1906
+ const oldAdjustTop = peek$(this.context, "scrollAdjust") || 0;
1907
+ this.appliedAdjust = add + oldAdjustTop;
1908
+ const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
1909
+ if (this.mounted) {
1910
+ set();
1911
+ } else {
1912
+ requestAnimationFrame(set);
1626
1913
  }
1627
- };
1628
- const doMaintainScrollAtEnd = (animated) => {
1629
- const state = refState.current;
1630
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1631
- const paddingTop = peek$(ctx, "alignItemsPaddingTop");
1632
- if (paddingTop > 0) {
1633
- state.scroll = 0;
1914
+ }
1915
+ setMounted() {
1916
+ this.mounted = true;
1917
+ }
1918
+ };
1919
+
1920
+ // src/core/updateItemSize.ts
1921
+ function updateItemSizes(ctx, state, itemUpdates) {
1922
+ var _a;
1923
+ const {
1924
+ props: {
1925
+ horizontal,
1926
+ maintainVisibleContentPosition,
1927
+ suggestEstimatedItemSize,
1928
+ onItemSizeChanged,
1929
+ data,
1930
+ maintainScrollAtEnd
1931
+ }
1932
+ } = state;
1933
+ if (!data) return;
1934
+ const containersDidLayout = peek$(ctx, "containersDidLayout");
1935
+ let needsRecalculate = !containersDidLayout;
1936
+ let shouldMaintainScrollAtEnd = false;
1937
+ let minIndexSizeChanged;
1938
+ let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
1939
+ for (const { itemKey, sizeObj } of itemUpdates) {
1940
+ const index = state.indexByKey.get(itemKey);
1941
+ const prevSizeKnown = state.sizesKnown.get(itemKey);
1942
+ const diff = updateOneItemSize(state, itemKey, sizeObj);
1943
+ const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
1944
+ if (diff !== 0) {
1945
+ minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
1946
+ if (((_a = state.scrollingTo) == null ? void 0 : _a.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index && diff > 0) {
1947
+ requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
1948
+ }
1949
+ const { startBuffered, endBuffered } = state;
1950
+ needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
1951
+ if (!needsRecalculate) {
1952
+ const numContainers = ctx.values.get("numContainers");
1953
+ for (let i = 0; i < numContainers; i++) {
1954
+ if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
1955
+ needsRecalculate = true;
1956
+ break;
1957
+ }
1958
+ }
1634
1959
  }
1635
- requestAnimationFrame(() => {
1636
- var _a2;
1637
- state.maintainingScrollAtEnd = true;
1638
- (_a2 = refScroller.current) == null ? void 0 : _a2.scrollToEnd({
1639
- animated
1640
- });
1641
- setTimeout(
1642
- () => {
1643
- state.maintainingScrollAtEnd = false;
1644
- },
1645
- 0
1646
- );
1647
- });
1648
- return true;
1649
- }
1650
- };
1651
- const checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1652
- const distanceAbs = Math.abs(distance);
1653
- const isAtThreshold = atThreshold || distanceAbs < threshold;
1654
- if (!isReached && !isBlockedByTimer) {
1655
- if (isAtThreshold) {
1656
- onReached == null ? void 0 : onReached(distance);
1657
- blockTimer == null ? void 0 : blockTimer(true);
1658
- setTimeout(() => {
1659
- blockTimer == null ? void 0 : blockTimer(false);
1660
- }, 700);
1661
- return true;
1960
+ if (state.needsOtherAxisSize) {
1961
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
1962
+ maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
1662
1963
  }
1663
- } else {
1664
- if (distance >= 1.3 * threshold) {
1665
- return false;
1964
+ if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
1965
+ shouldMaintainScrollAtEnd = true;
1666
1966
  }
1967
+ onItemSizeChanged == null ? void 0 : onItemSizeChanged({
1968
+ index,
1969
+ itemData: state.props.data[index],
1970
+ itemKey,
1971
+ previous: size - diff,
1972
+ size
1973
+ });
1667
1974
  }
1668
- return isReached;
1669
- };
1670
- const checkAtBottom = () => {
1671
- if (!refState.current) {
1672
- return;
1673
- }
1674
- const { queuedInitialLayout, scrollLength, scroll, maintainingScrollAtEnd } = refState.current;
1675
- const contentSize = getContentSize(ctx);
1676
- if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1677
- const distanceFromEnd = contentSize - scroll - scrollLength;
1678
- const isContentLess = contentSize < scrollLength;
1679
- refState.current.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1680
- refState.current.isEndReached = checkThreshold(
1681
- distanceFromEnd,
1682
- isContentLess,
1683
- onEndReachedThreshold * scrollLength,
1684
- refState.current.isEndReached,
1685
- refState.current.endReachedBlockedByTimer,
1686
- (distance) => {
1687
- var _a2, _b;
1688
- return (_b = (_a2 = callbacks.current).onEndReached) == null ? void 0 : _b.call(_a2, { distanceFromEnd: distance });
1689
- },
1690
- (block) => {
1691
- refState.current.endReachedBlockedByTimer = block;
1692
- }
1975
+ }
1976
+ if (minIndexSizeChanged !== void 0) {
1977
+ state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
1978
+ }
1979
+ if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
1980
+ if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
1981
+ state.timeoutSizeMessage = setTimeout(() => {
1982
+ var _a2;
1983
+ state.timeoutSizeMessage = void 0;
1984
+ const num = state.sizesKnown.size;
1985
+ const avg = (_a2 = state.averageSizes[""]) == null ? void 0 : _a2.avg;
1986
+ console.warn(
1987
+ `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
1693
1988
  );
1989
+ }, 1e3);
1990
+ }
1991
+ const cur = peek$(ctx, "otherAxisSize");
1992
+ if (!cur || maxOtherAxisSize > cur) {
1993
+ set$(ctx, "otherAxisSize", maxOtherAxisSize);
1994
+ }
1995
+ if (containersDidLayout || checkAllSizesKnown(state)) {
1996
+ if (needsRecalculate) {
1997
+ state.scrollForNextCalculateItemsInView = void 0;
1998
+ calculateItemsInView(ctx, state, { doMVCP: true });
1694
1999
  }
1695
- };
1696
- const checkAtTop = () => {
1697
- if (!refState.current) {
1698
- return;
2000
+ if (shouldMaintainScrollAtEnd) {
2001
+ if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2002
+ doMaintainScrollAtEnd(ctx, state, false);
2003
+ }
1699
2004
  }
1700
- const { scrollLength, scroll } = refState.current;
1701
- const distanceFromTop = scroll;
1702
- refState.current.isAtStart = distanceFromTop <= 0;
1703
- refState.current.isStartReached = checkThreshold(
1704
- distanceFromTop,
1705
- false,
1706
- onStartReachedThreshold * scrollLength,
1707
- refState.current.isStartReached,
1708
- refState.current.startReachedBlockedByTimer,
1709
- (distance) => {
1710
- var _a2, _b;
1711
- return (_b = (_a2 = callbacks.current).onStartReached) == null ? void 0 : _b.call(_a2, { distanceFromStart: distance });
1712
- },
1713
- (block) => {
1714
- refState.current.startReachedBlockedByTimer = block;
2005
+ }
2006
+ }
2007
+ function updateItemSize(ctx, state, itemKey, sizeObj) {
2008
+ const { queuedItemSizeUpdates, queuedItemSizeUpdatesWaiting } = state;
2009
+ const containersDidLayout = peek$(ctx, "containersDidLayout");
2010
+ if (!containersDidLayout || !queuedItemSizeUpdatesWaiting) {
2011
+ updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
2012
+ if (containersDidLayout) {
2013
+ state.queuedItemSizeUpdatesWaiting = true;
2014
+ requestAnimationFrame(() => {
2015
+ state.queuedItemSizeUpdatesWaiting = false;
2016
+ updateItemSizes(ctx, state, queuedItemSizeUpdates);
2017
+ queuedItemSizeUpdates.length = 0;
2018
+ });
2019
+ }
2020
+ } else {
2021
+ queuedItemSizeUpdates.push({ itemKey, sizeObj });
2022
+ }
2023
+ }
2024
+ function updateOneItemSize(state, itemKey, sizeObj) {
2025
+ const {
2026
+ sizes,
2027
+ indexByKey,
2028
+ sizesKnown,
2029
+ averageSizes,
2030
+ props: { data, horizontal }
2031
+ } = state;
2032
+ if (!data) return 0;
2033
+ const index = indexByKey.get(itemKey);
2034
+ const prevSize = getItemSize(state, itemKey, index, data);
2035
+ const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2036
+ sizesKnown.set(itemKey, size);
2037
+ const itemType = "";
2038
+ let averages = averageSizes[itemType];
2039
+ if (!averages) {
2040
+ averages = averageSizes[itemType] = { avg: 0, num: 0 };
2041
+ }
2042
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2043
+ averages.num++;
2044
+ if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2045
+ sizes.set(itemKey, size);
2046
+ return size - prevSize;
2047
+ }
2048
+ return 0;
2049
+ }
2050
+ var useCombinedRef = (...refs) => {
2051
+ const callback = useCallback((element) => {
2052
+ for (const ref of refs) {
2053
+ if (!ref) {
2054
+ continue;
1715
2055
  }
1716
- );
2056
+ if (isFunction(ref)) {
2057
+ ref(element);
2058
+ } else {
2059
+ ref.current = element;
2060
+ }
2061
+ }
2062
+ }, refs);
2063
+ return callback;
2064
+ };
2065
+
2066
+ // src/utils/createColumnWrapperStyle.ts
2067
+ function createColumnWrapperStyle(contentContainerStyle) {
2068
+ const { gap, columnGap, rowGap } = contentContainerStyle;
2069
+ if (gap || columnGap || rowGap) {
2070
+ contentContainerStyle.gap = void 0;
2071
+ contentContainerStyle.columnGap = void 0;
2072
+ contentContainerStyle.rowGap = void 0;
2073
+ return {
2074
+ columnGap,
2075
+ gap,
2076
+ rowGap
2077
+ };
2078
+ }
2079
+ }
2080
+ function getRenderedItem(ctx, state, key) {
2081
+ if (!state) {
2082
+ return null;
2083
+ }
2084
+ const {
2085
+ indexByKey,
2086
+ props: { data, renderItem: renderItem2 }
2087
+ } = state;
2088
+ const index = indexByKey.get(key);
2089
+ if (index === void 0) {
2090
+ return null;
2091
+ }
2092
+ let renderedItem = null;
2093
+ if (renderItem2) {
2094
+ const itemProps = {
2095
+ extraData: peek$(ctx, "extraData"),
2096
+ index,
2097
+ item: data[index]
2098
+ };
2099
+ renderedItem = React3__default.createElement(renderItem2, itemProps);
2100
+ }
2101
+ return { index, item: data[index], renderedItem };
2102
+ }
2103
+
2104
+ // src/components/LegendList.tsx
2105
+ var DEFAULT_DRAW_DISTANCE = 250;
2106
+ var DEFAULT_ITEM_SIZE = 100;
2107
+ var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
2108
+ return /* @__PURE__ */ React3.createElement(StateProvider, null, /* @__PURE__ */ React3.createElement(LegendListInner, { ...props, ref: forwardedRef }));
2109
+ });
2110
+ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
2111
+ var _a;
2112
+ const {
2113
+ data: dataProp = [],
2114
+ initialScrollIndex: initialScrollIndexProp,
2115
+ initialScrollOffset,
2116
+ horizontal,
2117
+ drawDistance = 250,
2118
+ recycleItems = false,
2119
+ onEndReachedThreshold = 0.5,
2120
+ onStartReachedThreshold = 0.5,
2121
+ maintainScrollAtEnd = false,
2122
+ maintainScrollAtEndThreshold = 0.1,
2123
+ alignItemsAtEnd = false,
2124
+ maintainVisibleContentPosition = false,
2125
+ onScroll: onScrollProp,
2126
+ onMomentumScrollEnd,
2127
+ numColumns: numColumnsProp = 1,
2128
+ columnWrapperStyle,
2129
+ keyExtractor: keyExtractorProp,
2130
+ renderItem: renderItem2,
2131
+ estimatedListSize,
2132
+ estimatedItemSize: estimatedItemSizeProp,
2133
+ getEstimatedItemSize,
2134
+ suggestEstimatedItemSize,
2135
+ ListHeaderComponent,
2136
+ ListEmptyComponent,
2137
+ onItemSizeChanged,
2138
+ refScrollView,
2139
+ waitForInitialLayout = true,
2140
+ extraData,
2141
+ contentContainerStyle: contentContainerStyleProp,
2142
+ style: styleProp,
2143
+ onLayout: onLayoutProp,
2144
+ onRefresh,
2145
+ refreshing,
2146
+ progressViewOffset,
2147
+ refreshControl,
2148
+ initialContainerPoolRatio = 2,
2149
+ viewabilityConfig,
2150
+ viewabilityConfigCallbackPairs,
2151
+ snapToIndices,
2152
+ onViewableItemsChanged,
2153
+ onStartReached,
2154
+ onEndReached,
2155
+ onLoad,
2156
+ ...rest
2157
+ } = props;
2158
+ const [renderNum, setRenderNum] = useState(0);
2159
+ const initialScroll = typeof initialScrollIndexProp === "number" ? { index: initialScrollIndexProp } : initialScrollIndexProp;
2160
+ const initialScrollIndex = initialScroll == null ? void 0 : initialScroll.index;
2161
+ const [canRender, setCanRender] = React3.useState(!IsNewArchitecture);
2162
+ const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
2163
+ const style = { ...StyleSheet.flatten(styleProp) };
2164
+ const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
2165
+ const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
2166
+ const ctx = useStateContext();
2167
+ ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
2168
+ const refScroller = useRef(null);
2169
+ const combinedRef = useCombinedRef(refScroller, refScrollView);
2170
+ const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
2171
+ const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
2172
+ const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
2173
+ const refState = useRef();
2174
+ if (!refState.current) {
2175
+ const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : Dimensions.get("window"))[horizontal ? "width" : "height"];
2176
+ refState.current = {
2177
+ averageSizes: {},
2178
+ columns: /* @__PURE__ */ new Map(),
2179
+ containerItemKeys: /* @__PURE__ */ new Set(),
2180
+ enableScrollForNextCalculateItemsInView: true,
2181
+ endBuffered: -1,
2182
+ endNoBuffer: -1,
2183
+ endReachedBlockedByTimer: false,
2184
+ firstFullyOnScreenIndex: -1,
2185
+ idCache: /* @__PURE__ */ new Map(),
2186
+ idsInView: [],
2187
+ indexByKey: /* @__PURE__ */ new Map(),
2188
+ initialScroll,
2189
+ isAtEnd: false,
2190
+ isAtStart: false,
2191
+ isEndReached: false,
2192
+ isStartReached: false,
2193
+ lastBatchingAction: Date.now(),
2194
+ lastLayout: void 0,
2195
+ loadStartTime: Date.now(),
2196
+ minIndexSizeChanged: 0,
2197
+ nativeMarginTop: 0,
2198
+ pendingAdjust: 0,
2199
+ positions: /* @__PURE__ */ new Map(),
2200
+ props: {},
2201
+ queuedCalculateItemsInView: 0,
2202
+ queuedItemSizeUpdates: [],
2203
+ refScroller: void 0,
2204
+ scroll: 0,
2205
+ scrollAdjustHandler: new ScrollAdjustHandler(ctx),
2206
+ scrollForNextCalculateItemsInView: void 0,
2207
+ scrollHistory: [],
2208
+ scrollLength: initialScrollLength,
2209
+ scrollPending: 0,
2210
+ scrollPrev: 0,
2211
+ scrollPrevTime: 0,
2212
+ scrollTime: 0,
2213
+ sizes: /* @__PURE__ */ new Map(),
2214
+ sizesKnown: /* @__PURE__ */ new Map(),
2215
+ startBuffered: -1,
2216
+ startNoBuffer: -1,
2217
+ startReachedBlockedByTimer: false,
2218
+ timeoutSizeMessage: 0,
2219
+ timeouts: /* @__PURE__ */ new Set(),
2220
+ totalSize: 0,
2221
+ viewabilityConfigCallbackPairs: void 0
2222
+ };
2223
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
2224
+ set$(ctx, "extraData", extraData);
2225
+ }
2226
+ const state = refState.current;
2227
+ const isFirst = !state.props.renderItem;
2228
+ const didDataChange = state.props.data !== dataProp;
2229
+ state.props = {
2230
+ alignItemsAtEnd,
2231
+ data: dataProp,
2232
+ estimatedItemSize,
2233
+ getEstimatedItemSize,
2234
+ horizontal: !!horizontal,
2235
+ initialContainerPoolRatio,
2236
+ initialScroll,
2237
+ keyExtractor,
2238
+ maintainScrollAtEnd,
2239
+ maintainScrollAtEndThreshold,
2240
+ maintainVisibleContentPosition,
2241
+ numColumns: numColumnsProp,
2242
+ onEndReached,
2243
+ onEndReachedThreshold,
2244
+ onItemSizeChanged,
2245
+ onLoad,
2246
+ onScroll: onScrollProp,
2247
+ onStartReached,
2248
+ onStartReachedThreshold,
2249
+ renderItem: renderItem2,
2250
+ scrollBuffer,
2251
+ snapToIndices,
2252
+ stylePaddingBottom: stylePaddingBottomState,
2253
+ stylePaddingTop: stylePaddingTopState,
2254
+ suggestEstimatedItemSize: !!suggestEstimatedItemSize
1717
2255
  };
2256
+ state.refScroller = refScroller;
1718
2257
  const checkResetContainers = (isFirst2) => {
1719
- const state = refState.current;
1720
- if (state) {
1721
- state.data = dataProp;
2258
+ const state2 = refState.current;
2259
+ if (state2) {
2260
+ state2.props.data = dataProp;
1722
2261
  if (!isFirst2) {
1723
- calculateItemsInView({ dataChanged: true, doMVCP: true });
1724
- const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
1725
- if (!didMaintainScrollAtEnd && dataProp.length > state.data.length) {
1726
- state.isEndReached = false;
2262
+ calculateItemsInView(ctx, state2, { dataChanged: true, doMVCP: true });
2263
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2264
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state2, false);
2265
+ if (!didMaintainScrollAtEnd && dataProp.length > state2.props.data.length) {
2266
+ state2.isEndReached = false;
1727
2267
  }
1728
2268
  if (!didMaintainScrollAtEnd) {
1729
- checkAtTop();
1730
- checkAtBottom();
1731
- }
1732
- }
1733
- }
1734
- };
1735
- const updateTotalSize = () => {
1736
- const { data, positions } = refState.current;
1737
- if (data.length === 0) {
1738
- addTotalSize(null, 0);
1739
- } else {
1740
- const lastId = getId(data.length - 1);
1741
- if (lastId !== void 0) {
1742
- const lastPosition = positions.get(lastId);
1743
- if (lastPosition !== void 0) {
1744
- const lastSize = getItemSize(lastId, data.length - 1, data[dataProp.length - 1]);
1745
- if (lastSize !== void 0) {
1746
- const totalSize = lastPosition + lastSize;
1747
- addTotalSize(null, totalSize);
1748
- }
1749
- }
1750
- }
1751
- }
1752
- };
1753
- const findAvailableContainers = (numNeeded, startBuffered, endBuffered, pendingRemoval) => {
1754
- const state = refState.current;
1755
- const numContainers = peek$(ctx, "numContainers");
1756
- const result = [];
1757
- const availableContainers = [];
1758
- for (let u = 0; u < numContainers; u++) {
1759
- const key = peek$(ctx, `containerItemKey${u}`);
1760
- let isOk = key === void 0;
1761
- if (!isOk) {
1762
- const index = pendingRemoval.indexOf(u);
1763
- if (index !== -1) {
1764
- pendingRemoval.splice(index, 1);
1765
- isOk = true;
1766
- }
1767
- }
1768
- if (isOk) {
1769
- result.push(u);
1770
- if (result.length >= numNeeded) {
1771
- return result;
1772
- }
1773
- }
1774
- }
1775
- for (let u = 0; u < numContainers; u++) {
1776
- const key = peek$(ctx, `containerItemKey${u}`);
1777
- if (key === void 0) continue;
1778
- const index = state.indexByKey.get(key);
1779
- if (index < startBuffered) {
1780
- availableContainers.push({ index: u, distance: startBuffered - index });
1781
- } else if (index > endBuffered) {
1782
- availableContainers.push({ index: u, distance: index - endBuffered });
1783
- }
1784
- }
1785
- const remaining = numNeeded - result.length;
1786
- if (remaining > 0) {
1787
- if (availableContainers.length > 0) {
1788
- if (availableContainers.length > remaining) {
1789
- availableContainers.sort(comparatorByDistance);
1790
- availableContainers.length = remaining;
1791
- }
1792
- for (const container of availableContainers) {
1793
- result.push(container.index);
1794
- }
1795
- }
1796
- const stillNeeded = numNeeded - result.length;
1797
- if (stillNeeded > 0) {
1798
- for (let i = 0; i < stillNeeded; i++) {
1799
- result.push(numContainers + i);
1800
- }
1801
- if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1802
- console.warn(
1803
- "[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.",
1804
- {
1805
- debugInfo: {
1806
- numContainers,
1807
- numNeeded,
1808
- stillNeeded,
1809
- numContainersPooled: peek$(ctx, "numContainersPooled")
1810
- }
1811
- }
1812
- );
2269
+ checkAtTop(state2);
2270
+ checkAtBottom(ctx, state2);
1813
2271
  }
1814
2272
  }
1815
2273
  }
1816
- return result.sort(comparatorDefault);
1817
2274
  };
1818
- const isFirst = !refState.current.renderItem;
1819
2275
  const memoizedLastItemKeys = useMemo(() => {
1820
2276
  if (!dataProp.length) return [];
1821
2277
  return Array.from(
1822
2278
  { length: Math.min(numColumnsProp, dataProp.length) },
1823
- (_, i) => getId(dataProp.length - 1 - i)
2279
+ (_, i) => getId(state, dataProp.length - 1 - i)
1824
2280
  );
1825
2281
  }, [dataProp, numColumnsProp]);
1826
- const initalizeStateVars = () => {
2282
+ const initializeStateVars = () => {
1827
2283
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
1828
2284
  set$(ctx, "numColumns", numColumnsProp);
1829
2285
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
1830
- setPaddingTop({ stylePaddingTop: stylePaddingTopState });
1831
- refState.current.stylePaddingBottom = stylePaddingBottomState;
1832
- const paddingDiff = stylePaddingTopState - prevPaddingTop;
1833
- if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
1834
- requestAdjust(paddingDiff);
2286
+ setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
2287
+ refState.current.props.stylePaddingBottom = stylePaddingBottomState;
2288
+ let paddingDiff = stylePaddingTopState - prevPaddingTop;
2289
+ if (maintainVisibleContentPosition && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
2290
+ if (state.scroll < 0) {
2291
+ paddingDiff += state.scroll;
2292
+ }
2293
+ requestAdjust(ctx, state, paddingDiff);
1835
2294
  }
1836
2295
  };
1837
2296
  if (isFirst) {
1838
- initalizeStateVars();
1839
- updateAllPositions();
2297
+ initializeStateVars();
2298
+ updateAllPositions(ctx, state);
1840
2299
  }
1841
2300
  const initialContentOffset = useMemo(() => {
1842
- const initialContentOffset2 = initialScrollOffset || calculateOffsetForIndex(initialScrollIndex);
2301
+ const initialContentOffset2 = initialScrollOffset || calculateOffsetForIndex(ctx, state, initialScrollIndex);
1843
2302
  refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
1844
2303
  if (initialContentOffset2 > 0) {
1845
- scrollTo({ offset: initialContentOffset2, animated: false, index: initialScrollIndex });
2304
+ scrollTo(state, { animated: false, index: initialScrollIndex, offset: initialContentOffset2 });
1846
2305
  }
1847
2306
  return initialContentOffset2;
1848
2307
  }, [renderNum]);
@@ -1858,18 +2317,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1858
2317
  }
1859
2318
  }
1860
2319
  useLayoutEffect(() => {
1861
- var _a2, _b;
1862
2320
  if (IsNewArchitecture) {
1863
- const measured = (_b = (_a2 = refScroller.current) == null ? void 0 : _a2.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a2);
2321
+ let measured;
2322
+ refScroller.current.measure((x, y, width, height) => {
2323
+ measured = { height, width, x, y };
2324
+ });
1864
2325
  if (measured) {
1865
2326
  const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
1866
2327
  if (size) {
1867
- handleLayout(measured);
2328
+ handleLayout(ctx, state, measured, setCanRender);
1868
2329
  }
1869
2330
  }
1870
2331
  }
1871
2332
  if (!isFirst) {
1872
- calculateItemsInView({ doMVCP: true });
2333
+ calculateItemsInView(ctx, state, { doMVCP: true });
1873
2334
  }
1874
2335
  }, [dataProp]);
1875
2336
  const onLayoutHeader = useCallback((rect, fromLayoutEffect) => {
@@ -1882,13 +2343,18 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1882
2343
  }
1883
2344
  } else {
1884
2345
  setTimeout(() => {
1885
- scrollToIndex({ ...initialScroll, animated: false });
2346
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1886
2347
  }, 17);
1887
2348
  }
1888
2349
  }
1889
2350
  }, []);
1890
2351
  useLayoutEffect(() => {
1891
- const didAllocateContainers = doInitialAllocateContainers();
2352
+ if (snapToIndices) {
2353
+ updateSnapToOffsets(ctx, state);
2354
+ }
2355
+ }, [snapToIndices]);
2356
+ useLayoutEffect(() => {
2357
+ const didAllocateContainers = doInitialAllocateContainersCallback();
1892
2358
  if (!didAllocateContainers) {
1893
2359
  checkResetContainers(
1894
2360
  /*isFirst*/
@@ -1899,421 +2365,183 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1899
2365
  useLayoutEffect(() => {
1900
2366
  set$(ctx, "extraData", extraData);
1901
2367
  }, [extraData]);
1902
- refState.current.renderItem = renderItem2;
1903
- useLayoutEffect(initalizeStateVars, [
2368
+ useLayoutEffect(initializeStateVars, [
1904
2369
  memoizedLastItemKeys.join(","),
1905
2370
  numColumnsProp,
1906
2371
  stylePaddingTopState,
1907
2372
  stylePaddingBottomState
1908
2373
  ]);
1909
- const getRenderedItem = useCallback((key) => {
1910
- const state = refState.current;
1911
- if (!state) {
1912
- return null;
1913
- }
1914
- const { data, indexByKey } = state;
1915
- const index = indexByKey.get(key);
1916
- if (index === void 0) {
1917
- return null;
1918
- }
1919
- const renderItemProp = refState.current.renderItem;
1920
- let renderedItem = null;
1921
- if (renderItemProp) {
1922
- const itemProps = {
1923
- item: data[index],
1924
- index,
1925
- extraData: peek$(ctx, "extraData")
1926
- };
1927
- renderedItem = React2.createElement(renderItemProp, itemProps);
1928
- }
1929
- return { index, item: data[index], renderedItem };
1930
- }, []);
1931
- const doInitialAllocateContainers = () => {
1932
- const state = refState.current;
1933
- const { scrollLength, data } = state;
1934
- if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1935
- const averageItemSize = getEstimatedItemSize ? getEstimatedItemSize(0, data[0]) : estimatedItemSize;
1936
- const Extra = 1.5;
1937
- const numContainers = Math.ceil(
1938
- (scrollLength + scrollBuffer * 2) / averageItemSize * numColumnsProp * Extra
1939
- );
1940
- for (let i = 0; i < numContainers; i++) {
1941
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1942
- set$(ctx, `containerColumn${i}`, -1);
1943
- }
1944
- set$(ctx, "numContainers", numContainers);
1945
- set$(ctx, "numContainersPooled", numContainers * initialContainerPoolRatio);
1946
- if (!IsNewArchitecture) {
1947
- if (initialScroll) {
1948
- requestAnimationFrame(() => {
1949
- calculateItemsInView();
1950
- });
1951
- } else {
1952
- calculateItemsInView();
1953
- }
1954
- }
1955
- return true;
1956
- }
2374
+ const doInitialAllocateContainersCallback = () => {
2375
+ return doInitialAllocateContainers(ctx, state);
1957
2376
  };
1958
2377
  useEffect(() => {
1959
- const state = refState.current;
1960
2378
  const viewability = setupViewability({
2379
+ onViewableItemsChanged,
1961
2380
  viewabilityConfig,
1962
- viewabilityConfigCallbackPairs,
1963
- onViewableItemsChanged
2381
+ viewabilityConfigCallbackPairs
1964
2382
  });
1965
2383
  state.viewabilityConfigCallbackPairs = viewability;
1966
2384
  state.enableScrollForNextCalculateItemsInView = !viewability;
1967
2385
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
1968
2386
  if (!IsNewArchitecture) {
1969
2387
  useInit(() => {
1970
- doInitialAllocateContainers();
2388
+ doInitialAllocateContainersCallback();
1971
2389
  });
1972
2390
  }
1973
- const updateOneItemSize = useCallback((itemKey, sizeObj) => {
1974
- const state = refState.current;
1975
- const { sizes, indexByKey, sizesKnown, data, averageSizes } = state;
1976
- if (!data) return 0;
1977
- const index = indexByKey.get(itemKey);
1978
- const prevSize = getItemSize(itemKey, index, data);
1979
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
1980
- sizesKnown.set(itemKey, size);
1981
- const itemType = "";
1982
- let averages = averageSizes[itemType];
1983
- if (!averages) {
1984
- averages = averageSizes[itemType] = { num: 0, avg: 0 };
1985
- }
1986
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
1987
- averages.num++;
1988
- if (!prevSize || Math.abs(prevSize - size) > 0.1) {
1989
- sizes.set(itemKey, size);
1990
- return size - prevSize;
1991
- }
1992
- return 0;
1993
- }, []);
1994
- const updateItemSizes = useCallback(
1995
- (itemUpdates) => {
1996
- var _a2;
1997
- const state = refState.current;
1998
- if (!state.data) return;
1999
- let needsRecalculate = false;
2000
- let shouldMaintainScrollAtEnd = false;
2001
- let minIndexSizeChanged;
2002
- let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2003
- for (const { itemKey, sizeObj } of itemUpdates) {
2004
- const index = state.indexByKey.get(itemKey);
2005
- const prevSizeKnown = state.sizesKnown.get(itemKey);
2006
- const diff = updateOneItemSize(itemKey, sizeObj);
2007
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2008
- if (diff !== 0) {
2009
- minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2010
- if (((_a2 = state.scrollingTo) == null ? void 0 : _a2.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index) {
2011
- requestAdjust(diff * state.scrollingTo.viewPosition);
2012
- }
2013
- const { startBuffered, endBuffered } = state;
2014
- needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2015
- if (!needsRecalculate) {
2016
- const numContainers = ctx.values.get("numContainers");
2017
- for (let i = 0; i < numContainers; i++) {
2018
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2019
- needsRecalculate = true;
2020
- break;
2021
- }
2022
- }
2023
- }
2024
- if (state.needsOtherAxisSize) {
2025
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2026
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
2027
- }
2028
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2029
- shouldMaintainScrollAtEnd = true;
2030
- }
2031
- onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2032
- size,
2033
- previous: size - diff,
2034
- index,
2035
- itemKey,
2036
- itemData: state.data[index]
2037
- });
2038
- }
2039
- }
2040
- if (minIndexSizeChanged !== void 0) {
2041
- state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
2042
- }
2043
- if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2044
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
2045
- state.timeoutSizeMessage = setTimeout(() => {
2046
- var _a3;
2047
- state.timeoutSizeMessage = void 0;
2048
- const num = state.sizesKnown.size;
2049
- const avg = (_a3 = state.averageSizes[""]) == null ? void 0 : _a3.avg;
2050
- console.warn(
2051
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2052
- );
2053
- }, 1e3);
2054
- }
2055
- const cur = peek$(ctx, "otherAxisSize");
2056
- if (!cur || maxOtherAxisSize > cur) {
2057
- set$(ctx, "otherAxisSize", maxOtherAxisSize);
2058
- }
2059
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2060
- if (containersDidLayout || checkAllSizesKnown()) {
2061
- if (needsRecalculate) {
2062
- state.scrollForNextCalculateItemsInView = void 0;
2063
- calculateItemsInView({ doMVCP: true });
2064
- }
2065
- if (shouldMaintainScrollAtEnd) {
2066
- doMaintainScrollAtEnd(false);
2067
- }
2068
- }
2069
- },
2070
- []
2071
- );
2072
- const updateItemSize = useCallback((itemKey, sizeObj) => {
2073
- var _a2, _b;
2074
- if (IsNewArchitecture) {
2075
- const { sizesKnown } = refState.current;
2076
- const numContainers = ctx.values.get("numContainers");
2077
- const changes = [];
2078
- for (let i = 0; i < numContainers; i++) {
2079
- const containerItemKey = peek$(ctx, `containerItemKey${i}`);
2080
- if (itemKey === containerItemKey) {
2081
- changes.push({ itemKey, sizeObj });
2082
- } else if (!sizesKnown.has(containerItemKey) && containerItemKey !== void 0) {
2083
- const containerRef = ctx.viewRefs.get(i);
2084
- if (containerRef) {
2085
- const measured = (_b = (_a2 = containerRef.current) == null ? void 0 : _a2.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a2);
2086
- if (measured) {
2087
- changes.push({ itemKey: containerItemKey, sizeObj: measured });
2088
- }
2089
- }
2090
- }
2091
- }
2092
- if (changes.length > 0) {
2093
- updateItemSizes(changes);
2094
- }
2095
- } else {
2096
- updateItemSizes([{ itemKey, sizeObj }]);
2097
- }
2098
- }, []);
2099
- const handleLayout = useCallback((size) => {
2100
- const scrollLength = size[horizontal ? "width" : "height"];
2101
- const otherAxisSize = size[horizontal ? "height" : "width"];
2102
- const state = refState.current;
2103
- const didChange = scrollLength !== state.scrollLength;
2104
- const prevOtherAxisSize = state.otherAxisSize;
2105
- state.scrollLength = scrollLength;
2106
- state.otherAxisSize = otherAxisSize;
2107
- state.lastBatchingAction = Date.now();
2108
- state.scrollForNextCalculateItemsInView = void 0;
2109
- doInitialAllocateContainers();
2110
- if (didChange) {
2111
- calculateItemsInView({ doMVCP: true });
2112
- }
2113
- if (didChange || otherAxisSize !== prevOtherAxisSize) {
2114
- set$(ctx, "scrollSize", { width: size.width, height: size.height });
2115
- }
2116
- doMaintainScrollAtEnd(false);
2117
- updateAlignItemsPaddingTop();
2118
- checkAtBottom();
2119
- checkAtTop();
2120
- if (refState.current) {
2121
- refState.current.needsOtherAxisSize = otherAxisSize - (stylePaddingTopState || 0) < 10;
2122
- }
2123
- if (__DEV__ && scrollLength === 0) {
2124
- warnDevOnce(
2125
- "height0",
2126
- `List ${horizontal ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
2127
- );
2128
- }
2129
- calculateItemsInView({ doMVCP: true });
2130
- setCanRender(true);
2131
- }, []);
2132
2391
  const onLayout = useCallback((event) => {
2133
2392
  const layout = event.nativeEvent.layout;
2134
- handleLayout(layout);
2393
+ handleLayout(ctx, state, layout, setCanRender);
2135
2394
  if (onLayoutProp) {
2136
2395
  onLayoutProp(event);
2137
2396
  }
2138
2397
  }, []);
2139
- const handleScroll = useCallback(
2140
- (event) => {
2141
- var _a2, _b, _c, _d;
2142
- if (((_b = (_a2 = event.nativeEvent) == null ? void 0 : _a2.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2143
- return;
2144
- }
2145
- const state = refState.current;
2146
- const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
2147
- const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
2148
- if (ignoreScrollFromMVCP && !state.scrollingTo) {
2149
- const { lt, gt } = ignoreScrollFromMVCP;
2150
- if (lt && newScroll < lt || gt && newScroll > gt) {
2151
- return;
2398
+ useImperativeHandle(forwardedRef, () => {
2399
+ const scrollIndexIntoView = (options) => {
2400
+ const state2 = refState.current;
2401
+ if (state2) {
2402
+ const { index, ...rest2 } = options;
2403
+ const { startNoBuffer, endNoBuffer } = state2;
2404
+ if (index < startNoBuffer || index > endNoBuffer) {
2405
+ const viewPosition = index < startNoBuffer ? 0 : 1;
2406
+ scrollToIndex(ctx, state2, {
2407
+ ...rest2,
2408
+ index,
2409
+ viewPosition
2410
+ });
2152
2411
  }
2153
2412
  }
2154
- state.scrollPending = newScroll;
2155
- updateScroll(newScroll);
2156
- (_d = state.onScroll) == null ? void 0 : _d.call(state, event);
2157
- },
2158
- []
2159
- );
2160
- const updateScroll = useCallback((newScroll) => {
2161
- const state = refState.current;
2162
- const scrollingTo = state.scrollingTo;
2163
- state.hasScrolled = true;
2164
- state.lastBatchingAction = Date.now();
2165
- const currentTime = performance.now();
2166
- if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
2167
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2168
- }
2169
- if (state.scrollHistory.length > 5) {
2170
- state.scrollHistory.shift();
2171
- }
2172
- state.scrollPrev = state.scroll;
2173
- state.scrollPrevTime = state.scrollTime;
2174
- state.scroll = newScroll;
2175
- state.scrollTime = currentTime;
2176
- calculateItemsInView();
2177
- checkAtBottom();
2178
- checkAtTop();
2179
- }, []);
2180
- useImperativeHandle(
2181
- forwardedRef,
2182
- () => {
2183
- const scrollIndexIntoView = (options) => {
2184
- if (refState.current) {
2185
- const { index, ...rest2 } = options;
2186
- const { startNoBuffer, endNoBuffer } = refState.current;
2187
- if (index < startNoBuffer || index > endNoBuffer) {
2188
- const viewPosition = index < startNoBuffer ? 0 : 1;
2189
- scrollToIndex({
2190
- ...rest2,
2191
- viewPosition,
2192
- index
2193
- });
2194
- }
2413
+ };
2414
+ return {
2415
+ flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
2416
+ getNativeScrollRef: () => refScroller.current,
2417
+ getScrollableNode: () => refScroller.current.getScrollableNode(),
2418
+ getScrollResponder: () => refScroller.current.getScrollResponder(),
2419
+ getState: () => {
2420
+ const state2 = refState.current;
2421
+ return state2 ? {
2422
+ contentLength: state2.totalSize,
2423
+ end: state2.endNoBuffer,
2424
+ endBuffered: state2.endBuffered,
2425
+ isAtEnd: state2.isAtEnd,
2426
+ isAtStart: state2.isAtStart,
2427
+ positions: state2.positions,
2428
+ scroll: state2.scroll,
2429
+ scrollLength: state2.scrollLength,
2430
+ sizeAtIndex: (index) => state2.sizesKnown.get(getId(state2, index)),
2431
+ sizes: state2.sizesKnown,
2432
+ start: state2.startNoBuffer,
2433
+ startBuffered: state2.startBuffered
2434
+ } : {};
2435
+ },
2436
+ scrollIndexIntoView,
2437
+ scrollItemIntoView: ({ item, ...props2 }) => {
2438
+ const data = refState.current.props.data;
2439
+ const index = data.indexOf(item);
2440
+ if (index !== -1) {
2441
+ scrollIndexIntoView({ index, ...props2 });
2195
2442
  }
2196
- };
2197
- return {
2198
- flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
2199
- getNativeScrollRef: () => refScroller.current,
2200
- getScrollableNode: () => refScroller.current.getScrollableNode(),
2201
- getScrollResponder: () => refScroller.current.getScrollResponder(),
2202
- getState: () => {
2203
- const state = refState.current;
2204
- return state ? {
2205
- contentLength: state.totalSize,
2206
- end: state.endNoBuffer,
2207
- endBuffered: state.endBuffered,
2208
- isAtEnd: state.isAtEnd,
2209
- isAtStart: state.isAtStart,
2210
- scroll: state.scroll,
2211
- scrollLength: state.scrollLength,
2212
- start: state.startNoBuffer,
2213
- startBuffered: state.startBuffered,
2214
- sizes: state.sizesKnown,
2215
- sizeAtIndex: (index) => state.sizesKnown.get(getId(index))
2216
- } : {};
2217
- },
2218
- scrollIndexIntoView,
2219
- scrollItemIntoView: ({ item, ...props2 }) => {
2220
- const { data } = refState.current;
2221
- const index = data.indexOf(item);
2222
- if (index !== -1) {
2223
- scrollIndexIntoView({ index, ...props2 });
2224
- }
2225
- },
2226
- scrollToIndex,
2227
- scrollToItem: ({ item, ...props2 }) => {
2228
- const { data } = refState.current;
2229
- const index = data.indexOf(item);
2230
- if (index !== -1) {
2231
- scrollToIndex({ index, ...props2 });
2232
- }
2233
- },
2234
- scrollToOffset: (params) => scrollTo(params),
2235
- scrollToEnd: (options) => {
2236
- const { data, stylePaddingBottom } = refState.current;
2237
- const index = data.length - 1;
2238
- if (index !== -1) {
2239
- const paddingBottom = stylePaddingBottom || 0;
2240
- const footerSize = peek$(ctx, "footerSize") || 0;
2241
- scrollToIndex({
2242
- index,
2243
- viewPosition: 1,
2244
- viewOffset: -paddingBottom - footerSize,
2245
- ...options
2246
- });
2247
- }
2248
- },
2249
- setVisibleContentAnchorOffset: (value) => {
2250
- const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
2251
- set$(ctx, "scrollAdjustUserOffset", val);
2443
+ },
2444
+ scrollToEnd: (options) => {
2445
+ const data = refState.current.props.data;
2446
+ const stylePaddingBottom = refState.current.props.stylePaddingBottom;
2447
+ const index = data.length - 1;
2448
+ if (index !== -1) {
2449
+ const paddingBottom = stylePaddingBottom || 0;
2450
+ const footerSize = peek$(ctx, "footerSize") || 0;
2451
+ scrollToIndex(ctx, state, {
2452
+ index,
2453
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
2454
+ viewPosition: 1,
2455
+ ...options
2456
+ });
2252
2457
  }
2253
- };
2254
- },
2255
- []
2256
- );
2458
+ },
2459
+ scrollToIndex: (params) => scrollToIndex(ctx, state, params),
2460
+ scrollToItem: ({ item, ...props2 }) => {
2461
+ const data = refState.current.props.data;
2462
+ const index = data.indexOf(item);
2463
+ if (index !== -1) {
2464
+ scrollToIndex(ctx, state, { index, ...props2 });
2465
+ }
2466
+ },
2467
+ scrollToOffset: (params) => scrollTo(state, params),
2468
+ setVisibleContentAnchorOffset: (value) => {
2469
+ const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
2470
+ set$(ctx, "scrollAdjustUserOffset", val);
2471
+ }
2472
+ };
2473
+ }, []);
2257
2474
  if (Platform.OS === "web") {
2258
2475
  useEffect(() => {
2259
2476
  if (initialContentOffset) {
2260
- scrollTo({ offset: initialContentOffset, animated: false });
2477
+ scrollTo(state, { animated: false, offset: initialContentOffset });
2261
2478
  }
2262
2479
  }, []);
2263
2480
  }
2264
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(
2481
+ const fns = useMemo(
2482
+ () => ({
2483
+ getRenderedItem: (key) => getRenderedItem(ctx, state, key),
2484
+ onScroll: (event) => onScroll(ctx, state, event),
2485
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
2486
+ }),
2487
+ []
2488
+ );
2489
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
2265
2490
  ListComponent,
2266
2491
  {
2267
2492
  ...rest,
2493
+ alignItemsAtEnd,
2268
2494
  canRender,
2495
+ contentContainerStyle,
2496
+ getRenderedItem: fns.getRenderedItem,
2269
2497
  horizontal,
2270
- refScrollView: combinedRef,
2271
2498
  initialContentOffset,
2272
- getRenderedItem,
2273
- updateItemSize,
2274
- handleScroll,
2499
+ ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
2500
+ ListHeaderComponent,
2501
+ maintainVisibleContentPosition,
2502
+ onLayout,
2503
+ onLayoutHeader,
2275
2504
  onMomentumScrollEnd: (event) => {
2276
2505
  requestAnimationFrame(() => {
2277
- finishScrollTo();
2506
+ finishScrollTo(refState.current);
2278
2507
  });
2279
2508
  if (onMomentumScrollEnd) {
2280
2509
  onMomentumScrollEnd(event);
2281
2510
  }
2282
2511
  },
2283
- onLayout,
2512
+ onScroll: fns.onScroll,
2284
2513
  recycleItems,
2285
- alignItemsAtEnd,
2286
- ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
2287
- ListHeaderComponent,
2288
- maintainVisibleContentPosition,
2289
- scrollEventThrottle: Platform.OS === "web" ? 16 : void 0,
2290
- waitForInitialLayout,
2291
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControl, {
2514
+ refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
2292
2515
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
2293
- }) : refreshControl : onRefresh && /* @__PURE__ */ React2.createElement(
2516
+ }) : refreshControl : onRefresh && /* @__PURE__ */ React3.createElement(
2294
2517
  RefreshControl,
2295
2518
  {
2296
- refreshing: !!refreshing,
2297
2519
  onRefresh,
2298
- progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState
2520
+ progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState,
2521
+ refreshing: !!refreshing
2299
2522
  }
2300
2523
  ),
2301
- style,
2302
- contentContainerStyle,
2524
+ refScrollView: combinedRef,
2303
2525
  scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
2304
- onLayoutHeader
2526
+ scrollEventThrottle: Platform.OS === "web" ? 16 : void 0,
2527
+ snapToIndices,
2528
+ style,
2529
+ updateItemSize: fns.updateItemSize,
2530
+ waitForInitialLayout
2305
2531
  }
2306
- ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React2.createElement(DebugView, { state: refState.current }));
2532
+ ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3.createElement(DebugView, { state: refState.current }));
2307
2533
  });
2534
+
2535
+ // src/components/LazyLegendList.tsx
2308
2536
  var typedForwardRef2 = forwardRef;
2309
2537
  var renderItem = ({ item }) => item;
2310
2538
  var LazyLegendList = typedForwardRef2(function LazyLegendList2(props, forwardedRef) {
2311
2539
  const { LegendList: LegendListProp, children, ...rest } = props;
2312
2540
  const LegendListComponent = LegendListProp != null ? LegendListProp : LegendList;
2313
- const data = (isArray(children) ? children : React2.Children.toArray(children)).flat(1);
2541
+ const data = (isArray(children) ? children : React3.Children.toArray(children)).flat(1);
2314
2542
  return (
2315
2543
  // @ts-expect-error TODO: Fix this type
2316
- /* @__PURE__ */ React2.createElement(LegendListComponent, { ...rest, data, renderItem, ref: forwardedRef })
2544
+ /* @__PURE__ */ React3.createElement(LegendListComponent, { ...rest, data, ref: forwardedRef, renderItem })
2317
2545
  );
2318
2546
  });
2319
2547