@legendapp/list 2.0.0-next.1 → 2.0.0-next.11

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.js CHANGED
@@ -24,21 +24,24 @@ function _interopNamespace(e) {
24
24
 
25
25
  var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
26
26
 
27
- // src/LegendList.tsx
27
+ // src/components/LazyLegendList.tsx
28
28
  var ContextState = React3__namespace.createContext(null);
29
29
  function StateProvider({ children }) {
30
30
  const [value] = React3__namespace.useState(() => ({
31
+ animatedScrollY: new reactNative.Animated.Value(0),
32
+ columnWrapperStyle: void 0,
31
33
  listeners: /* @__PURE__ */ new Map(),
34
+ mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
35
+ mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
36
+ mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
37
+ mapViewabilityValues: /* @__PURE__ */ new Map(),
32
38
  values: /* @__PURE__ */ new Map([
33
39
  ["alignItemsPaddingTop", 0],
34
40
  ["stylePaddingTop", 0],
35
- ["headerSize", 0]
41
+ ["headerSize", 0],
42
+ ["numContainers", 0],
43
+ ["totalSize", 0]
36
44
  ]),
37
- mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
38
- mapViewabilityValues: /* @__PURE__ */ new Map(),
39
- mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
40
- mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
41
- columnWrapperStyle: void 0,
42
45
  viewRefs: /* @__PURE__ */ new Map()
43
46
  }));
44
47
  return /* @__PURE__ */ React3__namespace.createElement(ContextState.Provider, { value }, children);
@@ -50,17 +53,6 @@ function createSelectorFunctionsArr(ctx, signalNames) {
50
53
  let lastValues = [];
51
54
  let lastSignalValues = [];
52
55
  return {
53
- subscribe: (cb) => {
54
- const listeners = [];
55
- for (const signalName of signalNames) {
56
- listeners.push(listen$(ctx, signalName, cb));
57
- }
58
- return () => {
59
- for (const listener of listeners) {
60
- listener();
61
- }
62
- };
63
- },
64
56
  get: () => {
65
57
  const currentValues = [];
66
58
  let hasChanged = false;
@@ -76,6 +68,17 @@ function createSelectorFunctionsArr(ctx, signalNames) {
76
68
  lastValues = currentValues;
77
69
  }
78
70
  return lastValues;
71
+ },
72
+ subscribe: (cb) => {
73
+ const listeners = [];
74
+ for (const signalName of signalNames) {
75
+ listeners.push(listen$(ctx, signalName, cb));
76
+ }
77
+ return () => {
78
+ for (const listener of listeners) {
79
+ listener();
80
+ }
81
+ };
79
82
  }
80
83
  };
81
84
  }
@@ -110,7 +113,7 @@ function getContentSize(ctx) {
110
113
  const stylePaddingTop = values.get("stylePaddingTop") || 0;
111
114
  const headerSize = values.get("headerSize") || 0;
112
115
  const footerSize = values.get("footerSize") || 0;
113
- const totalSize = values.get("totalSize") || 0;
116
+ const totalSize = values.get("totalSize");
114
117
  return headerSize + footerSize + totalSize + stylePaddingTop;
115
118
  }
116
119
  function useArr$(signalNames) {
@@ -126,13 +129,13 @@ function useSelector$(signalName, selector) {
126
129
  return value;
127
130
  }
128
131
 
129
- // src/DebugView.tsx
132
+ // src/components/DebugView.tsx
130
133
  var DebugRow = ({ children }) => {
131
- return /* @__PURE__ */ React3__namespace.createElement(reactNative.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" } }, children);
134
+ return /* @__PURE__ */ React3__namespace.createElement(reactNative.View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
132
135
  };
133
136
  var DebugView = React3__namespace.memo(function DebugView2({ state }) {
134
137
  const ctx = useStateContext();
135
- const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, numContainers = 0, numContainersPooled = 0] = useArr$([
138
+ const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
136
139
  "totalSize",
137
140
  "scrollAdjust",
138
141
  "debugRawScroll",
@@ -148,18 +151,18 @@ var DebugView = React3__namespace.memo(function DebugView2({ state }) {
148
151
  return /* @__PURE__ */ React3__namespace.createElement(
149
152
  reactNative.View,
150
153
  {
154
+ pointerEvents: "none",
151
155
  style: {
152
- position: "absolute",
153
- top: 0,
154
- right: 0,
155
- paddingLeft: 4,
156
- paddingBottom: 4,
157
156
  // height: 100,
158
157
  backgroundColor: "#FFFFFFCC",
158
+ borderRadius: 4,
159
159
  padding: 4,
160
- borderRadius: 4
161
- },
162
- pointerEvents: "none"
160
+ paddingBottom: 4,
161
+ paddingLeft: 4,
162
+ position: "absolute",
163
+ right: 0,
164
+ top: 0
165
+ }
163
166
  },
164
167
  /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "TotalSize:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, totalSize.toFixed(2))),
165
168
  /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "ContentSize:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, contentSize.toFixed(2))),
@@ -177,8 +180,146 @@ function useInterval(callback, delay) {
177
180
  return () => clearInterval(interval);
178
181
  }, [delay]);
179
182
  }
183
+ var LeanViewComponent = React3__namespace.forwardRef((props, ref) => {
184
+ return React3__namespace.createElement("RCTView", { ...props, ref });
185
+ });
186
+ LeanViewComponent.displayName = "RCTView";
187
+ var LeanView = reactNative.Platform.OS === "android" || reactNative.Platform.OS === "ios" ? LeanViewComponent : reactNative.View;
188
+
189
+ // src/constants.ts
190
+ var POSITION_OUT_OF_VIEW = -1e7;
191
+ var ENABLE_DEVMODE = __DEV__ && false;
192
+ var ENABLE_DEBUG_VIEW = __DEV__ && false;
193
+ var IsNewArchitecture = global.nativeFabricUIManager != null;
194
+ var useAnimatedValue = (initialValue) => {
195
+ return React3.useRef(new reactNative.Animated.Value(initialValue)).current;
196
+ };
197
+
198
+ // src/hooks/useValue$.ts
199
+ function useValue$(key, params) {
200
+ var _a;
201
+ const { getValue, delay } = params || {};
202
+ const ctx = useStateContext();
203
+ const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
204
+ React3.useMemo(() => {
205
+ let newValue;
206
+ let prevValue;
207
+ let didQueueTask = false;
208
+ listen$(ctx, key, (v) => {
209
+ newValue = getValue ? getValue(v) : v;
210
+ if (delay !== void 0) {
211
+ const fn = () => {
212
+ didQueueTask = false;
213
+ if (newValue !== void 0) {
214
+ animValue.setValue(newValue);
215
+ }
216
+ };
217
+ const delayValue = typeof delay === "function" ? delay(newValue, prevValue) : delay;
218
+ prevValue = newValue;
219
+ if (!didQueueTask) {
220
+ didQueueTask = true;
221
+ if (delayValue === 0) {
222
+ queueMicrotask(fn);
223
+ } else {
224
+ setTimeout(fn, delayValue);
225
+ }
226
+ }
227
+ } else {
228
+ animValue.setValue(newValue);
229
+ }
230
+ });
231
+ }, []);
232
+ return animValue;
233
+ }
234
+ var typedForwardRef = React3.forwardRef;
235
+ var typedMemo = React3.memo;
236
+
237
+ // src/components/PositionView.tsx
238
+ var PositionViewState = typedMemo(function PositionView({
239
+ id,
240
+ horizontal,
241
+ style,
242
+ refView,
243
+ ...rest
244
+ }) {
245
+ const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
246
+ return /* @__PURE__ */ React3__namespace.createElement(
247
+ LeanView,
248
+ {
249
+ ref: refView,
250
+ style: [
251
+ style,
252
+ horizontal ? { transform: [{ translateX: position }] } : { transform: [{ translateY: position }] }
253
+ ],
254
+ ...rest
255
+ }
256
+ );
257
+ });
258
+ var PositionViewAnimated = typedMemo(function PositionView2({
259
+ id,
260
+ horizontal,
261
+ style,
262
+ refView,
263
+ ...rest
264
+ }) {
265
+ const position$ = useValue$(`containerPosition${id}`, {
266
+ getValue: (v) => v != null ? v : POSITION_OUT_OF_VIEW
267
+ });
268
+ return /* @__PURE__ */ React3__namespace.createElement(
269
+ reactNative.Animated.View,
270
+ {
271
+ ref: refView,
272
+ style: [
273
+ style,
274
+ horizontal ? { transform: [{ translateX: position$ }] } : { transform: [{ translateY: position$ }] }
275
+ ],
276
+ ...rest
277
+ }
278
+ );
279
+ });
280
+ var PositionViewSticky = typedMemo(function PositionViewSticky2({
281
+ id,
282
+ horizontal,
283
+ style,
284
+ refView,
285
+ animatedScrollY,
286
+ stickyOffset,
287
+ index,
288
+ ...rest
289
+ }) {
290
+ const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
291
+ const transform = React3__namespace.useMemo(() => {
292
+ if (animatedScrollY && stickyOffset) {
293
+ const stickyPosition = animatedScrollY.interpolate({
294
+ extrapolate: "clamp",
295
+ inputRange: [position, position + 5e3],
296
+ outputRange: [position, position + 5e3]
297
+ });
298
+ return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
299
+ }
300
+ }, [position, horizontal, animatedScrollY, stickyOffset]);
301
+ console.log("index", index, position, transform);
302
+ const viewStyle = React3__namespace.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
303
+ return /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { ref: refView, style: viewStyle, ...rest });
304
+ });
305
+ var PositionView3 = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
306
+
307
+ // src/components/Separator.tsx
308
+ function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
309
+ const [lastItemKeys] = useArr$(["lastItemKeys"]);
310
+ const isALastItem = lastItemKeys.includes(itemKey);
311
+ return isALastItem ? null : /* @__PURE__ */ React.createElement(ItemSeparatorComponent, { leadingItem });
312
+ }
313
+ var symbolFirst = Symbol();
314
+ function useInit(cb) {
315
+ const refValue = React3.useRef(symbolFirst);
316
+ if (refValue.current === symbolFirst) {
317
+ refValue.current = cb();
318
+ }
319
+ return refValue.current;
320
+ }
180
321
 
181
- // src/helpers.ts
322
+ // src/utils/helpers.ts
182
323
  function isFunction(obj) {
183
324
  return typeof obj === "function";
184
325
  }
@@ -208,16 +349,8 @@ function getPadding(s, type) {
208
349
  function extractPadding(style, contentContainerStyle, type) {
209
350
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
210
351
  }
211
- var symbolFirst = Symbol();
212
- function useInit(cb) {
213
- const refValue = React3.useRef(symbolFirst);
214
- if (refValue.current === symbolFirst) {
215
- refValue.current = cb();
216
- }
217
- return refValue.current;
218
- }
219
352
 
220
- // src/ContextContainer.ts
353
+ // src/state/ContextContainer.ts
221
354
  var ContextContainer = React3.createContext(null);
222
355
  function useViewability(callback, configId) {
223
356
  const ctx = useStateContext();
@@ -261,7 +394,7 @@ function useRecyclingEffect(effect) {
261
394
  prevItem: void 0
262
395
  });
263
396
  React3.useEffect(() => {
264
- let ret = void 0;
397
+ let ret;
265
398
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
266
399
  ret = effect({
267
400
  index,
@@ -275,7 +408,7 @@ function useRecyclingEffect(effect) {
275
408
  prevItem: value
276
409
  };
277
410
  return ret;
278
- }, [index, value]);
411
+ }, [index, value, effect]);
279
412
  }
280
413
  function useRecyclingState(valueOrFun) {
281
414
  const { index, value, itemKey, triggerLayout } = React3.useContext(ContextContainer);
@@ -313,43 +446,26 @@ function useListScrollSize() {
313
446
  const [scrollSize] = useArr$(["scrollSize"]);
314
447
  return scrollSize;
315
448
  }
316
- var LeanViewComponent = React3__namespace.forwardRef((props, ref) => {
317
- return React3__namespace.createElement("RCTView", { ...props, ref });
318
- });
319
- LeanViewComponent.displayName = "RCTView";
320
- var LeanView = reactNative.Platform.OS === "android" || reactNative.Platform.OS === "ios" ? LeanViewComponent : reactNative.View;
321
-
322
- // src/Separator.tsx
323
- function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
324
- const [lastItemKeys] = useArr$(["lastItemKeys"]);
325
- const isALastItem = lastItemKeys.includes(itemKey);
326
- return isALastItem ? null : /* @__PURE__ */ React.createElement(ItemSeparatorComponent, { leadingItem });
327
- }
328
-
329
- // src/constants.ts
330
- var POSITION_OUT_OF_VIEW = -1e7;
331
- var ENABLE_DEVMODE = __DEV__ && false;
332
- var ENABLE_DEBUG_VIEW = __DEV__ && false;
333
- var IsNewArchitecture = global.nativeFabricUIManager != null;
334
449
 
335
- // src/Container.tsx
336
- var Container = ({
450
+ // src/components/Container.tsx
451
+ var Container = typedMemo(function Container2({
337
452
  id,
338
453
  recycleItems,
339
454
  horizontal,
340
455
  getRenderedItem: getRenderedItem2,
341
456
  updateItemSize: updateItemSize2,
342
457
  ItemSeparatorComponent
343
- }) => {
458
+ }) {
344
459
  const ctx = useStateContext();
345
- const columnWrapperStyle = ctx.columnWrapperStyle;
346
- const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, extraData] = useArr$([
460
+ const { columnWrapperStyle, animatedScrollY } = ctx;
461
+ const [column = 0, data, itemKey, numColumns, extraData, isSticky, stickyOffset] = useArr$([
347
462
  `containerColumn${id}`,
348
463
  `containerItemData${id}`,
349
464
  `containerItemKey${id}`,
350
- `containerPosition${id}`,
351
465
  "numColumns",
352
- "extraData"
466
+ "extraData",
467
+ `containerSticky${id}`,
468
+ `containerStickyOffset${id}`
353
469
  ]);
354
470
  const refLastSize = React3.useRef();
355
471
  const ref = React3.useRef(null);
@@ -357,47 +473,54 @@ var Container = ({
357
473
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
358
474
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
359
475
  let didLayout = false;
360
- let paddingStyles;
361
- if (columnWrapperStyle) {
362
- const { columnGap, rowGap, gap } = columnWrapperStyle;
363
- if (horizontal) {
364
- paddingStyles = {
365
- paddingRight: columnGap || gap || void 0,
366
- paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
367
- };
368
- } else {
369
- paddingStyles = {
370
- paddingBottom: rowGap || gap || void 0,
371
- paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
372
- };
476
+ const style = React3.useMemo(() => {
477
+ let paddingStyles;
478
+ if (columnWrapperStyle) {
479
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
480
+ if (horizontal) {
481
+ paddingStyles = {
482
+ paddingRight: columnGap || gap || void 0,
483
+ paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
484
+ };
485
+ } else {
486
+ paddingStyles = {
487
+ paddingBottom: rowGap || gap || void 0,
488
+ paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
489
+ };
490
+ }
373
491
  }
374
- }
375
- const style = horizontal ? {
376
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
377
- position: "absolute",
378
- top: otherAxisPos,
379
- height: otherAxisSize,
380
- left: position,
381
- ...paddingStyles || {}
382
- } : {
383
- position: "absolute",
384
- left: otherAxisPos,
385
- right: numColumns > 1 ? null : 0,
386
- width: otherAxisSize,
387
- top: position,
388
- ...paddingStyles || {}
389
- };
492
+ return horizontal ? {
493
+ flexDirection: ItemSeparatorComponent ? "row" : void 0,
494
+ height: otherAxisSize,
495
+ left: 0,
496
+ position: "absolute",
497
+ top: otherAxisPos,
498
+ ...paddingStyles || {}
499
+ } : {
500
+ left: otherAxisPos,
501
+ position: "absolute",
502
+ right: numColumns > 1 ? null : 0,
503
+ top: 0,
504
+ width: otherAxisSize,
505
+ ...paddingStyles || {}
506
+ };
507
+ }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
390
508
  const renderedItemInfo = React3.useMemo(
391
509
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
392
510
  [itemKey, data, extraData]
393
511
  );
394
512
  const { index, renderedItem } = renderedItemInfo || {};
395
- const triggerLayout = React3.useCallback(() => {
396
- forceLayoutRender((v) => v + 1);
397
- }, []);
398
513
  const contextValue = React3.useMemo(() => {
399
514
  ctx.viewRefs.set(id, ref);
400
- return { containerId: id, itemKey, index, value: data, triggerLayout };
515
+ return {
516
+ containerId: id,
517
+ index,
518
+ itemKey,
519
+ triggerLayout: () => {
520
+ forceLayoutRender((v) => v + 1);
521
+ },
522
+ value: data
523
+ };
401
524
  }, [id, itemKey, index, data]);
402
525
  const onLayout = (event) => {
403
526
  var _a, _b;
@@ -406,14 +529,14 @@ var Container = ({
406
529
  let layout = event.nativeEvent.layout;
407
530
  const size = layout[horizontal ? "width" : "height"];
408
531
  const doUpdate = () => {
409
- refLastSize.current = { width: layout.width, height: layout.height };
532
+ refLastSize.current = { height: layout.height, width: layout.width };
410
533
  updateItemSize2(itemKey, layout);
411
534
  };
412
535
  if (IsNewArchitecture || size > 0) {
413
536
  doUpdate();
414
537
  } else {
415
- (_b = (_a = ref.current) == null ? void 0 : _a.measure) == null ? void 0 : _b.call(_a, (x, y, width, height) => {
416
- layout = { width, height };
538
+ (_b = (_a = ref.current) == null ? void 0 : _a.measure) == null ? void 0 : _b.call(_a, (_x, _y, width, height) => {
539
+ layout = { height, width };
417
540
  doUpdate();
418
541
  });
419
542
  }
@@ -446,59 +569,32 @@ var Container = ({
446
569
  }
447
570
  }, [itemKey]);
448
571
  }
449
- return /* @__PURE__ */ React3__namespace.createElement(LeanView, { style, onLayout, ref, key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React3__namespace.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3__namespace.createElement(
450
- Separator,
572
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView3;
573
+ return /* @__PURE__ */ React3__namespace.createElement(
574
+ PositionComponent,
451
575
  {
452
- itemKey,
453
- ItemSeparatorComponent,
454
- leadingItem: renderedItemInfo.item
455
- }
456
- )));
457
- };
458
- var typedForwardRef = React3.forwardRef;
459
- var typedMemo = React3.memo;
460
- var useAnimatedValue = (initialValue) => {
461
- return React3.useRef(new reactNative.Animated.Value(initialValue)).current;
462
- };
463
-
464
- // src/useValue$.ts
465
- function useValue$(key, params) {
466
- var _a;
467
- const { getValue, delay } = params || {};
468
- const ctx = useStateContext();
469
- const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
470
- React3.useMemo(() => {
471
- let newValue = void 0;
472
- let prevValue = void 0;
473
- let didQueueTask = false;
474
- listen$(ctx, key, (v) => {
475
- newValue = getValue ? getValue(v) : v;
476
- if (delay !== void 0) {
477
- const fn = () => {
478
- didQueueTask = false;
479
- if (newValue !== void 0) {
480
- animValue.setValue(newValue);
481
- }
482
- };
483
- const delayValue = typeof delay === "function" ? delay(newValue, prevValue) : delay;
484
- prevValue = newValue;
485
- if (!didQueueTask) {
486
- didQueueTask = true;
487
- if (delayValue === 0) {
488
- queueMicrotask(fn);
489
- } else {
490
- setTimeout(fn, delayValue);
491
- }
492
- }
493
- } else {
494
- animValue.setValue(newValue);
576
+ animatedScrollY: isSticky ? animatedScrollY : void 0,
577
+ horizontal,
578
+ id,
579
+ index,
580
+ key: recycleItems ? void 0 : itemKey,
581
+ onLayout,
582
+ refView: ref,
583
+ stickyOffset: isSticky ? stickyOffset : void 0,
584
+ style
585
+ },
586
+ /* @__PURE__ */ React3__namespace.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3__namespace.createElement(
587
+ Separator,
588
+ {
589
+ ItemSeparatorComponent,
590
+ itemKey,
591
+ leadingItem: renderedItemInfo.item
495
592
  }
496
- });
497
- }, []);
498
- return animValue;
499
- }
593
+ ))
594
+ );
595
+ });
500
596
 
501
- // src/Containers.tsx
597
+ // src/components/Containers.tsx
502
598
  var Containers = typedMemo(function Containers2({
503
599
  horizontal,
504
600
  recycleItems,
@@ -522,18 +618,18 @@ var Containers = typedMemo(function Containers2({
522
618
  /* @__PURE__ */ React3__namespace.createElement(
523
619
  Container,
524
620
  {
621
+ getRenderedItem: getRenderedItem2,
622
+ horizontal,
623
+ ItemSeparatorComponent,
525
624
  id: i,
526
625
  key: i,
527
626
  recycleItems,
528
- horizontal,
529
- getRenderedItem: getRenderedItem2,
530
- updateItemSize: updateItemSize2,
531
- ItemSeparatorComponent
627
+ updateItemSize: updateItemSize2
532
628
  }
533
629
  )
534
630
  );
535
631
  }
536
- const style = horizontal ? { width: animSize, opacity: animOpacity, minHeight: otherAxisSize } : { height: animSize, opacity: animOpacity, minWidth: otherAxisSize };
632
+ const style = horizontal ? { minHeight: otherAxisSize, opacity: animOpacity, width: animSize } : { height: animSize, minWidth: otherAxisSize, opacity: animOpacity };
537
633
  if (columnWrapperStyle && numColumns > 1) {
538
634
  const { columnGap, rowGap, gap } = columnWrapperStyle;
539
635
  const gapX = columnGap || gap || 0;
@@ -564,15 +660,21 @@ function ScrollAdjust() {
564
660
  reactNative.View,
565
661
  {
566
662
  style: {
567
- position: "absolute",
568
663
  height: 0,
569
- width: 0,
664
+ left: 0,
665
+ position: "absolute",
570
666
  top: scrollOffset,
571
- left: 0
667
+ width: 0
572
668
  }
573
669
  }
574
670
  );
575
671
  }
672
+
673
+ // src/components/SnapWrapper.tsx
674
+ function SnapWrapper({ ScrollComponent, ...props }) {
675
+ const [snapToOffsets] = useArr$(["snapToOffsets"]);
676
+ return /* @__PURE__ */ React.createElement(ScrollComponent, { ...props, snapToOffsets });
677
+ }
576
678
  function useSyncLayout({
577
679
  onChange
578
680
  }) {
@@ -583,17 +685,19 @@ function useSyncLayout({
583
685
  },
584
686
  [onChange]
585
687
  );
586
- React3.useLayoutEffect(() => {
587
- if (ref.current) {
588
- ref.current.measure((x, y, width, height) => {
589
- onChange({ x, y, width, height }, true);
590
- });
591
- }
592
- }, []);
688
+ if (IsNewArchitecture) {
689
+ React3.useLayoutEffect(() => {
690
+ if (ref.current) {
691
+ ref.current.measure((x, y, width, height) => {
692
+ onChange({ height, width, x, y }, true);
693
+ });
694
+ }
695
+ }, []);
696
+ }
593
697
  return { onLayout, ref };
594
698
  }
595
699
 
596
- // src/ListComponent.tsx
700
+ // src/components/ListComponent.tsx
597
701
  var getComponent = (Component) => {
598
702
  if (React3__namespace.isValidElement(Component)) {
599
703
  return Component;
@@ -613,12 +717,12 @@ var PaddingDevMode = () => {
613
717
  reactNative.Animated.View,
614
718
  {
615
719
  style: {
616
- position: "absolute",
617
- top: 0,
720
+ backgroundColor: "green",
618
721
  height: animPaddingTop,
619
722
  left: 0,
723
+ position: "absolute",
620
724
  right: 0,
621
- backgroundColor: "green"
725
+ top: 0
622
726
  }
623
727
  }
624
728
  ));
@@ -647,6 +751,8 @@ var ListComponent = typedMemo(function ListComponent2({
647
751
  renderScrollComponent,
648
752
  scrollAdjustHandler,
649
753
  onLayoutHeader,
754
+ snapToIndices,
755
+ stickyIndices,
650
756
  ...rest
651
757
  }) {
652
758
  const ctx = useStateContext();
@@ -656,7 +762,7 @@ var ListComponent = typedMemo(function ListComponent2({
656
762
  const ScrollComponent = renderScrollComponent ? React3.useMemo(
657
763
  () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
658
764
  [renderScrollComponent]
659
- ) : reactNative.ScrollView;
765
+ ) : reactNative.Animated.ScrollView;
660
766
  React3__namespace.useEffect(() => {
661
767
  if (canRender) {
662
768
  setTimeout(() => {
@@ -664,76 +770,73 @@ var ListComponent = typedMemo(function ListComponent2({
664
770
  }, 0);
665
771
  }
666
772
  }, [canRender]);
773
+ const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
667
774
  return /* @__PURE__ */ React3__namespace.createElement(
668
- ScrollComponent,
775
+ SnapOrScroll,
669
776
  {
670
777
  ...rest,
671
- style,
672
- maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
673
778
  contentContainerStyle: [
674
779
  contentContainerStyle,
675
780
  horizontal ? {
676
781
  height: "100%"
677
782
  } : {}
678
783
  ],
679
- onScroll: onScroll2,
680
- onLayout,
681
- horizontal,
682
784
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
683
- ref: refScrollView
785
+ horizontal,
786
+ maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
787
+ onLayout,
788
+ onScroll: onScroll2,
789
+ ref: refScrollView,
790
+ ScrollComponent: snapToIndices ? ScrollComponent : void 0,
791
+ style
684
792
  },
685
793
  maintainVisibleContentPosition && /* @__PURE__ */ React3__namespace.createElement(ScrollAdjust, null),
686
794
  ENABLE_DEVMODE ? /* @__PURE__ */ React3__namespace.createElement(PaddingDevMode, null) : /* @__PURE__ */ React3__namespace.createElement(Padding, null),
687
- ListHeaderComponent && /* @__PURE__ */ React3__namespace.createElement(reactNative.View, { style: ListHeaderComponentStyle, onLayout: onLayoutHeaderSync, ref: refHeader }, getComponent(ListHeaderComponent)),
795
+ ListHeaderComponent && /* @__PURE__ */ React3__namespace.createElement(reactNative.View, { onLayout: onLayoutHeaderSync, ref: refHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
688
796
  ListEmptyComponent && getComponent(ListEmptyComponent),
689
797
  canRender && /* @__PURE__ */ React3__namespace.createElement(
690
798
  Containers,
691
799
  {
692
- horizontal,
693
- recycleItems,
694
- waitForInitialLayout,
695
800
  getRenderedItem: getRenderedItem2,
801
+ horizontal,
696
802
  ItemSeparatorComponent,
697
- updateItemSize: updateItemSize2
803
+ recycleItems,
804
+ updateItemSize: updateItemSize2,
805
+ waitForInitialLayout
698
806
  }
699
807
  ),
700
808
  ListFooterComponent && /* @__PURE__ */ React3__namespace.createElement(
701
809
  reactNative.View,
702
810
  {
703
- style: ListFooterComponentStyle,
704
811
  onLayout: (event) => {
705
812
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
706
813
  set$(ctx, "footerSize", size);
707
- }
814
+ },
815
+ style: ListFooterComponentStyle
708
816
  },
709
817
  getComponent(ListFooterComponent)
710
- )
818
+ ),
819
+ __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React3__namespace.createElement(DevNumbers, null)
711
820
  );
712
821
  });
822
+ var DevNumbers = __DEV__ && React3__namespace.memo(function DevNumbers2() {
823
+ return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3__namespace.createElement(
824
+ reactNative.View,
825
+ {
826
+ key: index,
827
+ style: {
828
+ height: 100,
829
+ pointerEvents: "none",
830
+ position: "absolute",
831
+ top: index * 100,
832
+ width: "100%"
833
+ }
834
+ },
835
+ /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, { style: { color: "red" } }, index * 100)
836
+ ));
837
+ });
713
838
 
714
- // src/ScrollAdjustHandler.ts
715
- var ScrollAdjustHandler = class {
716
- constructor(ctx) {
717
- this.appliedAdjust = 0;
718
- this.mounted = false;
719
- this.context = ctx;
720
- }
721
- requestAdjust(add) {
722
- const oldAdjustTop = peek$(this.context, "scrollAdjust") || 0;
723
- this.appliedAdjust = add + oldAdjustTop;
724
- const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
725
- if (this.mounted) {
726
- set();
727
- } else {
728
- requestAnimationFrame(set);
729
- }
730
- }
731
- setMounted() {
732
- this.mounted = true;
733
- }
734
- };
735
-
736
- // src/getId.ts
839
+ // src/utils/getId.ts
737
840
  function getId(state, index) {
738
841
  const { data, keyExtractor } = state.props;
739
842
  if (!data) {
@@ -745,7 +848,7 @@ function getId(state, index) {
745
848
  return id;
746
849
  }
747
850
 
748
- // src/calculateOffsetForIndex.ts
851
+ // src/core/calculateOffsetForIndex.ts
749
852
  function calculateOffsetForIndex(ctx, state, index) {
750
853
  let position = 0;
751
854
  if (index !== void 0) {
@@ -762,21 +865,37 @@ function calculateOffsetForIndex(ctx, state, index) {
762
865
  return position;
763
866
  }
764
867
 
765
- // src/getItemSize.ts
766
- function getItemSize(state, key, index, data, useAverageSize) {
868
+ // src/utils/getItemSize.ts
869
+ function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize) {
870
+ var _a, _b;
767
871
  const {
768
872
  sizesKnown,
769
873
  sizes,
770
874
  scrollingTo,
771
- props: { estimatedItemSize, getEstimatedItemSize }
875
+ averageSizes,
876
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
772
877
  } = state;
773
878
  const sizeKnown = sizesKnown.get(key);
774
879
  if (sizeKnown !== void 0) {
775
880
  return sizeKnown;
776
881
  }
777
882
  let size;
778
- if (IsNewArchitecture && useAverageSize !== void 0 && sizeKnown === void 0 && !getEstimatedItemSize && !scrollingTo) {
779
- size = useAverageSize;
883
+ const itemType = getItemType ? (_a = getItemType(data, index)) != null ? _a : "" : "";
884
+ if (getFixedItemSize) {
885
+ size = getFixedItemSize(index, data, itemType);
886
+ if (size !== void 0) {
887
+ sizesKnown.set(key, size);
888
+ }
889
+ }
890
+ if (size === void 0 && useAverageSize && sizeKnown === void 0 && !scrollingTo) {
891
+ if (itemType === "") {
892
+ size = defaultAverageSize;
893
+ } else {
894
+ const averageSizeForType = (_b = averageSizes[itemType]) == null ? void 0 : _b.avg;
895
+ if (averageSizeForType !== void 0) {
896
+ size = roundSize(averageSizeForType);
897
+ }
898
+ }
780
899
  }
781
900
  if (size === void 0) {
782
901
  size = sizes.get(key);
@@ -785,13 +904,13 @@ function getItemSize(state, key, index, data, useAverageSize) {
785
904
  }
786
905
  }
787
906
  if (size === void 0) {
788
- size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
907
+ size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
789
908
  }
790
909
  sizes.set(key, size);
791
910
  return size;
792
911
  }
793
912
 
794
- // src/calculateOffsetWithOffsetPosition.ts
913
+ // src/core/calculateOffsetWithOffsetPosition.ts
795
914
  function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
796
915
  const { index, viewOffset, viewPosition } = params;
797
916
  let offset = offsetParam;
@@ -804,127 +923,38 @@ function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
804
923
  return offset;
805
924
  }
806
925
 
807
- // src/checkAllSizesKnown.ts
808
- function checkAllSizesKnown(state) {
809
- const { startBuffered, endBuffered, sizesKnown } = state;
810
- if (endBuffered !== null) {
811
- let areAllKnown = true;
812
- for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
813
- const key = getId(state, i);
814
- areAllKnown && (areAllKnown = sizesKnown.has(key));
815
- }
816
- return areAllKnown;
926
+ // src/core/finishScrollTo.ts
927
+ var finishScrollTo = (state) => {
928
+ if (state) {
929
+ state.scrollingTo = void 0;
930
+ state.scrollHistory.length = 0;
817
931
  }
818
- return false;
819
- }
932
+ };
820
933
 
821
- // src/findAvailableContainers.ts
822
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval) {
823
- const numContainers = peek$(ctx, "numContainers");
824
- const result = [];
825
- const availableContainers = [];
826
- for (let u = 0; u < numContainers; u++) {
827
- const key = peek$(ctx, `containerItemKey${u}`);
828
- let isOk = key === void 0;
829
- if (!isOk) {
830
- const index = pendingRemoval.indexOf(u);
831
- if (index !== -1) {
832
- pendingRemoval.splice(index, 1);
833
- isOk = true;
834
- }
835
- }
836
- if (isOk) {
837
- result.push(u);
838
- if (result.length >= numNeeded) {
839
- return result;
840
- }
841
- }
842
- }
843
- for (let u = 0; u < numContainers; u++) {
844
- const key = peek$(ctx, `containerItemKey${u}`);
845
- if (key === void 0) continue;
846
- const index = state.indexByKey.get(key);
847
- if (index < startBuffered) {
848
- availableContainers.push({ index: u, distance: startBuffered - index });
849
- } else if (index > endBuffered) {
850
- availableContainers.push({ index: u, distance: index - endBuffered });
851
- }
852
- }
853
- const remaining = numNeeded - result.length;
854
- if (remaining > 0) {
855
- if (availableContainers.length > 0) {
856
- if (availableContainers.length > remaining) {
857
- availableContainers.sort(comparatorByDistance);
858
- availableContainers.length = remaining;
859
- }
860
- for (const container of availableContainers) {
861
- result.push(container.index);
862
- }
863
- }
864
- const stillNeeded = numNeeded - result.length;
865
- if (stillNeeded > 0) {
866
- for (let i = 0; i < stillNeeded; i++) {
867
- result.push(numContainers + i);
868
- }
869
- if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
870
- console.warn(
871
- "[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.",
872
- {
873
- debugInfo: {
874
- numContainers,
875
- numNeeded,
876
- stillNeeded,
877
- numContainersPooled: peek$(ctx, "numContainersPooled")
878
- }
879
- }
880
- );
881
- }
882
- }
934
+ // src/core/scrollTo.ts
935
+ function scrollTo(state, params = {}) {
936
+ var _a;
937
+ const { animated } = params;
938
+ const {
939
+ refScroller,
940
+ props: { horizontal }
941
+ } = state;
942
+ const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
943
+ state.scrollHistory.length = 0;
944
+ state.scrollingTo = params;
945
+ state.scrollPending = offset;
946
+ (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
947
+ animated: !!animated,
948
+ x: horizontal ? offset : 0,
949
+ y: horizontal ? 0 : offset
950
+ });
951
+ if (!animated) {
952
+ state.scroll = offset;
953
+ setTimeout(() => finishScrollTo(state), 100);
883
954
  }
884
- return result.sort(comparatorDefault);
885
- }
886
- function comparatorByDistance(a, b) {
887
- return b.distance - a.distance;
888
955
  }
889
956
 
890
- // src/getScrollVelocity.ts
891
- var getScrollVelocity = (state) => {
892
- const { scrollHistory } = state;
893
- let velocity = 0;
894
- if (scrollHistory.length >= 1) {
895
- const newest = scrollHistory[scrollHistory.length - 1];
896
- let oldest;
897
- let start = 0;
898
- for (let i = 0; i < scrollHistory.length - 1; i++) {
899
- const entry = scrollHistory[i];
900
- const nextEntry = scrollHistory[i + 1];
901
- if (i > 0) {
902
- const prevEntry = scrollHistory[i - 1];
903
- const prevDirection = entry.scroll - prevEntry.scroll;
904
- const currentDirection = nextEntry.scroll - entry.scroll;
905
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
906
- start = i;
907
- break;
908
- }
909
- }
910
- }
911
- for (let i = start; i < scrollHistory.length - 1; i++) {
912
- const entry = scrollHistory[i];
913
- if (newest.time - entry.time <= 1e3) {
914
- oldest = entry;
915
- break;
916
- }
917
- }
918
- if (oldest) {
919
- const scrollDiff = newest.scroll - oldest.scroll;
920
- const timeDiff = newest.time - oldest.time;
921
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
922
- }
923
- }
924
- return velocity;
925
- };
926
-
927
- // src/requestAdjust.ts
957
+ // src/utils/requestAdjust.ts
928
958
  function requestAdjust(ctx, state, positionDiff) {
929
959
  if (Math.abs(positionDiff) > 0.1) {
930
960
  const doit = () => {
@@ -932,31 +962,32 @@ function requestAdjust(ctx, state, positionDiff) {
932
962
  };
933
963
  state.scroll += positionDiff;
934
964
  state.scrollForNextCalculateItemsInView = void 0;
935
- if (peek$(ctx, "containersDidLayout")) {
965
+ const didLayout = peek$(ctx, "containersDidLayout");
966
+ if (didLayout) {
936
967
  doit();
968
+ const threshold = state.scroll - positionDiff / 2;
969
+ if (!state.ignoreScrollFromMVCP) {
970
+ state.ignoreScrollFromMVCP = {};
971
+ }
972
+ if (positionDiff > 0) {
973
+ state.ignoreScrollFromMVCP.lt = threshold;
974
+ } else {
975
+ state.ignoreScrollFromMVCP.gt = threshold;
976
+ }
977
+ if (state.ignoreScrollFromMVCPTimeout) {
978
+ clearTimeout(state.ignoreScrollFromMVCPTimeout);
979
+ }
980
+ state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
981
+ state.ignoreScrollFromMVCP = void 0;
982
+ }, 100);
937
983
  } else {
938
984
  requestAnimationFrame(doit);
939
985
  }
940
- const threshold = state.scroll - positionDiff / 2;
941
- if (!state.ignoreScrollFromMVCP) {
942
- state.ignoreScrollFromMVCP = {};
943
- }
944
- if (positionDiff > 0) {
945
- state.ignoreScrollFromMVCP.lt = threshold;
946
- } else {
947
- state.ignoreScrollFromMVCP.gt = threshold;
948
- }
949
- if (state.ignoreScrollFromMVCPTimeout) {
950
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
951
- }
952
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
953
- state.ignoreScrollFromMVCP = void 0;
954
- }, 100);
955
986
  }
956
987
  }
957
988
 
958
- // src/prepareMVCP.ts
959
- function prepareMVCP(ctx, state) {
989
+ // src/core/prepareMVCP.ts
990
+ function prepareMVCP(ctx, state, dataChanged) {
960
991
  const {
961
992
  positions,
962
993
  scrollingTo,
@@ -975,159 +1006,39 @@ function prepareMVCP(ctx, state) {
975
1006
  targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
976
1007
  targetIndex = indexByKey.get(targetId);
977
1008
  }
978
- if (targetId !== void 0 && targetIndex !== void 0) {
979
- prevPosition = positions.get(targetId);
980
- }
981
- }
982
- return () => {
983
- if (targetId !== void 0 && prevPosition !== void 0) {
984
- const newPosition = positions.get(targetId);
985
- if (newPosition !== void 0) {
986
- const positionDiff = newPosition - prevPosition;
987
- if (Math.abs(positionDiff) > 0.1) {
988
- requestAdjust(ctx, state, positionDiff);
989
- }
990
- }
991
- }
992
- };
993
- }
994
-
995
- // src/checkThreshold.ts
996
- var checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
997
- const distanceAbs = Math.abs(distance);
998
- const isAtThreshold = atThreshold || distanceAbs < threshold;
999
- if (!isReached && !isBlockedByTimer) {
1000
- if (isAtThreshold) {
1001
- onReached == null ? void 0 : onReached(distance);
1002
- blockTimer == null ? void 0 : blockTimer(true);
1003
- setTimeout(() => {
1004
- blockTimer == null ? void 0 : blockTimer(false);
1005
- }, 700);
1006
- return true;
1007
- }
1008
- } else {
1009
- if (distance >= 1.3 * threshold) {
1010
- return false;
1011
- }
1012
- }
1013
- return isReached;
1014
- };
1015
-
1016
- // src/checkAtBottom.ts
1017
- function checkAtBottom(ctx, state) {
1018
- if (!state) {
1019
- return;
1020
- }
1021
- const {
1022
- queuedInitialLayout,
1023
- scrollLength,
1024
- scroll,
1025
- maintainingScrollAtEnd,
1026
- props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1027
- } = state;
1028
- const contentSize = getContentSize(ctx);
1029
- if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1030
- const distanceFromEnd = contentSize - scroll - scrollLength;
1031
- const isContentLess = contentSize < scrollLength;
1032
- state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1033
- state.isEndReached = checkThreshold(
1034
- distanceFromEnd,
1035
- isContentLess,
1036
- onEndReachedThreshold * scrollLength,
1037
- state.isEndReached,
1038
- state.endReachedBlockedByTimer,
1039
- (distance) => {
1040
- var _a, _b;
1041
- return (_b = (_a = state.props).onEndReached) == null ? void 0 : _b.call(_a, { distanceFromEnd: distance });
1042
- },
1043
- (block) => {
1044
- state.endReachedBlockedByTimer = block;
1045
- }
1046
- );
1047
- }
1048
- }
1049
-
1050
- // src/finishScrollTo.ts
1051
- var finishScrollTo = (state) => {
1052
- if (state) {
1053
- state.scrollingTo = void 0;
1054
- state.scrollHistory.length = 0;
1055
- }
1056
- };
1057
-
1058
- // src/scrollTo.ts
1059
- function scrollTo(state, params = {}) {
1060
- var _a;
1061
- const { animated } = params;
1062
- const {
1063
- refScroller,
1064
- props: { horizontal }
1065
- } = state;
1066
- const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1067
- state.scrollHistory.length = 0;
1068
- state.scrollingTo = params;
1069
- state.scrollPending = offset;
1070
- (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1071
- x: horizontal ? offset : 0,
1072
- y: horizontal ? 0 : offset,
1073
- animated: !!animated
1074
- });
1075
- if (!animated) {
1076
- state.scroll = offset;
1077
- setTimeout(() => finishScrollTo(state), 100);
1078
- }
1079
- }
1080
-
1081
- // src/scrollToIndex.ts
1082
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1083
- if (index >= state.props.data.length) {
1084
- index = state.props.data.length - 1;
1085
- } else if (index < 0) {
1086
- index = 0;
1087
- }
1088
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
1089
- const isLast = index === state.props.data.length - 1;
1090
- if (isLast && viewPosition === void 0) {
1091
- viewPosition = 1;
1092
- }
1093
- const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1094
- state.scrollForNextCalculateItemsInView = void 0;
1095
- scrollTo(state, {
1096
- offset: firstIndexScrollPostion,
1097
- animated,
1098
- index,
1099
- viewPosition: viewPosition != null ? viewPosition : 0,
1100
- viewOffset
1101
- });
1102
- }
1103
-
1104
- // src/setDidLayout.ts
1105
- function setDidLayout(ctx, state) {
1106
- const {
1107
- loadStartTime,
1108
- initialScroll,
1109
- props: { onLoad }
1110
- } = state;
1111
- state.queuedInitialLayout = true;
1112
- checkAtBottom(ctx, state);
1113
- if (!IsNewArchitecture && initialScroll) {
1114
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1115
- }
1116
- set$(ctx, "containersDidLayout", true);
1117
- if (onLoad) {
1118
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1009
+ if (targetId !== void 0 && targetIndex !== void 0) {
1010
+ prevPosition = positions.get(targetId);
1011
+ }
1119
1012
  }
1013
+ return () => {
1014
+ if (targetId !== void 0 && prevPosition !== void 0) {
1015
+ const newPosition = positions.get(targetId);
1016
+ if (newPosition !== void 0) {
1017
+ const positionDiff = newPosition - prevPosition;
1018
+ if (Math.abs(positionDiff) > 0.1) {
1019
+ if (reactNative.Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff) {
1020
+ scrollTo(state, {
1021
+ offset: state.scroll + positionDiff
1022
+ });
1023
+ } else {
1024
+ requestAdjust(ctx, state, positionDiff);
1025
+ }
1026
+ }
1027
+ }
1028
+ }
1029
+ };
1120
1030
  }
1121
1031
 
1122
- // src/setPaddingTop.ts
1123
- function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1032
+ // src/utils/setPaddingTop.ts
1033
+ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1124
1034
  if (stylePaddingTop !== void 0) {
1125
1035
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1126
1036
  if (stylePaddingTop < prevStylePaddingTop) {
1127
- const prevTotalSize = peek$(ctx, "totalSize") || 0;
1037
+ let prevTotalSize = peek$(ctx, "totalSize");
1128
1038
  set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1129
- setTimeout(() => {
1130
- set$(ctx, "totalSize", prevTotalSize);
1039
+ state.timeoutSetPaddingTop = setTimeout(() => {
1040
+ prevTotalSize = peek$(ctx, "totalSize");
1041
+ set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1131
1042
  }, 16);
1132
1043
  }
1133
1044
  set$(ctx, "stylePaddingTop", stylePaddingTop);
@@ -1137,7 +1048,7 @@ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1137
1048
  }
1138
1049
  }
1139
1050
 
1140
- // src/updateAlignItemsPaddingTop.ts
1051
+ // src/utils/updateAlignItemsPaddingTop.ts
1141
1052
  function updateAlignItemsPaddingTop(ctx, state) {
1142
1053
  const {
1143
1054
  scrollLength,
@@ -1149,11 +1060,11 @@ function updateAlignItemsPaddingTop(ctx, state) {
1149
1060
  const contentSize = getContentSize(ctx);
1150
1061
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1151
1062
  }
1152
- setPaddingTop(ctx, { alignItemsPaddingTop });
1063
+ setPaddingTop(ctx, state, { alignItemsPaddingTop });
1153
1064
  }
1154
1065
  }
1155
1066
 
1156
- // src/updateTotalSize.ts
1067
+ // src/core/updateTotalSize.ts
1157
1068
  function updateTotalSize(ctx, state) {
1158
1069
  const {
1159
1070
  positions,
@@ -1179,6 +1090,10 @@ function addTotalSize(ctx, state, key, add) {
1179
1090
  const { alignItemsAtEnd } = state.props;
1180
1091
  {
1181
1092
  state.totalSize = add;
1093
+ if (state.timeoutSetPaddingTop) {
1094
+ clearTimeout(state.timeoutSetPaddingTop);
1095
+ state.timeoutSetPaddingTop = void 0;
1096
+ }
1182
1097
  }
1183
1098
  set$(ctx, "totalSize", state.totalSize);
1184
1099
  if (alignItemsAtEnd) {
@@ -1186,10 +1101,71 @@ function addTotalSize(ctx, state, key, add) {
1186
1101
  }
1187
1102
  }
1188
1103
 
1189
- // src/updateAllPositions.ts
1104
+ // src/utils/getScrollVelocity.ts
1105
+ var getScrollVelocity = (state) => {
1106
+ const { scrollHistory } = state;
1107
+ let velocity = 0;
1108
+ if (scrollHistory.length >= 1) {
1109
+ const newest = scrollHistory[scrollHistory.length - 1];
1110
+ let oldest;
1111
+ let start = 0;
1112
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
1113
+ const entry = scrollHistory[i];
1114
+ const nextEntry = scrollHistory[i + 1];
1115
+ if (i > 0) {
1116
+ const prevEntry = scrollHistory[i - 1];
1117
+ const prevDirection = entry.scroll - prevEntry.scroll;
1118
+ const currentDirection = nextEntry.scroll - entry.scroll;
1119
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1120
+ start = i;
1121
+ break;
1122
+ }
1123
+ }
1124
+ }
1125
+ for (let i = start; i < scrollHistory.length - 1; i++) {
1126
+ const entry = scrollHistory[i];
1127
+ if (newest.time - entry.time <= 1e3) {
1128
+ oldest = entry;
1129
+ break;
1130
+ }
1131
+ }
1132
+ if (oldest) {
1133
+ const scrollDiff = newest.scroll - oldest.scroll;
1134
+ const timeDiff = newest.time - oldest.time;
1135
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1136
+ }
1137
+ }
1138
+ return velocity;
1139
+ };
1140
+
1141
+ // src/utils/updateSnapToOffsets.ts
1142
+ function updateSnapToOffsets(ctx, state) {
1143
+ const {
1144
+ positions,
1145
+ props: { snapToIndices }
1146
+ } = state;
1147
+ const snapToOffsets = Array(snapToIndices.length);
1148
+ for (let i = 0; i < snapToIndices.length; i++) {
1149
+ const idx = snapToIndices[i];
1150
+ const key = getId(state, idx);
1151
+ snapToOffsets[i] = positions.get(key);
1152
+ }
1153
+ set$(ctx, "snapToOffsets", snapToOffsets);
1154
+ }
1155
+
1156
+ // src/core/updateAllPositions.ts
1190
1157
  function updateAllPositions(ctx, state, dataChanged) {
1191
1158
  var _a, _b, _c, _d, _e;
1192
- const { averageSizes, columns, indexByKey, positions, firstFullyOnScreenIndex, idCache, sizesKnown } = state;
1159
+ const {
1160
+ averageSizes,
1161
+ columns,
1162
+ indexByKey,
1163
+ positions,
1164
+ firstFullyOnScreenIndex,
1165
+ idCache,
1166
+ sizesKnown,
1167
+ props: { getEstimatedItemSize, snapToIndices }
1168
+ } = state;
1193
1169
  const data = state.props.data;
1194
1170
  const numColumns = peek$(ctx, "numColumns");
1195
1171
  const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
@@ -1198,6 +1174,7 @@ function updateAllPositions(ctx, state, dataChanged) {
1198
1174
  indexByKey.clear();
1199
1175
  idCache.clear();
1200
1176
  }
1177
+ const useAverageSize = !getEstimatedItemSize;
1201
1178
  const itemType = "";
1202
1179
  let averageSize = (_a = averageSizes[itemType]) == null ? void 0 : _a.avg;
1203
1180
  if (averageSize !== void 0) {
@@ -1213,7 +1190,7 @@ function updateAllPositions(ctx, state, dataChanged) {
1213
1190
  let bailout = false;
1214
1191
  for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1215
1192
  const id = (_b = idCache.get(i)) != null ? _b : getId(state, i);
1216
- const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(state, id, i, data[i], averageSize);
1193
+ const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(state, id, i, data[i], useAverageSize, averageSize);
1217
1194
  const itemColumn = columns.get(id);
1218
1195
  maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1219
1196
  if (itemColumn === 1) {
@@ -1240,7 +1217,7 @@ function updateAllPositions(ctx, state, dataChanged) {
1240
1217
  const dataLength = data.length;
1241
1218
  for (let i = 0; i < dataLength; i++) {
1242
1219
  const id = (_d = idCache.get(i)) != null ? _d : getId(state, i);
1243
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(state, id, i, data[i], averageSize);
1220
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(state, id, i, data[i], useAverageSize, averageSize);
1244
1221
  if (__DEV__ && needsIndexByKey) {
1245
1222
  if (indexByKeyForChecking.has(id)) {
1246
1223
  console.error(
@@ -1269,9 +1246,12 @@ function updateAllPositions(ctx, state, dataChanged) {
1269
1246
  }
1270
1247
  }
1271
1248
  updateTotalSize(ctx, state);
1249
+ if (snapToIndices) {
1250
+ updateSnapToOffsets(ctx, state);
1251
+ }
1272
1252
  }
1273
1253
 
1274
- // src/viewability.ts
1254
+ // src/core/viewability.ts
1275
1255
  var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
1276
1256
  function setupViewability(props) {
1277
1257
  let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
@@ -1279,27 +1259,31 @@ function setupViewability(props) {
1279
1259
  viewabilityConfigCallbackPairs = [
1280
1260
  ...viewabilityConfigCallbackPairs || [],
1281
1261
  {
1262
+ onViewableItemsChanged,
1282
1263
  viewabilityConfig: viewabilityConfig || {
1283
1264
  viewAreaCoveragePercentThreshold: 0
1284
- },
1285
- onViewableItemsChanged
1265
+ }
1286
1266
  }
1287
1267
  ];
1288
1268
  }
1289
1269
  if (viewabilityConfigCallbackPairs) {
1290
1270
  for (const pair of viewabilityConfigCallbackPairs) {
1291
1271
  mapViewabilityConfigCallbackPairs.set(pair.viewabilityConfig.id, {
1292
- viewableItems: [],
1293
- start: -1,
1294
1272
  end: -1,
1273
+ previousEnd: -1,
1295
1274
  previousStart: -1,
1296
- previousEnd: -1
1275
+ start: -1,
1276
+ viewableItems: []
1297
1277
  });
1298
1278
  }
1299
1279
  }
1300
1280
  return viewabilityConfigCallbackPairs;
1301
1281
  }
1302
1282
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
1283
+ const {
1284
+ timeouts,
1285
+ props: { data }
1286
+ } = state;
1303
1287
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
1304
1288
  const viewabilityState = mapViewabilityConfigCallbackPairs.get(
1305
1289
  viewabilityConfigCallbackPair.viewabilityConfig.id
@@ -1308,12 +1292,12 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollS
1308
1292
  viewabilityState.end = end;
1309
1293
  if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
1310
1294
  const timer = setTimeout(() => {
1311
- state.timeouts.delete(timer);
1312
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
1295
+ timeouts.delete(timer);
1296
+ updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
1313
1297
  }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
1314
- state.timeouts.add(timer);
1298
+ timeouts.add(timer);
1315
1299
  } else {
1316
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
1300
+ updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
1317
1301
  }
1318
1302
  }
1319
1303
  }
@@ -1365,11 +1349,11 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1365
1349
  const containerId = findContainerId(ctx, key);
1366
1350
  if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1367
1351
  const viewToken = {
1368
- item,
1369
- key,
1352
+ containerId,
1370
1353
  index: i,
1371
1354
  isViewable: true,
1372
- containerId
1355
+ item,
1356
+ key
1373
1357
  };
1374
1358
  viewableItems.push(viewToken);
1375
1359
  if (!(previousViewableItems == null ? void 0 : previousViewableItems.find((v) => v.key === viewToken.key))) {
@@ -1379,9 +1363,9 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1379
1363
  }
1380
1364
  }
1381
1365
  Object.assign(viewabilityState, {
1382
- viewableItems,
1366
+ previousEnd: end,
1383
1367
  previousStart: start,
1384
- previousEnd: end
1368
+ viewableItems
1385
1369
  });
1386
1370
  if (changed.length > 0) {
1387
1371
  viewabilityState.viewableItems = viewableItems;
@@ -1390,7 +1374,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1390
1374
  maybeUpdateViewabilityCallback(ctx, configId, change.containerId, change);
1391
1375
  }
1392
1376
  if (onViewableItemsChanged) {
1393
- onViewableItemsChanged({ viewableItems, changed });
1377
+ onViewableItemsChanged({ changed, viewableItems });
1394
1378
  }
1395
1379
  }
1396
1380
  for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
@@ -1416,360 +1400,656 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1416
1400
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
1417
1401
  const isViewable2 = percent >= viewablePercentThreshold;
1418
1402
  const value = {
1403
+ containerId,
1419
1404
  index,
1420
1405
  isViewable: isViewable2,
1421
1406
  item,
1422
1407
  key,
1423
- percentVisible,
1424
1408
  percentOfScroller,
1425
- sizeVisible,
1426
- size,
1409
+ percentVisible,
1427
1410
  scrollSize,
1428
- containerId
1411
+ size,
1412
+ sizeVisible
1413
+ };
1414
+ if (JSON.stringify(value) !== JSON.stringify(ctx.mapViewabilityAmountValues.get(containerId))) {
1415
+ ctx.mapViewabilityAmountValues.set(containerId, value);
1416
+ const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
1417
+ if (cb) {
1418
+ cb(value);
1419
+ }
1420
+ }
1421
+ return value;
1422
+ }
1423
+ function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
1424
+ const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
1425
+ return value.isViewable;
1426
+ }
1427
+ function findContainerId(ctx, key) {
1428
+ const numContainers = peek$(ctx, "numContainers");
1429
+ for (let i = 0; i < numContainers; i++) {
1430
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
1431
+ if (itemKey === key) {
1432
+ return i;
1433
+ }
1434
+ }
1435
+ return -1;
1436
+ }
1437
+ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1438
+ const key = containerId + configId;
1439
+ ctx.mapViewabilityValues.set(key, viewToken);
1440
+ const cb = ctx.mapViewabilityCallbacks.get(key);
1441
+ cb == null ? void 0 : cb(viewToken);
1442
+ }
1443
+
1444
+ // src/utils/checkAllSizesKnown.ts
1445
+ function checkAllSizesKnown(state) {
1446
+ const { startBuffered, endBuffered, sizesKnown } = state;
1447
+ if (endBuffered !== null) {
1448
+ let areAllKnown = true;
1449
+ for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1450
+ const key = getId(state, i);
1451
+ areAllKnown && (areAllKnown = sizesKnown.has(key));
1452
+ }
1453
+ return areAllKnown;
1454
+ }
1455
+ return false;
1456
+ }
1457
+
1458
+ // src/utils/findAvailableContainers.ts
1459
+ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
1460
+ const numContainers = peek$(ctx, "numContainers");
1461
+ const { stickyIndicesSet } = state.props;
1462
+ const result = [];
1463
+ const availableContainers = [];
1464
+ const stickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => stickyIndicesSet.has(index))) || [];
1465
+ const nonStickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => !stickyIndicesSet.has(index))) || [];
1466
+ const canReuseContainer = (containerIndex, requiredType) => {
1467
+ if (!requiredType) return true;
1468
+ const existingType = state.containerItemTypes.get(containerIndex);
1469
+ if (!existingType) return true;
1470
+ return existingType === requiredType;
1471
+ };
1472
+ const neededTypes = requiredItemTypes ? [...requiredItemTypes] : [];
1473
+ let typeIndex = 0;
1474
+ for (let i = 0; i < stickyItemIndices.length; i++) {
1475
+ const requiredType = neededTypes[typeIndex];
1476
+ let foundContainer = false;
1477
+ for (const containerIndex of state.stickyContainerPool) {
1478
+ const key = peek$(ctx, `containerItemKey${containerIndex}`);
1479
+ const isPendingRemoval = pendingRemoval.includes(containerIndex);
1480
+ if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
1481
+ result.push(containerIndex);
1482
+ if (isPendingRemoval) {
1483
+ const index = pendingRemoval.indexOf(containerIndex);
1484
+ pendingRemoval.splice(index, 1);
1485
+ }
1486
+ foundContainer = true;
1487
+ if (requiredItemTypes) typeIndex++;
1488
+ break;
1489
+ }
1490
+ }
1491
+ if (!foundContainer) {
1492
+ const newContainerIndex = numContainers + result.filter((index) => index >= numContainers).length;
1493
+ result.push(newContainerIndex);
1494
+ state.stickyContainerPool.add(newContainerIndex);
1495
+ if (requiredItemTypes) typeIndex++;
1496
+ }
1497
+ }
1498
+ if (nonStickyItemIndices.length > 0) {
1499
+ for (let u = 0; u < numContainers; u++) {
1500
+ if (state.stickyContainerPool.has(u)) {
1501
+ continue;
1502
+ }
1503
+ const key = peek$(ctx, `containerItemKey${u}`);
1504
+ let isOk = key === void 0;
1505
+ if (!isOk) {
1506
+ const index = pendingRemoval.indexOf(u);
1507
+ if (index !== -1) {
1508
+ pendingRemoval.splice(index, 1);
1509
+ const requiredType = neededTypes[typeIndex];
1510
+ isOk = canReuseContainer(u, requiredType);
1511
+ }
1512
+ }
1513
+ if (isOk) {
1514
+ result.push(u);
1515
+ if (requiredItemTypes) {
1516
+ typeIndex++;
1517
+ }
1518
+ if (result.length >= numNeeded) {
1519
+ return result;
1520
+ }
1521
+ }
1522
+ }
1523
+ }
1524
+ for (let u = 0; u < numContainers; u++) {
1525
+ if (state.stickyContainerPool.has(u)) {
1526
+ continue;
1527
+ }
1528
+ const key = peek$(ctx, `containerItemKey${u}`);
1529
+ if (key === void 0) continue;
1530
+ const index = state.indexByKey.get(key);
1531
+ const isOutOfView = index < startBuffered || index > endBuffered;
1532
+ if (isOutOfView) {
1533
+ const distance = index < startBuffered ? startBuffered - index : index - endBuffered;
1534
+ if (!requiredItemTypes || typeIndex < neededTypes.length && canReuseContainer(u, neededTypes[typeIndex])) {
1535
+ availableContainers.push({ distance, index: u });
1536
+ }
1537
+ }
1538
+ }
1539
+ const remaining = numNeeded - result.length;
1540
+ if (remaining > 0) {
1541
+ if (availableContainers.length > 0) {
1542
+ if (availableContainers.length > remaining) {
1543
+ availableContainers.sort(comparatorByDistance);
1544
+ availableContainers.length = remaining;
1545
+ }
1546
+ for (const container of availableContainers) {
1547
+ result.push(container.index);
1548
+ if (requiredItemTypes) {
1549
+ typeIndex++;
1550
+ }
1551
+ }
1552
+ }
1553
+ const stillNeeded = numNeeded - result.length;
1554
+ if (stillNeeded > 0) {
1555
+ for (let i = 0; i < stillNeeded; i++) {
1556
+ result.push(numContainers + i);
1557
+ }
1558
+ if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1559
+ console.warn(
1560
+ "[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.",
1561
+ {
1562
+ debugInfo: {
1563
+ numContainers,
1564
+ numContainersPooled: peek$(ctx, "numContainersPooled"),
1565
+ numNeeded,
1566
+ stillNeeded
1567
+ }
1568
+ }
1569
+ );
1570
+ }
1571
+ }
1572
+ }
1573
+ return result.sort(comparatorDefault);
1574
+ }
1575
+ function comparatorByDistance(a, b) {
1576
+ return b.distance - a.distance;
1577
+ }
1578
+
1579
+ // src/core/scrollToIndex.ts
1580
+ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1581
+ if (index >= state.props.data.length) {
1582
+ index = state.props.data.length - 1;
1583
+ } else if (index < 0) {
1584
+ index = 0;
1585
+ }
1586
+ const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
1587
+ const isLast = index === state.props.data.length - 1;
1588
+ if (isLast && viewPosition === void 0) {
1589
+ viewPosition = 1;
1590
+ }
1591
+ const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1592
+ state.scrollForNextCalculateItemsInView = void 0;
1593
+ scrollTo(state, {
1594
+ animated,
1595
+ index,
1596
+ offset: firstIndexScrollPostion,
1597
+ viewOffset,
1598
+ viewPosition: viewPosition != null ? viewPosition : 0
1599
+ });
1600
+ }
1601
+
1602
+ // src/utils/checkThreshold.ts
1603
+ var checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1604
+ const distanceAbs = Math.abs(distance);
1605
+ const isAtThreshold = atThreshold || distanceAbs < threshold;
1606
+ if (!isReached && !isBlockedByTimer) {
1607
+ if (isAtThreshold) {
1608
+ onReached == null ? void 0 : onReached(distance);
1609
+ blockTimer == null ? void 0 : blockTimer(true);
1610
+ setTimeout(() => {
1611
+ blockTimer == null ? void 0 : blockTimer(false);
1612
+ }, 700);
1613
+ return true;
1614
+ }
1615
+ } else {
1616
+ if (distance >= 1.3 * threshold) {
1617
+ return false;
1618
+ }
1619
+ }
1620
+ return isReached;
1621
+ };
1622
+
1623
+ // src/utils/checkAtBottom.ts
1624
+ function checkAtBottom(ctx, state) {
1625
+ if (!state) {
1626
+ return;
1627
+ }
1628
+ const {
1629
+ queuedInitialLayout,
1630
+ scrollLength,
1631
+ scroll,
1632
+ maintainingScrollAtEnd,
1633
+ props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1634
+ } = state;
1635
+ const contentSize = getContentSize(ctx);
1636
+ if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1637
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1638
+ const isContentLess = contentSize < scrollLength;
1639
+ state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1640
+ state.isEndReached = checkThreshold(
1641
+ distanceFromEnd,
1642
+ isContentLess,
1643
+ onEndReachedThreshold * scrollLength,
1644
+ state.isEndReached,
1645
+ state.endReachedBlockedByTimer,
1646
+ (distance) => {
1647
+ var _a, _b;
1648
+ return (_b = (_a = state.props).onEndReached) == null ? void 0 : _b.call(_a, { distanceFromEnd: distance });
1649
+ },
1650
+ (block) => {
1651
+ state.endReachedBlockedByTimer = block;
1652
+ }
1653
+ );
1654
+ }
1655
+ }
1656
+
1657
+ // src/utils/setDidLayout.ts
1658
+ function setDidLayout(ctx, state) {
1659
+ const {
1660
+ loadStartTime,
1661
+ initialScroll,
1662
+ props: { onLoad }
1663
+ } = state;
1664
+ state.queuedInitialLayout = true;
1665
+ checkAtBottom(ctx, state);
1666
+ const setIt = () => {
1667
+ set$(ctx, "containersDidLayout", true);
1668
+ if (onLoad) {
1669
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1670
+ }
1429
1671
  };
1430
- if (JSON.stringify(value) !== JSON.stringify(ctx.mapViewabilityAmountValues.get(containerId))) {
1431
- ctx.mapViewabilityAmountValues.set(containerId, value);
1432
- const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
1433
- if (cb) {
1434
- cb(value);
1672
+ if (reactNative.Platform.OS === "android" || !IsNewArchitecture) {
1673
+ if (initialScroll) {
1674
+ queueMicrotask(() => {
1675
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1676
+ requestAnimationFrame(() => {
1677
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1678
+ setIt();
1679
+ });
1680
+ });
1681
+ } else {
1682
+ queueMicrotask(setIt);
1435
1683
  }
1684
+ } else {
1685
+ setIt();
1436
1686
  }
1437
- return value;
1438
- }
1439
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
1440
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
1441
- return value.isViewable;
1442
1687
  }
1443
- function findContainerId(ctx, key) {
1444
- const numContainers = peek$(ctx, "numContainers");
1445
- for (let i = 0; i < numContainers; i++) {
1446
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1447
- if (itemKey === key) {
1688
+
1689
+ // src/core/calculateItemsInView.ts
1690
+ function findCurrentStickyIndex(stickyArray, scroll, state) {
1691
+ var _a;
1692
+ for (let i = stickyArray.length - 1; i >= 0; i--) {
1693
+ const stickyId = (_a = state.idCache.get(stickyArray[i])) != null ? _a : getId(state, stickyArray[i]);
1694
+ const stickyPos = stickyId ? state.positions.get(stickyId) : void 0;
1695
+ if (stickyPos !== void 0 && scroll >= stickyPos) {
1448
1696
  return i;
1449
1697
  }
1450
1698
  }
1451
1699
  return -1;
1452
1700
  }
1453
- function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1454
- const key = containerId + configId;
1455
- ctx.mapViewabilityValues.set(key, viewToken);
1456
- const cb = ctx.mapViewabilityCallbacks.get(key);
1457
- cb == null ? void 0 : cb(viewToken);
1701
+ function getActiveStickyIndices(ctx, state, stickyIndices) {
1702
+ return new Set(
1703
+ Array.from(state.stickyContainerPool).map((i) => peek$(ctx, `containerItemKey${i}`)).map((key) => key ? state.indexByKey.get(key) : void 0).filter((idx) => idx !== void 0 && stickyIndices.has(idx))
1704
+ );
1458
1705
  }
1459
-
1460
- // src/calculateItemsInView.ts
1461
- function calculateItemsInView(ctx, state, params = {}) {
1462
- var _a, _b, _c, _d, _e, _f, _g, _h;
1463
- const {
1464
- scrollLength,
1465
- startBufferedId: startBufferedIdOrig,
1466
- positions,
1467
- columns,
1468
- containerItemKeys,
1469
- idCache,
1470
- sizes,
1471
- indexByKey,
1472
- scrollForNextCalculateItemsInView,
1473
- enableScrollForNextCalculateItemsInView,
1474
- minIndexSizeChanged
1475
- } = state;
1476
- const data = state.props.data;
1477
- if (!data || scrollLength === 0) {
1478
- return;
1479
- }
1480
- const totalSize = peek$(ctx, "totalSize");
1481
- const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1482
- const numColumns = peek$(ctx, "numColumns");
1483
- const previousScrollAdjust = 0;
1484
- const { dataChanged, doMVCP } = params;
1485
- const speed = getScrollVelocity(state);
1486
- if (doMVCP || dataChanged) {
1487
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state) : void 0;
1488
- updateAllPositions(ctx, state, dataChanged);
1489
- checkMVCP == null ? void 0 : checkMVCP();
1490
- }
1491
- const scrollExtra = 0;
1492
- const { queuedInitialLayout } = state;
1493
- let { scroll: scrollState } = state;
1494
- const initialScroll = state.props.initialScroll;
1495
- if (!queuedInitialLayout && initialScroll) {
1496
- const updatedOffset = calculateOffsetWithOffsetPosition(
1497
- state,
1498
- calculateOffsetForIndex(ctx, state, initialScroll.index),
1499
- initialScroll
1500
- );
1501
- scrollState = updatedOffset;
1502
- }
1503
- const scrollAdjustPad = -previousScrollAdjust - topPad;
1504
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
1505
- if (scroll + scrollLength > totalSize) {
1506
- scroll = totalSize - scrollLength;
1507
- }
1508
- if (ENABLE_DEBUG_VIEW) {
1509
- set$(ctx, "debugRawScroll", scrollState);
1510
- set$(ctx, "debugComputedScroll", scroll);
1511
- }
1512
- const scrollBuffer = state.props.scrollBuffer;
1513
- let scrollBufferTop = scrollBuffer;
1514
- let scrollBufferBottom = scrollBuffer;
1515
- if (speed > 0) {
1516
- scrollBufferTop = scrollBuffer * 0.5;
1517
- scrollBufferBottom = scrollBuffer * 1.5;
1518
- } else {
1519
- scrollBufferTop = scrollBuffer * 1.5;
1520
- scrollBufferBottom = scrollBuffer * 0.5;
1521
- }
1522
- const scrollTopBuffered = scroll - scrollBufferTop;
1523
- const scrollBottom = scroll + scrollLength;
1524
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
1525
- if (scrollForNextCalculateItemsInView) {
1526
- const { top, bottom } = scrollForNextCalculateItemsInView;
1527
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
1528
- return;
1706
+ function handleStickyActivation(ctx, state, stickyIndices, stickyArray, scroll, needNewContainers, startBuffered, endBuffered) {
1707
+ var _a;
1708
+ const activeIndices = getActiveStickyIndices(ctx, state, stickyIndices);
1709
+ const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1710
+ for (let offset = 0; offset <= 1; offset++) {
1711
+ const idx = currentStickyIdx - offset;
1712
+ if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
1713
+ const stickyIndex = stickyArray[idx];
1714
+ const stickyId = (_a = state.idCache.get(stickyIndex)) != null ? _a : getId(state, stickyIndex);
1715
+ if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
1716
+ needNewContainers.push(stickyIndex);
1529
1717
  }
1530
1718
  }
1531
- let startNoBuffer = null;
1532
- let startBuffered = null;
1533
- let startBufferedId = null;
1534
- let endNoBuffer = null;
1535
- let endBuffered = null;
1536
- let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1537
- if (minIndexSizeChanged !== void 0) {
1538
- loopStart = Math.min(minIndexSizeChanged, loopStart);
1539
- state.minIndexSizeChanged = void 0;
1540
- }
1541
- for (let i = loopStart; i >= 0; i--) {
1542
- const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1543
- const top = positions.get(id);
1544
- const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
1545
- const bottom = top + size;
1546
- if (bottom > scroll - scrollBuffer) {
1547
- loopStart = i;
1719
+ }
1720
+ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pendingRemoval) {
1721
+ var _a, _b, _c;
1722
+ const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1723
+ for (const containerIndex of state.stickyContainerPool) {
1724
+ const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
1725
+ const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
1726
+ if (itemIndex === void 0) continue;
1727
+ const arrayIdx = stickyArray.indexOf(itemIndex);
1728
+ if (arrayIdx === -1) continue;
1729
+ const isRecentSticky = arrayIdx >= currentStickyIdx - 1 && arrayIdx <= currentStickyIdx + 1;
1730
+ if (isRecentSticky) continue;
1731
+ const nextIndex = stickyArray[arrayIdx + 1];
1732
+ let shouldRecycle = false;
1733
+ if (nextIndex) {
1734
+ const nextId = (_a = state.idCache.get(nextIndex)) != null ? _a : getId(state, nextIndex);
1735
+ const nextPos = nextId ? state.positions.get(nextId) : void 0;
1736
+ shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
1548
1737
  } else {
1549
- break;
1738
+ const currentId = (_b = state.idCache.get(itemIndex)) != null ? _b : getId(state, itemIndex);
1739
+ if (currentId) {
1740
+ const currentPos = state.positions.get(currentId);
1741
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(state, currentId, itemIndex, state.props.data[itemIndex]);
1742
+ shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
1743
+ }
1550
1744
  }
1551
- }
1552
- const loopStartMod = loopStart % numColumns;
1553
- if (loopStartMod > 0) {
1554
- loopStart -= loopStartMod;
1555
- }
1556
- let foundEnd = false;
1557
- let nextTop;
1558
- let nextBottom;
1559
- const prevNumContainers = ctx.values.get("numContainers");
1560
- let maxIndexRendered = 0;
1561
- for (let i = 0; i < prevNumContainers; i++) {
1562
- const key = peek$(ctx, `containerItemKey${i}`);
1563
- if (key !== void 0) {
1564
- const index = indexByKey.get(key);
1565
- maxIndexRendered = Math.max(maxIndexRendered, index);
1745
+ if (shouldRecycle) {
1746
+ pendingRemoval.push(containerIndex);
1566
1747
  }
1567
1748
  }
1568
- let firstFullyOnScreenIndex;
1569
- const dataLength = data.length;
1570
- for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
1571
- const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
1572
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
1573
- const top = positions.get(id);
1574
- if (!foundEnd) {
1575
- if (startNoBuffer === null && top + size > scroll) {
1576
- startNoBuffer = i;
1577
- }
1578
- if (firstFullyOnScreenIndex === void 0 && top >= scroll - 10) {
1579
- firstFullyOnScreenIndex = i;
1580
- }
1581
- if (startBuffered === null && top + size > scrollTopBuffered) {
1582
- startBuffered = i;
1583
- startBufferedId = id;
1584
- nextTop = top;
1585
- }
1586
- if (startNoBuffer !== null) {
1587
- if (top <= scrollBottom) {
1588
- endNoBuffer = i;
1589
- }
1590
- if (top <= scrollBottomBuffered) {
1591
- endBuffered = i;
1592
- nextBottom = top + size;
1593
- } else {
1594
- foundEnd = true;
1595
- }
1749
+ }
1750
+ function calculateItemsInView(ctx, state, params = {}) {
1751
+ reactNative.unstable_batchedUpdates(() => {
1752
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1753
+ const {
1754
+ scrollLength,
1755
+ startBufferedId: startBufferedIdOrig,
1756
+ positions,
1757
+ columns,
1758
+ containerItemKeys,
1759
+ idCache,
1760
+ sizes,
1761
+ indexByKey,
1762
+ scrollForNextCalculateItemsInView,
1763
+ enableScrollForNextCalculateItemsInView,
1764
+ minIndexSizeChanged
1765
+ } = state;
1766
+ const { data, stickyIndicesArr, stickyIndicesSet } = state.props;
1767
+ const prevNumContainers = peek$(ctx, "numContainers");
1768
+ if (!data || scrollLength === 0 || !prevNumContainers) {
1769
+ return;
1770
+ }
1771
+ const totalSize = peek$(ctx, "totalSize");
1772
+ const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1773
+ const numColumns = peek$(ctx, "numColumns");
1774
+ const previousScrollAdjust = 0;
1775
+ const { dataChanged, doMVCP } = params;
1776
+ const speed = getScrollVelocity(state);
1777
+ if (doMVCP || dataChanged) {
1778
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
1779
+ updateAllPositions(ctx, state, dataChanged);
1780
+ checkMVCP == null ? void 0 : checkMVCP();
1781
+ }
1782
+ const scrollExtra = 0;
1783
+ const { queuedInitialLayout } = state;
1784
+ let { scroll: scrollState } = state;
1785
+ const initialScroll = state.props.initialScroll;
1786
+ if (!queuedInitialLayout && initialScroll) {
1787
+ const updatedOffset = calculateOffsetWithOffsetPosition(
1788
+ state,
1789
+ calculateOffsetForIndex(ctx, state, initialScroll.index),
1790
+ initialScroll
1791
+ );
1792
+ scrollState = updatedOffset;
1793
+ }
1794
+ const scrollAdjustPad = -previousScrollAdjust - topPad;
1795
+ let scroll = scrollState + scrollExtra + scrollAdjustPad;
1796
+ if (scroll + scrollLength > totalSize) {
1797
+ scroll = totalSize - scrollLength;
1798
+ }
1799
+ if (ENABLE_DEBUG_VIEW) {
1800
+ set$(ctx, "debugRawScroll", scrollState);
1801
+ set$(ctx, "debugComputedScroll", scroll);
1802
+ }
1803
+ const scrollBuffer = state.props.scrollBuffer;
1804
+ let scrollBufferTop = scrollBuffer;
1805
+ let scrollBufferBottom = scrollBuffer;
1806
+ if (speed > 0) {
1807
+ scrollBufferTop = scrollBuffer * 0.5;
1808
+ scrollBufferBottom = scrollBuffer * 1.5;
1809
+ } else {
1810
+ scrollBufferTop = scrollBuffer * 1.5;
1811
+ scrollBufferBottom = scrollBuffer * 0.5;
1812
+ }
1813
+ const scrollTopBuffered = scroll - scrollBufferTop;
1814
+ const scrollBottom = scroll + scrollLength;
1815
+ const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
1816
+ if (scrollForNextCalculateItemsInView) {
1817
+ const { top, bottom } = scrollForNextCalculateItemsInView;
1818
+ if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
1819
+ return;
1596
1820
  }
1597
1821
  }
1598
- }
1599
- const idsInView = [];
1600
- for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
1601
- const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
1602
- idsInView.push(id);
1603
- }
1604
- Object.assign(state, {
1605
- startBuffered,
1606
- startBufferedId,
1607
- startNoBuffer,
1608
- endBuffered,
1609
- endNoBuffer,
1610
- idsInView,
1611
- firstFullyOnScreenIndex
1612
- });
1613
- if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
1614
- state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
1615
- top: nextTop,
1616
- bottom: nextBottom
1617
- } : void 0;
1618
- }
1619
- const numContainers = peek$(ctx, "numContainers");
1620
- const pendingRemoval = [];
1621
- if (dataChanged) {
1622
- for (let i = 0; i < numContainers; i++) {
1623
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1624
- if (!state.props.keyExtractor || itemKey && indexByKey.get(itemKey) === void 0) {
1625
- pendingRemoval.push(i);
1822
+ let startNoBuffer = null;
1823
+ let startBuffered = null;
1824
+ let startBufferedId = null;
1825
+ let endNoBuffer = null;
1826
+ let endBuffered = null;
1827
+ let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1828
+ if (minIndexSizeChanged !== void 0) {
1829
+ loopStart = Math.min(minIndexSizeChanged, loopStart);
1830
+ state.minIndexSizeChanged = void 0;
1831
+ }
1832
+ for (let i = loopStart; i >= 0; i--) {
1833
+ const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1834
+ const top = positions.get(id);
1835
+ const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
1836
+ const bottom = top + size;
1837
+ if (bottom > scroll - scrollBuffer) {
1838
+ loopStart = i;
1839
+ } else {
1840
+ break;
1626
1841
  }
1627
1842
  }
1628
- }
1629
- if (startBuffered !== null && endBuffered !== null) {
1630
- let numContainers2 = prevNumContainers;
1631
- const needNewContainers = [];
1632
- for (let i = startBuffered; i <= endBuffered; i++) {
1633
- const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
1634
- if (!containerItemKeys.has(id)) {
1635
- needNewContainers.push(i);
1843
+ const loopStartMod = loopStart % numColumns;
1844
+ if (loopStartMod > 0) {
1845
+ loopStart -= loopStartMod;
1846
+ }
1847
+ let foundEnd = false;
1848
+ let nextTop;
1849
+ let nextBottom;
1850
+ let maxIndexRendered = 0;
1851
+ for (let i = 0; i < prevNumContainers; i++) {
1852
+ const key = peek$(ctx, `containerItemKey${i}`);
1853
+ if (key !== void 0) {
1854
+ const index = indexByKey.get(key);
1855
+ maxIndexRendered = Math.max(maxIndexRendered, index);
1636
1856
  }
1637
1857
  }
1638
- if (needNewContainers.length > 0) {
1639
- const availableContainers = findAvailableContainers(
1640
- ctx,
1641
- state,
1642
- needNewContainers.length,
1643
- startBuffered,
1644
- endBuffered,
1645
- pendingRemoval
1646
- );
1647
- for (let idx = 0; idx < needNewContainers.length; idx++) {
1648
- const i = needNewContainers[idx];
1649
- const containerIndex = availableContainers[idx];
1650
- const id = (_g = idCache.get(i)) != null ? _g : getId(state, i);
1651
- const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
1652
- if (oldKey && oldKey !== id) {
1653
- containerItemKeys.delete(oldKey);
1858
+ let firstFullyOnScreenIndex;
1859
+ const dataLength = data.length;
1860
+ for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
1861
+ const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
1862
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
1863
+ const top = positions.get(id);
1864
+ if (!foundEnd) {
1865
+ if (startNoBuffer === null && top + size > scroll) {
1866
+ startNoBuffer = i;
1654
1867
  }
1655
- set$(ctx, `containerItemKey${containerIndex}`, id);
1656
- set$(ctx, `containerItemData${containerIndex}`, data[i]);
1657
- containerItemKeys.add(id);
1658
- if (containerIndex >= numContainers2) {
1659
- numContainers2 = containerIndex + 1;
1868
+ if (firstFullyOnScreenIndex === void 0 && top >= scroll - 10) {
1869
+ firstFullyOnScreenIndex = i;
1870
+ }
1871
+ if (startBuffered === null && top + size > scrollTopBuffered) {
1872
+ startBuffered = i;
1873
+ startBufferedId = id;
1874
+ nextTop = top;
1875
+ }
1876
+ if (startNoBuffer !== null) {
1877
+ if (top <= scrollBottom) {
1878
+ endNoBuffer = i;
1879
+ }
1880
+ if (top <= scrollBottomBuffered) {
1881
+ endBuffered = i;
1882
+ nextBottom = top + size;
1883
+ } else {
1884
+ foundEnd = true;
1885
+ }
1660
1886
  }
1661
1887
  }
1662
- if (numContainers2 !== prevNumContainers) {
1663
- set$(ctx, "numContainers", numContainers2);
1664
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
1665
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
1888
+ }
1889
+ const idsInView = [];
1890
+ for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
1891
+ const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
1892
+ idsInView.push(id);
1893
+ }
1894
+ Object.assign(state, {
1895
+ endBuffered,
1896
+ endNoBuffer,
1897
+ firstFullyOnScreenIndex,
1898
+ idsInView,
1899
+ startBuffered,
1900
+ startBufferedId,
1901
+ startNoBuffer
1902
+ });
1903
+ if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
1904
+ state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
1905
+ bottom: nextBottom,
1906
+ top: nextTop
1907
+ } : void 0;
1908
+ }
1909
+ const numContainers = peek$(ctx, "numContainers");
1910
+ const pendingRemoval = [];
1911
+ if (dataChanged) {
1912
+ for (let i = 0; i < numContainers; i++) {
1913
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
1914
+ if (!state.props.keyExtractor || itemKey && indexByKey.get(itemKey) === void 0) {
1915
+ pendingRemoval.push(i);
1666
1916
  }
1667
1917
  }
1668
1918
  }
1669
- }
1670
- for (let i = 0; i < numContainers; i++) {
1671
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1672
- if (pendingRemoval.includes(i)) {
1673
- if (itemKey) {
1674
- containerItemKeys.delete(itemKey);
1919
+ if (startBuffered !== null && endBuffered !== null) {
1920
+ let numContainers2 = prevNumContainers;
1921
+ const needNewContainers = [];
1922
+ for (let i = startBuffered; i <= endBuffered; i++) {
1923
+ const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
1924
+ if (!containerItemKeys.has(id)) {
1925
+ needNewContainers.push(i);
1926
+ }
1675
1927
  }
1676
- set$(ctx, `containerItemKey${i}`, void 0);
1677
- set$(ctx, `containerItemData${i}`, void 0);
1678
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1679
- set$(ctx, `containerColumn${i}`, -1);
1680
- } else {
1681
- const itemIndex = indexByKey.get(itemKey);
1682
- const item = data[itemIndex];
1683
- if (item !== void 0) {
1684
- const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
1685
- const position = positions.get(id);
1686
- if (position === void 0) {
1687
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1688
- } else {
1689
- const pos = positions.get(id);
1690
- const column = columns.get(id) || 1;
1691
- const prevPos = peek$(ctx, `containerPosition${i}`);
1692
- const prevColumn = peek$(ctx, `containerColumn${i}`);
1693
- const prevData = peek$(ctx, `containerItemData${i}`);
1694
- if (!prevPos || pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
1695
- set$(ctx, `containerPosition${i}`, pos);
1928
+ if (stickyIndicesArr.length > 0) {
1929
+ handleStickyActivation(ctx, state, stickyIndicesSet, stickyIndicesArr, scroll, needNewContainers, startBuffered, endBuffered);
1930
+ }
1931
+ if (needNewContainers.length > 0) {
1932
+ const requiredItemTypes = state.props.getItemType ? needNewContainers.map((i) => {
1933
+ const itemType = state.props.getItemType(data[i], i);
1934
+ return itemType ? String(itemType) : "";
1935
+ }) : void 0;
1936
+ const availableContainers = findAvailableContainers(
1937
+ ctx,
1938
+ state,
1939
+ needNewContainers.length,
1940
+ startBuffered,
1941
+ endBuffered,
1942
+ pendingRemoval,
1943
+ requiredItemTypes,
1944
+ needNewContainers
1945
+ );
1946
+ for (let idx = 0; idx < needNewContainers.length; idx++) {
1947
+ const i = needNewContainers[idx];
1948
+ const containerIndex = availableContainers[idx];
1949
+ const id = (_g = idCache.get(i)) != null ? _g : getId(state, i);
1950
+ const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
1951
+ if (oldKey && oldKey !== id) {
1952
+ containerItemKeys.delete(oldKey);
1953
+ }
1954
+ set$(ctx, `containerItemKey${containerIndex}`, id);
1955
+ set$(ctx, `containerItemData${containerIndex}`, data[i]);
1956
+ if (requiredItemTypes) {
1957
+ state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
1958
+ }
1959
+ containerItemKeys.add(id);
1960
+ if (stickyIndicesSet.has(i)) {
1961
+ set$(ctx, `containerSticky${containerIndex}`, true);
1962
+ const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
1963
+ set$(ctx, `containerStickyOffset${containerIndex}`, new reactNative.Animated.Value(topPadding));
1964
+ state.stickyContainerPool.add(containerIndex);
1965
+ } else {
1966
+ state.stickyContainerPool.delete(containerIndex);
1696
1967
  }
1697
- if (column >= 0 && column !== prevColumn) {
1698
- set$(ctx, `containerColumn${i}`, column);
1968
+ if (containerIndex >= numContainers2) {
1969
+ numContainers2 = containerIndex + 1;
1699
1970
  }
1700
- if (prevData !== item) {
1701
- set$(ctx, `containerItemData${i}`, data[itemIndex]);
1971
+ }
1972
+ if (numContainers2 !== prevNumContainers) {
1973
+ set$(ctx, "numContainers", numContainers2);
1974
+ if (numContainers2 > peek$(ctx, "numContainersPooled")) {
1975
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
1702
1976
  }
1703
1977
  }
1704
1978
  }
1705
1979
  }
1706
- }
1707
- if (!queuedInitialLayout && endBuffered !== null) {
1708
- if (checkAllSizesKnown(state)) {
1709
- setDidLayout(ctx, state);
1980
+ if (stickyIndicesArr.length > 0) {
1981
+ handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, pendingRemoval);
1710
1982
  }
1711
- }
1712
- if (state.props.viewabilityConfigCallbackPairs) {
1713
- updateViewableItems(
1714
- state,
1715
- ctx,
1716
- state.props.viewabilityConfigCallbackPairs,
1717
- scrollLength,
1718
- startNoBuffer,
1719
- endNoBuffer
1720
- );
1721
- }
1983
+ for (let i = 0; i < numContainers; i++) {
1984
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
1985
+ if (pendingRemoval.includes(i)) {
1986
+ if (itemKey) {
1987
+ containerItemKeys.delete(itemKey);
1988
+ }
1989
+ state.containerItemTypes.delete(i);
1990
+ if (state.stickyContainerPool.has(i)) {
1991
+ set$(ctx, `containerSticky${i}`, false);
1992
+ set$(ctx, `containerStickyOffset${i}`, void 0);
1993
+ state.stickyContainerPool.delete(i);
1994
+ }
1995
+ set$(ctx, `containerItemKey${i}`, void 0);
1996
+ set$(ctx, `containerItemData${i}`, void 0);
1997
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1998
+ set$(ctx, `containerColumn${i}`, -1);
1999
+ } else {
2000
+ const itemIndex = indexByKey.get(itemKey);
2001
+ const item = data[itemIndex];
2002
+ if (item !== void 0) {
2003
+ const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
2004
+ const position = positions.get(id);
2005
+ if (position === void 0) {
2006
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2007
+ } else {
2008
+ const column = columns.get(id) || 1;
2009
+ const prevPos = peek$(ctx, `containerPosition${i}`);
2010
+ const prevColumn = peek$(ctx, `containerColumn${i}`);
2011
+ const prevData = peek$(ctx, `containerItemData${i}`);
2012
+ if (position > POSITION_OUT_OF_VIEW && position !== prevPos) {
2013
+ set$(ctx, `containerPosition${i}`, position);
2014
+ }
2015
+ if (column >= 0 && column !== prevColumn) {
2016
+ set$(ctx, `containerColumn${i}`, column);
2017
+ }
2018
+ if (prevData !== item) {
2019
+ set$(ctx, `containerItemData${i}`, data[itemIndex]);
2020
+ }
2021
+ }
2022
+ }
2023
+ }
2024
+ }
2025
+ if (!queuedInitialLayout && endBuffered !== null) {
2026
+ if (checkAllSizesKnown(state)) {
2027
+ setDidLayout(ctx, state);
2028
+ }
2029
+ }
2030
+ if (state.viewabilityConfigCallbackPairs) {
2031
+ updateViewableItems(
2032
+ state,
2033
+ ctx,
2034
+ state.viewabilityConfigCallbackPairs,
2035
+ scrollLength,
2036
+ startNoBuffer,
2037
+ endNoBuffer
2038
+ );
2039
+ }
2040
+ });
1722
2041
  }
1723
2042
 
1724
- // src/checkAtTop.ts
1725
- function checkAtTop(state) {
1726
- if (!state) {
1727
- return;
1728
- }
2043
+ // src/core/doInitialAllocateContainers.ts
2044
+ function doInitialAllocateContainers(ctx, state) {
2045
+ var _a;
1729
2046
  const {
1730
2047
  scrollLength,
1731
- scroll,
1732
- props: { onStartReachedThreshold }
2048
+ props: { getItemType }
1733
2049
  } = state;
1734
- const distanceFromTop = scroll;
1735
- state.isAtStart = distanceFromTop <= 0;
1736
- state.isStartReached = checkThreshold(
1737
- distanceFromTop,
1738
- false,
1739
- onStartReachedThreshold * scrollLength,
1740
- state.isStartReached,
1741
- state.startReachedBlockedByTimer,
1742
- (distance) => {
1743
- var _a, _b;
1744
- return (_b = (_a = state.props).onStartReached) == null ? void 0 : _b.call(_a, { distanceFromStart: distance });
1745
- },
1746
- (block) => {
1747
- state.startReachedBlockedByTimer = block;
1748
- }
1749
- );
1750
- }
1751
-
1752
- // src/createColumnWrapperStyle.ts
1753
- function createColumnWrapperStyle(contentContainerStyle) {
1754
- const { gap, columnGap, rowGap } = contentContainerStyle;
1755
- if (gap || columnGap || rowGap) {
1756
- contentContainerStyle.gap = void 0;
1757
- contentContainerStyle.columnGap = void 0;
1758
- contentContainerStyle.rowGap = void 0;
1759
- return {
1760
- gap,
1761
- columnGap,
1762
- rowGap
1763
- };
1764
- }
1765
- }
1766
-
1767
- // src/doInitialAllocateContainers.ts
1768
- function doInitialAllocateContainers(ctx, state) {
1769
- const { scrollLength } = state;
1770
2050
  const data = state.props.data;
1771
2051
  if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1772
- const averageItemSize = state.props.getEstimatedItemSize ? state.props.getEstimatedItemSize(0, data[0]) : state.props.estimatedItemSize;
2052
+ const averageItemSize = state.props.getEstimatedItemSize ? state.props.getEstimatedItemSize(0, data[0], getItemType ? (_a = getItemType(data[0], 0)) != null ? _a : "" : "") : state.props.estimatedItemSize;
1773
2053
  const Extra = 1.5;
1774
2054
  const numContainers = Math.ceil(
1775
2055
  (scrollLength + state.props.scrollBuffer * 2) / averageItemSize * state.props.numColumns * Extra
@@ -1793,7 +2073,7 @@ function doInitialAllocateContainers(ctx, state) {
1793
2073
  }
1794
2074
  }
1795
2075
 
1796
- // src/doMaintainScrollAtEnd.ts
2076
+ // src/core/doMaintainScrollAtEnd.ts
1797
2077
  function doMaintainScrollAtEnd(ctx, state, animated) {
1798
2078
  const {
1799
2079
  refScroller,
@@ -1806,48 +2086,58 @@ function doMaintainScrollAtEnd(ctx, state, animated) {
1806
2086
  }
1807
2087
  requestAnimationFrame(() => {
1808
2088
  var _a;
1809
- state.maintainingScrollAtEnd = true;
1810
- (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
1811
- animated
1812
- });
1813
- setTimeout(
1814
- () => {
1815
- state.maintainingScrollAtEnd = false;
1816
- },
1817
- 0
1818
- );
2089
+ if (state == null ? void 0 : state.isAtEnd) {
2090
+ state.maintainingScrollAtEnd = true;
2091
+ (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
2092
+ animated
2093
+ });
2094
+ setTimeout(
2095
+ () => {
2096
+ state.maintainingScrollAtEnd = false;
2097
+ },
2098
+ 0
2099
+ );
2100
+ }
1819
2101
  });
1820
2102
  return true;
1821
2103
  }
1822
2104
  }
1823
- function getRenderedItem(ctx, state, key) {
2105
+
2106
+ // src/utils/checkAtTop.ts
2107
+ function checkAtTop(state) {
1824
2108
  if (!state) {
1825
- return null;
2109
+ return;
1826
2110
  }
1827
2111
  const {
1828
- indexByKey,
1829
- props: { data, renderItem: renderItem2 }
2112
+ scrollLength,
2113
+ scroll,
2114
+ props: { onStartReachedThreshold }
1830
2115
  } = state;
1831
- const index = indexByKey.get(key);
1832
- if (index === void 0) {
1833
- return null;
1834
- }
1835
- let renderedItem = null;
1836
- if (renderItem2) {
1837
- const itemProps = {
1838
- item: data[index],
1839
- index,
1840
- extraData: peek$(ctx, "extraData")
1841
- };
1842
- renderedItem = React3__namespace.default.createElement(renderItem2, itemProps);
1843
- }
1844
- return { index, item: data[index], renderedItem };
2116
+ const distanceFromTop = scroll;
2117
+ state.isAtStart = distanceFromTop <= 0;
2118
+ state.isStartReached = checkThreshold(
2119
+ distanceFromTop,
2120
+ false,
2121
+ onStartReachedThreshold * scrollLength,
2122
+ state.isStartReached,
2123
+ state.startReachedBlockedByTimer,
2124
+ (distance) => {
2125
+ var _a, _b;
2126
+ return (_b = (_a = state.props).onStartReached) == null ? void 0 : _b.call(_a, { distanceFromStart: distance });
2127
+ },
2128
+ (block) => {
2129
+ state.startReachedBlockedByTimer = block;
2130
+ }
2131
+ );
1845
2132
  }
1846
2133
 
1847
- // src/handleLayout.ts
1848
- function handleLayout(ctx, state, size, setCanRender) {
1849
- const scrollLength = size[state.props.horizontal ? "width" : "height"];
1850
- const otherAxisSize = size[state.props.horizontal ? "height" : "width"];
2134
+ // src/core/handleLayout.ts
2135
+ function handleLayout(ctx, state, layout, setCanRender) {
2136
+ const { maintainScrollAtEnd } = state.props;
2137
+ const scrollLength = layout[state.props.horizontal ? "width" : "height"];
2138
+ const otherAxisSize = layout[state.props.horizontal ? "height" : "width"];
2139
+ const needsCalculate = !state.lastLayout || scrollLength > state.scrollLength || state.lastLayout.x !== layout.x || state.lastLayout.y !== layout.y;
2140
+ state.lastLayout = layout;
1851
2141
  const didChange = scrollLength !== state.scrollLength;
1852
2142
  const prevOtherAxisSize = state.otherAxisSize;
1853
2143
  state.scrollLength = scrollLength;
@@ -1855,13 +2145,15 @@ function handleLayout(ctx, state, size, setCanRender) {
1855
2145
  state.lastBatchingAction = Date.now();
1856
2146
  state.scrollForNextCalculateItemsInView = void 0;
1857
2147
  doInitialAllocateContainers(ctx, state);
1858
- if (didChange) {
2148
+ if (needsCalculate) {
1859
2149
  calculateItemsInView(ctx, state, { doMVCP: true });
1860
2150
  }
1861
2151
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
1862
- set$(ctx, "scrollSize", { width: size.width, height: size.height });
2152
+ set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2153
+ }
2154
+ if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2155
+ doMaintainScrollAtEnd(ctx, state, false);
1863
2156
  }
1864
- doMaintainScrollAtEnd(ctx, state, false);
1865
2157
  updateAlignItemsPaddingTop(ctx, state);
1866
2158
  checkAtBottom(ctx, state);
1867
2159
  checkAtTop(state);
@@ -1874,11 +2166,10 @@ function handleLayout(ctx, state, size, setCanRender) {
1874
2166
  `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.`
1875
2167
  );
1876
2168
  }
1877
- calculateItemsInView(ctx, state, { doMVCP: true });
1878
2169
  setCanRender(true);
1879
2170
  }
1880
2171
 
1881
- // src/onScroll.ts
2172
+ // src/core/onScroll.ts
1882
2173
  function onScroll(ctx, state, event) {
1883
2174
  var _a, _b, _c, _d, _e;
1884
2175
  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) {
@@ -1916,14 +2207,44 @@ function updateScroll(ctx, state, newScroll) {
1916
2207
  checkAtTop(state);
1917
2208
  }
1918
2209
 
1919
- // src/updateItemSize.ts
2210
+ // src/core/ScrollAdjustHandler.ts
2211
+ var ScrollAdjustHandler = class {
2212
+ constructor(ctx) {
2213
+ this.appliedAdjust = 0;
2214
+ this.mounted = false;
2215
+ this.context = ctx;
2216
+ }
2217
+ requestAdjust(add) {
2218
+ const oldAdjustTop = peek$(this.context, "scrollAdjust") || 0;
2219
+ this.appliedAdjust = add + oldAdjustTop;
2220
+ const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
2221
+ if (this.mounted) {
2222
+ set();
2223
+ } else {
2224
+ requestAnimationFrame(set);
2225
+ }
2226
+ }
2227
+ setMounted() {
2228
+ this.mounted = true;
2229
+ }
2230
+ };
2231
+
2232
+ // src/core/updateItemSize.ts
1920
2233
  function updateItemSizes(ctx, state, itemUpdates) {
1921
2234
  var _a;
1922
2235
  const {
1923
- props: { horizontal, maintainVisibleContentPosition, suggestEstimatedItemSize, onItemSizeChanged, data }
2236
+ props: {
2237
+ horizontal,
2238
+ maintainVisibleContentPosition,
2239
+ suggestEstimatedItemSize,
2240
+ onItemSizeChanged,
2241
+ data,
2242
+ maintainScrollAtEnd
2243
+ }
1924
2244
  } = state;
1925
2245
  if (!data) return;
1926
- let needsRecalculate = false;
2246
+ const containersDidLayout = peek$(ctx, "containersDidLayout");
2247
+ let needsRecalculate = !containersDidLayout;
1927
2248
  let shouldMaintainScrollAtEnd = false;
1928
2249
  let minIndexSizeChanged;
1929
2250
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
@@ -1934,7 +2255,7 @@ function updateItemSizes(ctx, state, itemUpdates) {
1934
2255
  const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
1935
2256
  if (diff !== 0) {
1936
2257
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
1937
- if (((_a = state.scrollingTo) == null ? void 0 : _a.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index) {
2258
+ if (((_a = state.scrollingTo) == null ? void 0 : _a.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index && diff > 0) {
1938
2259
  requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
1939
2260
  }
1940
2261
  const { startBuffered, endBuffered } = state;
@@ -1956,11 +2277,11 @@ function updateItemSizes(ctx, state, itemUpdates) {
1956
2277
  shouldMaintainScrollAtEnd = true;
1957
2278
  }
1958
2279
  onItemSizeChanged == null ? void 0 : onItemSizeChanged({
1959
- size,
1960
- previous: size - diff,
1961
2280
  index,
2281
+ itemData: state.props.data[index],
1962
2282
  itemKey,
1963
- itemData: state.props.data[index]
2283
+ previous: size - diff,
2284
+ size
1964
2285
  });
1965
2286
  }
1966
2287
  }
@@ -1983,64 +2304,73 @@ function updateItemSizes(ctx, state, itemUpdates) {
1983
2304
  if (!cur || maxOtherAxisSize > cur) {
1984
2305
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
1985
2306
  }
1986
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1987
2307
  if (containersDidLayout || checkAllSizesKnown(state)) {
1988
2308
  if (needsRecalculate) {
1989
2309
  state.scrollForNextCalculateItemsInView = void 0;
1990
2310
  calculateItemsInView(ctx, state, { doMVCP: true });
1991
2311
  }
1992
2312
  if (shouldMaintainScrollAtEnd) {
1993
- doMaintainScrollAtEnd(ctx, state, false);
2313
+ if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2314
+ doMaintainScrollAtEnd(ctx, state, false);
2315
+ }
1994
2316
  }
1995
2317
  }
1996
2318
  }
1997
2319
  function updateItemSize(ctx, state, itemKey, sizeObj) {
1998
- var _a, _b;
1999
- if (IsNewArchitecture) {
2000
- const { sizesKnown } = state;
2001
- const numContainers = ctx.values.get("numContainers");
2002
- const changes = [];
2003
- for (let i = 0; i < numContainers; i++) {
2004
- const containerItemKey = peek$(ctx, `containerItemKey${i}`);
2005
- if (itemKey === containerItemKey) {
2006
- changes.push({ itemKey, sizeObj });
2007
- } else if (!sizesKnown.has(containerItemKey) && containerItemKey !== void 0) {
2008
- const containerRef = ctx.viewRefs.get(i);
2009
- if (containerRef) {
2010
- const measured = (_b = (_a = containerRef.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
2011
- if (measured) {
2012
- changes.push({ itemKey: containerItemKey, sizeObj: measured });
2013
- }
2014
- }
2015
- }
2320
+ var _a;
2321
+ const {
2322
+ queuedItemSizeUpdates,
2323
+ queuedItemSizeUpdatesWaiting,
2324
+ sizesKnown,
2325
+ props: { getFixedItemSize, getItemType }
2326
+ } = state;
2327
+ if (getFixedItemSize) {
2328
+ const index = state.indexByKey.get(itemKey);
2329
+ const itemData = state.props.data[index];
2330
+ const type = getItemType ? (_a = getItemType(itemData, index)) != null ? _a : "" : "";
2331
+ const size = getFixedItemSize(index, itemData, type);
2332
+ if (size !== void 0 && size === sizesKnown.get(itemKey)) {
2333
+ return;
2016
2334
  }
2017
- if (changes.length > 0) {
2018
- updateItemSizes(ctx, state, changes);
2335
+ }
2336
+ const containersDidLayout = peek$(ctx, "containersDidLayout");
2337
+ if (!containersDidLayout || !queuedItemSizeUpdatesWaiting) {
2338
+ updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
2339
+ if (containersDidLayout) {
2340
+ state.queuedItemSizeUpdatesWaiting = true;
2341
+ requestAnimationFrame(() => {
2342
+ state.queuedItemSizeUpdatesWaiting = false;
2343
+ updateItemSizes(ctx, state, queuedItemSizeUpdates);
2344
+ queuedItemSizeUpdates.length = 0;
2345
+ });
2019
2346
  }
2020
2347
  } else {
2021
- updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
2348
+ queuedItemSizeUpdates.push({ itemKey, sizeObj });
2022
2349
  }
2023
2350
  }
2024
2351
  function updateOneItemSize(state, itemKey, sizeObj) {
2352
+ var _a;
2025
2353
  const {
2026
2354
  sizes,
2027
2355
  indexByKey,
2028
2356
  sizesKnown,
2029
2357
  averageSizes,
2030
- props: { data, horizontal }
2358
+ props: { data, horizontal, getEstimatedItemSize, getItemType }
2031
2359
  } = state;
2032
2360
  if (!data) return 0;
2033
2361
  const index = indexByKey.get(itemKey);
2034
2362
  const prevSize = getItemSize(state, itemKey, index, data);
2035
2363
  const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2036
2364
  sizesKnown.set(itemKey, size);
2037
- const itemType = "";
2038
- let averages = averageSizes[itemType];
2039
- if (!averages) {
2040
- averages = averageSizes[itemType] = { num: 0, avg: 0 };
2365
+ if (!getEstimatedItemSize) {
2366
+ const itemType = getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : "";
2367
+ let averages = averageSizes[itemType];
2368
+ if (!averages) {
2369
+ averages = averageSizes[itemType] = { avg: 0, num: 0 };
2370
+ }
2371
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2372
+ averages.num++;
2041
2373
  }
2042
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2043
- averages.num++;
2044
2374
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2045
2375
  sizes.set(itemKey, size);
2046
2376
  return size - prevSize;
@@ -2063,7 +2393,47 @@ var useCombinedRef = (...refs) => {
2063
2393
  return callback;
2064
2394
  };
2065
2395
 
2066
- // src/LegendList.tsx
2396
+ // src/utils/createColumnWrapperStyle.ts
2397
+ function createColumnWrapperStyle(contentContainerStyle) {
2398
+ const { gap, columnGap, rowGap } = contentContainerStyle;
2399
+ if (gap || columnGap || rowGap) {
2400
+ contentContainerStyle.gap = void 0;
2401
+ contentContainerStyle.columnGap = void 0;
2402
+ contentContainerStyle.rowGap = void 0;
2403
+ return {
2404
+ columnGap,
2405
+ gap,
2406
+ rowGap
2407
+ };
2408
+ }
2409
+ }
2410
+ function getRenderedItem(ctx, state, key) {
2411
+ var _a;
2412
+ if (!state) {
2413
+ return null;
2414
+ }
2415
+ const {
2416
+ indexByKey,
2417
+ props: { data, getItemType, renderItem: renderItem2 }
2418
+ } = state;
2419
+ const index = indexByKey.get(key);
2420
+ if (index === void 0) {
2421
+ return null;
2422
+ }
2423
+ let renderedItem = null;
2424
+ if (renderItem2) {
2425
+ const itemProps = {
2426
+ extraData: peek$(ctx, "extraData"),
2427
+ index,
2428
+ item: data[index],
2429
+ type: getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : ""
2430
+ };
2431
+ renderedItem = React3__namespace.default.createElement(renderItem2, itemProps);
2432
+ }
2433
+ return { index, item: data[index], renderedItem };
2434
+ }
2435
+
2436
+ // src/components/LegendList.tsx
2067
2437
  var DEFAULT_DRAW_DISTANCE = 250;
2068
2438
  var DEFAULT_ITEM_SIZE = 100;
2069
2439
  var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
@@ -2072,48 +2442,52 @@ var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
2072
2442
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
2073
2443
  var _a;
2074
2444
  const {
2445
+ alignItemsAtEnd = false,
2446
+ columnWrapperStyle,
2447
+ contentContainerStyle: contentContainerStyleProp,
2075
2448
  data: dataProp = [],
2449
+ drawDistance = 250,
2450
+ estimatedItemSize: estimatedItemSizeProp,
2451
+ estimatedListSize,
2452
+ extraData,
2453
+ getEstimatedItemSize,
2454
+ getFixedItemSize,
2455
+ getItemType,
2456
+ horizontal,
2457
+ initialContainerPoolRatio = 2,
2076
2458
  initialScrollIndex: initialScrollIndexProp,
2077
2459
  initialScrollOffset,
2078
- horizontal,
2079
- drawDistance = 250,
2080
- recycleItems = false,
2081
- onEndReachedThreshold = 0.5,
2082
- onStartReachedThreshold = 0.5,
2460
+ keyExtractor: keyExtractorProp,
2461
+ ListEmptyComponent,
2462
+ ListHeaderComponent,
2083
2463
  maintainScrollAtEnd = false,
2084
2464
  maintainScrollAtEndThreshold = 0.1,
2085
- alignItemsAtEnd = false,
2086
2465
  maintainVisibleContentPosition = false,
2087
- onScroll: onScrollProp,
2088
- onMomentumScrollEnd,
2089
2466
  numColumns: numColumnsProp = 1,
2090
- columnWrapperStyle,
2091
- keyExtractor: keyExtractorProp,
2092
- renderItem: renderItem2,
2093
- estimatedListSize,
2094
- estimatedItemSize: estimatedItemSizeProp,
2095
- getEstimatedItemSize,
2096
- suggestEstimatedItemSize,
2097
- ListHeaderComponent,
2098
- ListEmptyComponent,
2467
+ onEndReached,
2468
+ onEndReachedThreshold = 0.5,
2099
2469
  onItemSizeChanged,
2100
- refScrollView,
2101
- waitForInitialLayout = true,
2102
- extraData,
2103
- contentContainerStyle: contentContainerStyleProp,
2104
- style: styleProp,
2105
2470
  onLayout: onLayoutProp,
2471
+ onLoad,
2472
+ onMomentumScrollEnd,
2106
2473
  onRefresh,
2107
- refreshing,
2474
+ onScroll: onScrollProp,
2475
+ onStartReached,
2476
+ onStartReachedThreshold = 0.5,
2477
+ onViewableItemsChanged,
2108
2478
  progressViewOffset,
2479
+ recycleItems = false,
2109
2480
  refreshControl,
2110
- initialContainerPoolRatio = 2,
2481
+ refreshing,
2482
+ refScrollView,
2483
+ renderItem: renderItem2,
2484
+ snapToIndices,
2485
+ stickyIndices,
2486
+ style: styleProp,
2487
+ suggestEstimatedItemSize,
2111
2488
  viewabilityConfig,
2112
2489
  viewabilityConfigCallbackPairs,
2113
- onViewableItemsChanged,
2114
- onStartReached,
2115
- onEndReached,
2116
- onLoad,
2490
+ waitForInitialLayout = true,
2117
2491
  ...rest
2118
2492
  } = props;
2119
2493
  const [renderNum, setRenderNum] = React3.useState(0);
@@ -2130,54 +2504,60 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2130
2504
  const combinedRef = useCombinedRef(refScroller, refScrollView);
2131
2505
  const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
2132
2506
  const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
2133
- const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
2507
+ const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
2134
2508
  const refState = React3.useRef();
2135
2509
  if (!refState.current) {
2136
- const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { width: 0, height: 0 } : reactNative.Dimensions.get("window"))[horizontal ? "width" : "height"];
2510
+ const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : reactNative.Dimensions.get("window"))[horizontal ? "width" : "height"];
2137
2511
  refState.current = {
2138
- sizes: /* @__PURE__ */ new Map(),
2139
- positions: /* @__PURE__ */ new Map(),
2512
+ activeStickyIndex: void 0,
2513
+ averageSizes: {},
2140
2514
  columns: /* @__PURE__ */ new Map(),
2141
- pendingAdjust: 0,
2142
- isStartReached: false,
2143
- isEndReached: false,
2144
- isAtEnd: false,
2145
- isAtStart: false,
2146
- scrollLength: initialScrollLength,
2147
- startBuffered: -1,
2148
- startNoBuffer: -1,
2515
+ containerItemKeys: /* @__PURE__ */ new Set(),
2516
+ containerItemTypes: /* @__PURE__ */ new Map(),
2517
+ enableScrollForNextCalculateItemsInView: true,
2149
2518
  endBuffered: -1,
2150
2519
  endNoBuffer: -1,
2520
+ endReachedBlockedByTimer: false,
2151
2521
  firstFullyOnScreenIndex: -1,
2522
+ idCache: /* @__PURE__ */ new Map(),
2523
+ idsInView: [],
2524
+ indexByKey: /* @__PURE__ */ new Map(),
2525
+ initialScroll,
2526
+ isAtEnd: false,
2527
+ isAtStart: false,
2528
+ isEndReached: false,
2529
+ isStartReached: false,
2530
+ lastBatchingAction: Date.now(),
2531
+ lastLayout: void 0,
2532
+ loadStartTime: Date.now(),
2533
+ minIndexSizeChanged: 0,
2534
+ nativeMarginTop: 0,
2535
+ pendingAdjust: 0,
2536
+ positions: /* @__PURE__ */ new Map(),
2537
+ props: {},
2538
+ queuedCalculateItemsInView: 0,
2539
+ queuedItemSizeUpdates: [],
2540
+ refScroller: void 0,
2152
2541
  scroll: 0,
2153
- totalSize: 0,
2154
- timeouts: /* @__PURE__ */ new Set(),
2155
- viewabilityConfigCallbackPairs: void 0,
2156
2542
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
2157
- nativeMarginTop: 0,
2543
+ scrollForNextCalculateItemsInView: void 0,
2544
+ scrollHistory: [],
2545
+ scrollLength: initialScrollLength,
2546
+ scrollPending: 0,
2158
2547
  scrollPrev: 0,
2159
2548
  scrollPrevTime: 0,
2160
2549
  scrollTime: 0,
2161
- scrollPending: 0,
2162
- indexByKey: /* @__PURE__ */ new Map(),
2163
- scrollHistory: [],
2550
+ sizes: /* @__PURE__ */ new Map(),
2164
2551
  sizesKnown: /* @__PURE__ */ new Map(),
2165
- timeoutSizeMessage: 0,
2552
+ startBuffered: -1,
2553
+ startNoBuffer: -1,
2166
2554
  startReachedBlockedByTimer: false,
2167
- endReachedBlockedByTimer: false,
2168
- scrollForNextCalculateItemsInView: void 0,
2169
- enableScrollForNextCalculateItemsInView: true,
2170
- minIndexSizeChanged: 0,
2171
- queuedCalculateItemsInView: 0,
2172
- lastBatchingAction: Date.now(),
2173
- averageSizes: {},
2174
- idsInView: [],
2175
- containerItemKeys: /* @__PURE__ */ new Set(),
2176
- idCache: /* @__PURE__ */ new Map(),
2177
- props: {},
2178
- refScroller: void 0,
2179
- loadStartTime: Date.now(),
2180
- initialScroll
2555
+ stickyContainerPool: /* @__PURE__ */ new Set(),
2556
+ stickyContainers: /* @__PURE__ */ new Map(),
2557
+ timeoutSizeMessage: 0,
2558
+ timeouts: /* @__PURE__ */ new Set(),
2559
+ totalSize: 0,
2560
+ viewabilityConfigCallbackPairs: void 0
2181
2561
  };
2182
2562
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
2183
2563
  set$(ctx, "extraData", extraData);
@@ -2189,28 +2569,33 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2189
2569
  alignItemsAtEnd,
2190
2570
  data: dataProp,
2191
2571
  estimatedItemSize,
2572
+ getEstimatedItemSize,
2573
+ getFixedItemSize,
2574
+ getItemType,
2575
+ horizontal: !!horizontal,
2576
+ initialContainerPoolRatio,
2577
+ initialScroll,
2578
+ keyExtractor,
2192
2579
  maintainScrollAtEnd,
2193
2580
  maintainScrollAtEndThreshold,
2194
- onEndReachedThreshold,
2195
- onStartReachedThreshold,
2196
- stylePaddingBottom: stylePaddingBottomState,
2197
- horizontal: !!horizontal,
2198
2581
  maintainVisibleContentPosition,
2582
+ numColumns: numColumnsProp,
2583
+ onEndReached,
2584
+ onEndReachedThreshold,
2199
2585
  onItemSizeChanged,
2200
- suggestEstimatedItemSize: !!suggestEstimatedItemSize,
2201
- keyExtractor,
2586
+ onLoad,
2202
2587
  onScroll: onScrollProp,
2203
- getEstimatedItemSize,
2204
2588
  onStartReached,
2205
- onEndReached,
2206
- onLoad,
2589
+ onStartReachedThreshold,
2590
+ recycleItems: !!recycleItems,
2207
2591
  renderItem: renderItem2,
2208
- initialScroll,
2209
2592
  scrollBuffer,
2210
- viewabilityConfigCallbackPairs: void 0,
2211
- numColumns: numColumnsProp,
2212
- initialContainerPoolRatio,
2213
- stylePaddingTop: stylePaddingTopState
2593
+ snapToIndices,
2594
+ stickyIndicesArr: stickyIndices != null ? stickyIndices : [],
2595
+ stickyIndicesSet: React3.useMemo(() => new Set(stickyIndices), [stickyIndices]),
2596
+ stylePaddingBottom: stylePaddingBottomState,
2597
+ stylePaddingTop: stylePaddingTopState,
2598
+ suggestEstimatedItemSize: !!suggestEstimatedItemSize
2214
2599
  };
2215
2600
  state.refScroller = refScroller;
2216
2601
  const checkResetContainers = (isFirst2) => {
@@ -2219,7 +2604,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2219
2604
  state2.props.data = dataProp;
2220
2605
  if (!isFirst2) {
2221
2606
  calculateItemsInView(ctx, state2, { dataChanged: true, doMVCP: true });
2222
- const didMaintainScrollAtEnd = doMaintainScrollAtEnd(ctx, state2, false);
2607
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2608
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state2, false);
2223
2609
  if (!didMaintainScrollAtEnd && dataProp.length > state2.props.data.length) {
2224
2610
  state2.isEndReached = false;
2225
2611
  }
@@ -2237,27 +2623,29 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2237
2623
  (_, i) => getId(state, dataProp.length - 1 - i)
2238
2624
  );
2239
2625
  }, [dataProp, numColumnsProp]);
2240
- const initalizeStateVars = () => {
2626
+ const initializeStateVars = () => {
2241
2627
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
2242
2628
  set$(ctx, "numColumns", numColumnsProp);
2243
2629
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
2244
- setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
2630
+ setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
2245
2631
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
2246
- const paddingDiff = stylePaddingTopState - prevPaddingTop;
2247
- if (paddingDiff && prevPaddingTop !== void 0 && reactNative.Platform.OS === "ios") {
2248
- calculateItemsInView(ctx, state, { doMVCP: true });
2632
+ let paddingDiff = stylePaddingTopState - prevPaddingTop;
2633
+ if (maintainVisibleContentPosition && paddingDiff && prevPaddingTop !== void 0 && reactNative.Platform.OS === "ios") {
2634
+ if (state.scroll < 0) {
2635
+ paddingDiff += state.scroll;
2636
+ }
2249
2637
  requestAdjust(ctx, state, paddingDiff);
2250
2638
  }
2251
2639
  };
2252
2640
  if (isFirst) {
2253
- initalizeStateVars();
2641
+ initializeStateVars();
2254
2642
  updateAllPositions(ctx, state);
2255
2643
  }
2256
2644
  const initialContentOffset = React3.useMemo(() => {
2257
2645
  const initialContentOffset2 = initialScrollOffset || calculateOffsetForIndex(ctx, state, initialScrollIndex);
2258
2646
  refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
2259
2647
  if (initialContentOffset2 > 0) {
2260
- scrollTo(state, { offset: initialContentOffset2, animated: false, index: initialScrollIndex });
2648
+ scrollTo(state, { animated: false, index: initialScrollIndex, offset: initialContentOffset2 });
2261
2649
  }
2262
2650
  return initialContentOffset2;
2263
2651
  }, [renderNum]);
@@ -2273,9 +2661,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2273
2661
  }
2274
2662
  }
2275
2663
  React3.useLayoutEffect(() => {
2276
- var _a2, _b;
2277
2664
  if (IsNewArchitecture) {
2278
- const measured = (_b = (_a2 = refScroller.current) == null ? void 0 : _a2.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a2);
2665
+ let measured;
2666
+ refScroller.current.measure((x, y, width, height) => {
2667
+ measured = { height, width, x, y };
2668
+ });
2279
2669
  if (measured) {
2280
2670
  const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
2281
2671
  if (size) {
@@ -2302,6 +2692,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2302
2692
  }
2303
2693
  }
2304
2694
  }, []);
2695
+ React3.useLayoutEffect(() => {
2696
+ if (snapToIndices) {
2697
+ updateSnapToOffsets(ctx, state);
2698
+ }
2699
+ }, [snapToIndices]);
2305
2700
  React3.useLayoutEffect(() => {
2306
2701
  const didAllocateContainers = doInitialAllocateContainersCallback();
2307
2702
  if (!didAllocateContainers) {
@@ -2314,7 +2709,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2314
2709
  React3.useLayoutEffect(() => {
2315
2710
  set$(ctx, "extraData", extraData);
2316
2711
  }, [extraData]);
2317
- React3.useLayoutEffect(initalizeStateVars, [
2712
+ React3.useLayoutEffect(initializeStateVars, [
2318
2713
  memoizedLastItemKeys.join(","),
2319
2714
  numColumnsProp,
2320
2715
  stylePaddingTopState,
@@ -2325,12 +2720,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2325
2720
  };
2326
2721
  React3.useEffect(() => {
2327
2722
  const viewability = setupViewability({
2723
+ onViewableItemsChanged,
2328
2724
  viewabilityConfig,
2329
- viewabilityConfigCallbackPairs,
2330
- onViewableItemsChanged
2725
+ viewabilityConfigCallbackPairs
2331
2726
  });
2332
2727
  state.viewabilityConfigCallbackPairs = viewability;
2333
- state.props.viewabilityConfigCallbackPairs = viewability;
2334
2728
  state.enableScrollForNextCalculateItemsInView = !viewability;
2335
2729
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
2336
2730
  if (!IsNewArchitecture) {
@@ -2345,144 +2739,161 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2345
2739
  onLayoutProp(event);
2346
2740
  }
2347
2741
  }, []);
2348
- React3.useImperativeHandle(
2349
- forwardedRef,
2350
- () => {
2351
- const scrollIndexIntoView = (options) => {
2742
+ React3.useImperativeHandle(forwardedRef, () => {
2743
+ const scrollIndexIntoView = (options) => {
2744
+ const state2 = refState.current;
2745
+ if (state2) {
2746
+ const { index, ...rest2 } = options;
2747
+ const { startNoBuffer, endNoBuffer } = state2;
2748
+ if (index < startNoBuffer || index > endNoBuffer) {
2749
+ const viewPosition = index < startNoBuffer ? 0 : 1;
2750
+ scrollToIndex(ctx, state2, {
2751
+ ...rest2,
2752
+ index,
2753
+ viewPosition
2754
+ });
2755
+ }
2756
+ }
2757
+ };
2758
+ return {
2759
+ flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
2760
+ getNativeScrollRef: () => refScroller.current,
2761
+ getScrollableNode: () => refScroller.current.getScrollableNode(),
2762
+ getScrollResponder: () => refScroller.current.getScrollResponder(),
2763
+ getState: () => {
2352
2764
  const state2 = refState.current;
2353
- if (state2) {
2354
- const { index, ...rest2 } = options;
2355
- const { startNoBuffer, endNoBuffer } = state2;
2356
- if (index < startNoBuffer || index > endNoBuffer) {
2357
- const viewPosition = index < startNoBuffer ? 0 : 1;
2358
- scrollToIndex(ctx, state2, {
2359
- ...rest2,
2360
- viewPosition,
2361
- index
2362
- });
2363
- }
2765
+ return state2 ? {
2766
+ contentLength: state2.totalSize,
2767
+ end: state2.endNoBuffer,
2768
+ endBuffered: state2.endBuffered,
2769
+ isAtEnd: state2.isAtEnd,
2770
+ isAtStart: state2.isAtStart,
2771
+ positions: state2.positions,
2772
+ scroll: state2.scroll,
2773
+ scrollLength: state2.scrollLength,
2774
+ sizeAtIndex: (index) => state2.sizesKnown.get(getId(state2, index)),
2775
+ sizes: state2.sizesKnown,
2776
+ start: state2.startNoBuffer,
2777
+ startBuffered: state2.startBuffered
2778
+ } : {};
2779
+ },
2780
+ scrollIndexIntoView,
2781
+ scrollItemIntoView: ({ item, ...props2 }) => {
2782
+ const data = refState.current.props.data;
2783
+ const index = data.indexOf(item);
2784
+ if (index !== -1) {
2785
+ scrollIndexIntoView({ index, ...props2 });
2364
2786
  }
2365
- };
2366
- return {
2367
- flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
2368
- getNativeScrollRef: () => refScroller.current,
2369
- getScrollableNode: () => refScroller.current.getScrollableNode(),
2370
- getScrollResponder: () => refScroller.current.getScrollResponder(),
2371
- getState: () => {
2372
- const state2 = refState.current;
2373
- return state2 ? {
2374
- contentLength: state2.totalSize,
2375
- end: state2.endNoBuffer,
2376
- endBuffered: state2.endBuffered,
2377
- isAtEnd: state2.isAtEnd,
2378
- isAtStart: state2.isAtStart,
2379
- scroll: state2.scroll,
2380
- scrollLength: state2.scrollLength,
2381
- start: state2.startNoBuffer,
2382
- startBuffered: state2.startBuffered,
2383
- sizes: state2.sizesKnown,
2384
- sizeAtIndex: (index) => state2.sizesKnown.get(getId(state2, index))
2385
- } : {};
2386
- },
2387
- scrollIndexIntoView,
2388
- scrollItemIntoView: ({ item, ...props2 }) => {
2389
- const data = refState.current.props.data;
2390
- const index = data.indexOf(item);
2391
- if (index !== -1) {
2392
- scrollIndexIntoView({ index, ...props2 });
2393
- }
2394
- },
2395
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
2396
- scrollToItem: ({ item, ...props2 }) => {
2397
- const data = refState.current.props.data;
2398
- const index = data.indexOf(item);
2399
- if (index !== -1) {
2400
- scrollToIndex(ctx, state, { index, ...props2 });
2401
- }
2402
- },
2403
- scrollToOffset: (params) => scrollTo(state, params),
2404
- scrollToEnd: (options) => {
2405
- const data = refState.current.props.data;
2406
- const stylePaddingBottom = refState.current.props.stylePaddingBottom;
2407
- const index = data.length - 1;
2408
- if (index !== -1) {
2409
- const paddingBottom = stylePaddingBottom || 0;
2410
- const footerSize = peek$(ctx, "footerSize") || 0;
2411
- scrollToIndex(ctx, state, {
2412
- index,
2413
- viewPosition: 1,
2414
- viewOffset: -paddingBottom - footerSize,
2415
- ...options
2416
- });
2417
- }
2418
- },
2419
- setVisibleContentAnchorOffset: (value) => {
2420
- const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
2421
- set$(ctx, "scrollAdjustUserOffset", val);
2787
+ },
2788
+ scrollToEnd: (options) => {
2789
+ const data = refState.current.props.data;
2790
+ const stylePaddingBottom = refState.current.props.stylePaddingBottom;
2791
+ const index = data.length - 1;
2792
+ if (index !== -1) {
2793
+ const paddingBottom = stylePaddingBottom || 0;
2794
+ const footerSize = peek$(ctx, "footerSize") || 0;
2795
+ scrollToIndex(ctx, state, {
2796
+ index,
2797
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
2798
+ viewPosition: 1,
2799
+ ...options
2800
+ });
2422
2801
  }
2423
- };
2424
- },
2425
- []
2426
- );
2802
+ },
2803
+ scrollToIndex: (params) => scrollToIndex(ctx, state, params),
2804
+ scrollToItem: ({ item, ...props2 }) => {
2805
+ const data = refState.current.props.data;
2806
+ const index = data.indexOf(item);
2807
+ if (index !== -1) {
2808
+ scrollToIndex(ctx, state, { index, ...props2 });
2809
+ }
2810
+ },
2811
+ scrollToOffset: (params) => scrollTo(state, params),
2812
+ setVisibleContentAnchorOffset: (value) => {
2813
+ const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
2814
+ set$(ctx, "scrollAdjustUserOffset", val);
2815
+ }
2816
+ };
2817
+ }, []);
2427
2818
  if (reactNative.Platform.OS === "web") {
2428
2819
  React3.useEffect(() => {
2429
2820
  if (initialContentOffset) {
2430
- scrollTo(state, { offset: initialContentOffset, animated: false });
2821
+ scrollTo(state, { animated: false, offset: initialContentOffset });
2431
2822
  }
2432
2823
  }, []);
2433
2824
  }
2434
2825
  const fns = React3.useMemo(
2435
2826
  () => ({
2436
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj),
2437
2827
  getRenderedItem: (key) => getRenderedItem(ctx, state, key),
2438
- onScroll: (event) => onScroll(ctx, state, event)
2828
+ onScroll: (event) => onScroll(ctx, state, event),
2829
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
2439
2830
  }),
2440
2831
  []
2441
2832
  );
2833
+ const animatedScrollHandler = React3.useMemo(() => {
2834
+ if (stickyIndices == null ? void 0 : stickyIndices.length) {
2835
+ const { animatedScrollY } = ctx;
2836
+ return reactNative.Animated.event([{ nativeEvent: { contentOffset: { [horizontal ? "x" : "y"]: animatedScrollY } } }], {
2837
+ listener: fns.onScroll,
2838
+ useNativeDriver: true
2839
+ });
2840
+ }
2841
+ return fns.onScroll;
2842
+ }, [stickyIndices, horizontal, onScroll]);
2442
2843
  return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(
2443
2844
  ListComponent,
2444
2845
  {
2445
2846
  ...rest,
2847
+ alignItemsAtEnd,
2446
2848
  canRender,
2849
+ contentContainerStyle,
2850
+ getRenderedItem: fns.getRenderedItem,
2447
2851
  horizontal,
2448
- refScrollView: combinedRef,
2449
2852
  initialContentOffset,
2450
- getRenderedItem: fns.getRenderedItem,
2451
- updateItemSize: fns.updateItemSize,
2452
- onScroll: fns.onScroll,
2853
+ ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
2854
+ ListHeaderComponent,
2855
+ maintainVisibleContentPosition,
2856
+ onLayout,
2857
+ onLayoutHeader,
2453
2858
  onMomentumScrollEnd: (event) => {
2454
- requestAnimationFrame(() => {
2455
- finishScrollTo(refState.current);
2456
- });
2859
+ if (IsNewArchitecture) {
2860
+ requestAnimationFrame(() => {
2861
+ finishScrollTo(refState.current);
2862
+ });
2863
+ } else {
2864
+ setTimeout(() => {
2865
+ finishScrollTo(refState.current);
2866
+ }, 1e3);
2867
+ }
2457
2868
  if (onMomentumScrollEnd) {
2458
2869
  onMomentumScrollEnd(event);
2459
2870
  }
2460
2871
  },
2461
- onLayout,
2872
+ onScroll: animatedScrollHandler,
2462
2873
  recycleItems,
2463
- alignItemsAtEnd,
2464
- ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
2465
- ListHeaderComponent,
2466
- maintainVisibleContentPosition,
2467
- scrollEventThrottle: reactNative.Platform.OS === "web" ? 16 : void 0,
2468
- waitForInitialLayout,
2469
2874
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControl, {
2470
2875
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
2471
2876
  }) : refreshControl : onRefresh && /* @__PURE__ */ React3__namespace.createElement(
2472
2877
  reactNative.RefreshControl,
2473
2878
  {
2474
- refreshing: !!refreshing,
2475
2879
  onRefresh,
2476
- progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState
2880
+ progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState,
2881
+ refreshing: !!refreshing
2477
2882
  }
2478
2883
  ),
2479
- style,
2480
- contentContainerStyle,
2884
+ refScrollView: combinedRef,
2481
2885
  scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
2482
- onLayoutHeader
2886
+ scrollEventThrottle: reactNative.Platform.OS === "web" ? 16 : void 0,
2887
+ snapToIndices,
2888
+ stickyIndices,
2889
+ style,
2890
+ updateItemSize: fns.updateItemSize,
2891
+ waitForInitialLayout
2483
2892
  }
2484
2893
  ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3__namespace.createElement(DebugView, { state: refState.current }));
2485
2894
  });
2895
+
2896
+ // src/components/LazyLegendList.tsx
2486
2897
  var typedForwardRef2 = React3.forwardRef;
2487
2898
  var renderItem = ({ item }) => item;
2488
2899
  var LazyLegendList = typedForwardRef2(function LazyLegendList2(props, forwardedRef) {
@@ -2491,7 +2902,7 @@ var LazyLegendList = typedForwardRef2(function LazyLegendList2(props, forwardedR
2491
2902
  const data = (isArray(children) ? children : React3__namespace.Children.toArray(children)).flat(1);
2492
2903
  return (
2493
2904
  // @ts-expect-error TODO: Fix this type
2494
- /* @__PURE__ */ React3__namespace.createElement(LegendListComponent, { ...rest, data, renderItem, ref: forwardedRef })
2905
+ /* @__PURE__ */ React3__namespace.createElement(LegendListComponent, { ...rest, data, ref: forwardedRef, renderItem })
2495
2906
  );
2496
2907
  });
2497
2908