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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -0
  3. package/animated.native.d.mts +9 -0
  4. package/animated.native.d.ts +9 -0
  5. package/animated.native.js +9 -0
  6. package/animated.native.mjs +7 -0
  7. package/index.d.mts +781 -10
  8. package/index.d.ts +781 -10
  9. package/index.js +973 -530
  10. package/index.mjs +973 -532
  11. package/index.native.d.mts +781 -10
  12. package/index.native.d.ts +781 -10
  13. package/index.native.js +981 -494
  14. package/index.native.mjs +980 -495
  15. package/keyboard-controller.native.d.mts +12 -0
  16. package/keyboard-controller.native.d.ts +12 -0
  17. package/keyboard-controller.native.js +69 -0
  18. package/keyboard-controller.native.mjs +48 -0
  19. package/keyboard.d.mts +5 -2
  20. package/keyboard.d.ts +5 -2
  21. package/keyboard.js +232 -28
  22. package/keyboard.mjs +235 -31
  23. package/keyboard.native.d.mts +16 -0
  24. package/keyboard.native.d.ts +16 -0
  25. package/keyboard.native.js +318 -0
  26. package/keyboard.native.mjs +296 -0
  27. package/package.json +1 -1
  28. package/reanimated.d.mts +3 -3
  29. package/reanimated.d.ts +3 -3
  30. package/reanimated.js +15 -4
  31. package/reanimated.mjs +14 -3
  32. package/reanimated.native.d.mts +18 -0
  33. package/reanimated.native.d.ts +18 -0
  34. package/reanimated.native.js +89 -0
  35. package/reanimated.native.mjs +65 -0
  36. package/section-list.d.mts +1 -2
  37. package/section-list.d.ts +1 -2
  38. package/section-list.js +36 -3670
  39. package/section-list.mjs +34 -3669
  40. package/section-list.native.d.mts +1 -2
  41. package/section-list.native.d.ts +1 -2
  42. package/section-list.native.js +36 -3449
  43. package/section-list.native.mjs +33 -3447
  44. package/types-JPHClxiw.d.mts +0 -670
  45. package/types-JPHClxiw.d.ts +0 -670
  46. package/types-YNdphn_A.d.mts +0 -670
  47. package/types-YNdphn_A.d.ts +0 -670
package/index.native.mjs CHANGED
@@ -7,30 +7,64 @@ import { useSyncExternalStore } from 'use-sync-external-store/shim';
7
7
  Animated.View;
8
8
  var View = View$1;
9
9
  var Text = Text$1;
10
+
11
+ // src/state/getContentInsetEnd.ts
12
+ function getContentInsetEnd(state) {
13
+ var _a3;
14
+ const { props } = state;
15
+ const horizontal = props.horizontal;
16
+ let contentInset = props.contentInset;
17
+ if (!contentInset) {
18
+ const animatedInset = (_a3 = props.animatedProps) == null ? void 0 : _a3.contentInset;
19
+ if (animatedInset) {
20
+ if ("get" in animatedInset) {
21
+ contentInset = animatedInset.get();
22
+ } else {
23
+ contentInset = animatedInset;
24
+ }
25
+ }
26
+ }
27
+ return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
28
+ }
29
+
30
+ // src/state/getContentSize.ts
31
+ function getContentSize(ctx) {
32
+ var _a3;
33
+ const { values, state } = ctx;
34
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
35
+ const stylePaddingBottom = state.props.stylePaddingBottom || 0;
36
+ const headerSize = values.get("headerSize") || 0;
37
+ const footerSize = values.get("footerSize") || 0;
38
+ const contentInsetBottom = getContentInsetEnd(state);
39
+ const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
40
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
41
+ }
10
42
  var createAnimatedValue = (value) => new Animated.Value(value);
11
43
 
12
44
  // src/state/state.tsx
13
45
  var ContextState = React2.createContext(null);
46
+ var contextNum = 0;
14
47
  function StateProvider({ children }) {
15
48
  const [value] = React2.useState(() => ({
16
49
  animatedScrollY: createAnimatedValue(0),
17
50
  columnWrapperStyle: void 0,
18
- internalState: void 0,
51
+ contextNum: contextNum++,
19
52
  listeners: /* @__PURE__ */ new Map(),
20
53
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
21
54
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
22
55
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
23
56
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
24
57
  mapViewabilityValues: /* @__PURE__ */ new Map(),
58
+ positionListeners: /* @__PURE__ */ new Map(),
59
+ state: void 0,
25
60
  values: /* @__PURE__ */ new Map([
26
61
  ["alignItemsPaddingTop", 0],
27
62
  ["stylePaddingTop", 0],
28
63
  ["headerSize", 0],
29
64
  ["numContainers", 0],
30
- ["activeStickyIndex", void 0],
65
+ ["activeStickyIndex", -1],
31
66
  ["totalSize", 0],
32
- ["scrollAdjustPending", 0],
33
- ["scrollingTo", void 0]
67
+ ["scrollAdjustPending", 0]
34
68
  ]),
35
69
  viewRefs: /* @__PURE__ */ new Map()
36
70
  }));
@@ -98,15 +132,24 @@ function set$(ctx, signalName, value) {
98
132
  }
99
133
  }
100
134
  }
101
- function getContentSize(ctx) {
102
- var _a3, _b;
103
- const { values, internalState } = ctx;
104
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
105
- const stylePaddingBottom = (internalState == null ? void 0 : internalState.props.stylePaddingBottom) || 0;
106
- const headerSize = values.get("headerSize") || 0;
107
- const footerSize = values.get("footerSize") || 0;
108
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
109
- return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom;
135
+ function listenPosition$(ctx, key, cb) {
136
+ const { positionListeners } = ctx;
137
+ let setListeners = positionListeners.get(key);
138
+ if (!setListeners) {
139
+ setListeners = /* @__PURE__ */ new Set();
140
+ positionListeners.set(key, setListeners);
141
+ }
142
+ setListeners.add(cb);
143
+ return () => setListeners.delete(cb);
144
+ }
145
+ function notifyPosition$(ctx, key, value) {
146
+ const { positionListeners } = ctx;
147
+ const setListeners = positionListeners.get(key);
148
+ if (setListeners) {
149
+ for (const listener of setListeners) {
150
+ listener(value);
151
+ }
152
+ }
110
153
  }
111
154
  function useArr$(signalNames) {
112
155
  const ctx = React2.useContext(ContextState);
@@ -185,9 +228,11 @@ var ENABLE_DEVMODE = IS_DEV && false;
185
228
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
186
229
 
187
230
  // src/constants-platform.native.ts
188
- var IsNewArchitecture = global.nativeFabricUIManager != null;
231
+ var f = global.nativeFabricUIManager;
232
+ var IsNewArchitecture = f !== void 0 && f != null;
189
233
  var useAnimatedValue = (initialValue) => {
190
- return useRef(new Animated.Value(initialValue)).current;
234
+ const [animAnimatedValue] = useState(() => new Animated.Value(initialValue));
235
+ return animAnimatedValue;
191
236
  };
192
237
 
193
238
  // src/utils/helpers.ts
@@ -221,6 +266,11 @@ function extractPadding(style, contentContainerStyle, type) {
221
266
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
222
267
  }
223
268
  function findContainerId(ctx, key) {
269
+ var _a3, _b;
270
+ const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
271
+ if (directMatch !== void 0) {
272
+ return directMatch;
273
+ }
224
274
  const numContainers = peek$(ctx, "numContainers");
225
275
  for (let i = 0; i < numContainers; i++) {
226
276
  const itemKey = peek$(ctx, `containerItemKey${i}`);
@@ -274,9 +324,18 @@ function useValue$(key, params) {
274
324
  }
275
325
  var typedForwardRef = forwardRef;
276
326
  var typedMemo = memo;
327
+ var getComponent = (Component) => {
328
+ if (React2.isValidElement(Component)) {
329
+ return Component;
330
+ }
331
+ if (Component) {
332
+ return /* @__PURE__ */ React2.createElement(Component, null);
333
+ }
334
+ return null;
335
+ };
277
336
 
278
337
  // src/components/PositionView.native.tsx
279
- var PositionViewState = typedMemo(function PositionView({
338
+ var PositionViewState = typedMemo(function PositionViewState2({
280
339
  id,
281
340
  horizontal,
282
341
  style,
@@ -296,7 +355,7 @@ var PositionViewState = typedMemo(function PositionView({
296
355
  }
297
356
  );
298
357
  });
299
- var PositionViewAnimated = typedMemo(function PositionView2({
358
+ var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
300
359
  id,
301
360
  horizontal,
302
361
  style,
@@ -322,77 +381,117 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
322
381
  animatedScrollY,
323
382
  stickyOffset,
324
383
  index,
384
+ stickyHeaderConfig,
385
+ children,
325
386
  ...rest
326
387
  }) {
327
388
  const [position = POSITION_OUT_OF_VIEW, headerSize] = useArr$([`containerPosition${id}`, "headerSize"]);
328
389
  const transform = React2.useMemo(() => {
390
+ var _a3;
329
391
  if (animatedScrollY && stickyOffset !== void 0) {
392
+ const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
330
393
  const stickyPosition = animatedScrollY.interpolate({
331
394
  extrapolateLeft: "clamp",
332
395
  extrapolateRight: "extend",
333
- inputRange: [position + headerSize, position + 5e3 + headerSize],
396
+ inputRange: [
397
+ position + headerSize - stickyConfigOffset - stickyOffset,
398
+ position + 5e3 + headerSize - stickyConfigOffset - stickyOffset
399
+ ],
334
400
  outputRange: [position, position + 5e3]
335
401
  });
336
402
  return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
337
403
  }
338
- }, [animatedScrollY, headerSize, horizontal, stickyOffset, position]);
404
+ }, [animatedScrollY, headerSize, horizontal, stickyOffset, position, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
339
405
  const viewStyle = React2.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
340
- return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: viewStyle, ...rest });
406
+ const renderStickyHeaderBackdrop = React2.useMemo(() => {
407
+ if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
408
+ return null;
409
+ }
410
+ return /* @__PURE__ */ React2.createElement(
411
+ View$1,
412
+ {
413
+ style: {
414
+ inset: 0,
415
+ pointerEvents: "none",
416
+ position: "absolute"
417
+ }
418
+ },
419
+ getComponent(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)
420
+ );
421
+ }, [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]);
422
+ return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: viewStyle, ...rest }, renderStickyHeaderBackdrop, children);
341
423
  });
342
- var PositionView3 = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
343
- var symbolFirst = Symbol();
424
+ var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
344
425
  function useInit(cb) {
345
- const refValue = useRef(symbolFirst);
346
- if (refValue.current === symbolFirst) {
347
- refValue.current = cb();
348
- }
349
- return refValue.current;
426
+ useState(() => cb());
350
427
  }
351
428
 
352
429
  // src/state/ContextContainer.ts
353
430
  var ContextContainer = createContext(null);
431
+ function useContextContainer() {
432
+ return useContext(ContextContainer);
433
+ }
354
434
  function useViewability(callback, configId) {
355
435
  const ctx = useStateContext();
356
- const { containerId } = useContext(ContextContainer);
357
- const key = containerId + (configId != null ? configId : "");
436
+ const containerContext = useContextContainer();
358
437
  useInit(() => {
438
+ if (!containerContext) {
439
+ return;
440
+ }
441
+ const { containerId } = containerContext;
442
+ const key = containerId + (configId != null ? configId : "");
359
443
  const value = ctx.mapViewabilityValues.get(key);
360
444
  if (value) {
361
445
  callback(value);
362
446
  }
363
447
  });
364
- ctx.mapViewabilityCallbacks.set(key, callback);
365
- useEffect(
366
- () => () => {
448
+ useEffect(() => {
449
+ if (!containerContext) {
450
+ return;
451
+ }
452
+ const { containerId } = containerContext;
453
+ const key = containerId + (configId != null ? configId : "");
454
+ ctx.mapViewabilityCallbacks.set(key, callback);
455
+ return () => {
367
456
  ctx.mapViewabilityCallbacks.delete(key);
368
- },
369
- []
370
- );
457
+ };
458
+ }, [ctx, callback, configId, containerContext]);
371
459
  }
372
460
  function useViewabilityAmount(callback) {
373
461
  const ctx = useStateContext();
374
- const { containerId } = useContext(ContextContainer);
462
+ const containerContext = useContextContainer();
375
463
  useInit(() => {
464
+ if (!containerContext) {
465
+ return;
466
+ }
467
+ const { containerId } = containerContext;
376
468
  const value = ctx.mapViewabilityAmountValues.get(containerId);
377
469
  if (value) {
378
470
  callback(value);
379
471
  }
380
472
  });
381
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
382
- useEffect(
383
- () => () => {
473
+ useEffect(() => {
474
+ if (!containerContext) {
475
+ return;
476
+ }
477
+ const { containerId } = containerContext;
478
+ ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
479
+ return () => {
384
480
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
385
- },
386
- []
387
- );
481
+ };
482
+ }, [ctx, callback, containerContext]);
388
483
  }
389
484
  function useRecyclingEffect(effect) {
390
- const { index, value } = useContext(ContextContainer);
485
+ const containerContext = useContextContainer();
391
486
  const prevValues = useRef({
392
487
  prevIndex: void 0,
393
488
  prevItem: void 0
394
489
  });
395
490
  useEffect(() => {
491
+ if (!containerContext) {
492
+ return;
493
+ }
494
+ const { index, value } = containerContext;
396
495
  let ret;
397
496
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
398
497
  ret = effect({
@@ -407,38 +506,58 @@ function useRecyclingEffect(effect) {
407
506
  prevItem: value
408
507
  };
409
508
  return ret;
410
- }, [index, value, effect]);
509
+ }, [effect, containerContext]);
411
510
  }
412
511
  function useRecyclingState(valueOrFun) {
413
- const { index, value, itemKey, triggerLayout } = useContext(ContextContainer);
414
- const refState = useRef({
415
- itemKey: null,
416
- value: null
512
+ var _a3, _b;
513
+ const containerContext = useContextContainer();
514
+ const computeValue = (ctx) => {
515
+ if (isFunction(valueOrFun)) {
516
+ const initializer = valueOrFun;
517
+ return ctx ? initializer({
518
+ index: ctx.index,
519
+ item: ctx.value,
520
+ prevIndex: void 0,
521
+ prevItem: void 0
522
+ }) : initializer();
523
+ }
524
+ return valueOrFun;
525
+ };
526
+ const [stateValue, setStateValue] = useState(() => {
527
+ return computeValue(containerContext);
417
528
  });
418
- const [_, setRenderNum] = useState(0);
419
- const state = refState.current;
420
- if (state.itemKey !== itemKey) {
421
- state.itemKey = itemKey;
422
- state.value = isFunction(valueOrFun) ? valueOrFun({
423
- index,
424
- item: value,
425
- prevIndex: void 0,
426
- prevItem: void 0
427
- }) : valueOrFun;
529
+ const prevItemKeyRef = useRef((_a3 = containerContext == null ? void 0 : containerContext.itemKey) != null ? _a3 : null);
530
+ const currentItemKey = (_b = containerContext == null ? void 0 : containerContext.itemKey) != null ? _b : null;
531
+ if (currentItemKey !== null && prevItemKeyRef.current !== currentItemKey) {
532
+ prevItemKeyRef.current = currentItemKey;
533
+ setStateValue(computeValue(containerContext));
428
534
  }
535
+ const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
429
536
  const setState = useCallback(
430
537
  (newState) => {
431
- state.value = isFunction(newState) ? newState(state.value) : newState;
432
- setRenderNum((v) => v + 1);
538
+ if (!triggerLayout) {
539
+ return;
540
+ }
541
+ setStateValue((prevValue) => {
542
+ return isFunction(newState) ? newState(prevValue) : newState;
543
+ });
433
544
  triggerLayout();
434
545
  },
435
- [triggerLayout, state]
546
+ [triggerLayout]
436
547
  );
437
- return [state.value, setState];
548
+ return [stateValue, setState];
438
549
  }
439
550
  function useIsLastItem() {
440
- const { itemKey } = useContext(ContextContainer);
441
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
551
+ const containerContext = useContextContainer();
552
+ const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
553
+ if (containerContext) {
554
+ const { itemKey } = containerContext;
555
+ if (!isNullOrUndefined(itemKey)) {
556
+ return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
557
+ }
558
+ }
559
+ return false;
560
+ });
442
561
  return isLast;
443
562
  }
444
563
  function useListScrollSize() {
@@ -448,8 +567,9 @@ function useListScrollSize() {
448
567
  var noop = () => {
449
568
  };
450
569
  function useSyncLayout() {
451
- if (IsNewArchitecture) {
452
- const { triggerLayout: syncLayout } = useContext(ContextContainer);
570
+ const containerContext = useContextContainer();
571
+ if (IsNewArchitecture && containerContext) {
572
+ const { triggerLayout: syncLayout } = containerContext;
453
573
  return syncLayout;
454
574
  } else {
455
575
  return noop;
@@ -500,7 +620,8 @@ var Container = typedMemo(function Container2({
500
620
  horizontal,
501
621
  getRenderedItem: getRenderedItem2,
502
622
  updateItemSize: updateItemSize2,
503
- ItemSeparatorComponent
623
+ ItemSeparatorComponent,
624
+ stickyHeaderConfig
504
625
  }) {
505
626
  const ctx = useStateContext();
506
627
  const { columnWrapperStyle, animatedScrollY } = ctx;
@@ -612,6 +733,7 @@ var Container = typedMemo(function Container2({
612
733
  if (!IsNewArchitecture) {
613
734
  useEffect(() => {
614
735
  if (!isNullOrUndefined(itemKey)) {
736
+ didLayoutRef.current = false;
615
737
  const timeout = setTimeout(() => {
616
738
  if (!didLayoutRef.current) {
617
739
  const {
@@ -631,7 +753,7 @@ var Container = typedMemo(function Container2({
631
753
  }
632
754
  }, [itemKey]);
633
755
  }
634
- const PositionComponent = isSticky ? PositionViewSticky : PositionView3;
756
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
635
757
  return /* @__PURE__ */ React2.createElement(
636
758
  PositionComponent,
637
759
  {
@@ -642,6 +764,7 @@ var Container = typedMemo(function Container2({
642
764
  key: recycleItems ? void 0 : itemKey,
643
765
  onLayout,
644
766
  refView: ref,
767
+ stickyHeaderConfig,
645
768
  stickyOffset: isSticky ? stickyOffset : void 0,
646
769
  style
647
770
  },
@@ -666,10 +789,10 @@ var Containers = typedMemo(function Containers2({
666
789
  // If this is the initial scroll, we don't want to delay because we want to update the size immediately
667
790
  delay: (value, prevValue) => {
668
791
  var _a3;
669
- return !((_a3 = ctx.internalState) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
792
+ return !((_a3 = ctx.state) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
670
793
  }
671
794
  });
672
- const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("containersDidLayout", { getValue: (value) => value ? 1 : 0 }) : void 0;
795
+ const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("readyToRender", { getValue: (value) => value ? 1 : 0 }) : void 0;
673
796
  const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
674
797
  const containers = [];
675
798
  for (let i = 0; i < numContainers; i++) {
@@ -712,7 +835,8 @@ var Containers = typedMemo(function Containers2({
712
835
  return /* @__PURE__ */ React2.createElement(Animated.View, { style }, containers);
713
836
  });
714
837
  function DevNumbers() {
715
- return IS_DEV && React2.memo(function DevNumbers2() {
838
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
839
+ React2.memo(function DevNumbers2() {
716
840
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React2.createElement(
717
841
  View$1,
718
842
  {
@@ -778,15 +902,6 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
778
902
  };
779
903
 
780
904
  // src/components/ListComponent.tsx
781
- var getComponent = (Component) => {
782
- if (React2.isValidElement(Component)) {
783
- return Component;
784
- }
785
- if (Component) {
786
- return /* @__PURE__ */ React2.createElement(Component, null);
787
- }
788
- return null;
789
- };
790
905
  var ListComponent = typedMemo(function ListComponent2({
791
906
  canRender,
792
907
  style,
@@ -807,26 +922,20 @@ var ListComponent = typedMemo(function ListComponent2({
807
922
  getRenderedItem: getRenderedItem2,
808
923
  updateItemSize: updateItemSize2,
809
924
  refScrollView,
810
- maintainVisibleContentPosition,
811
925
  renderScrollComponent,
812
926
  scrollAdjustHandler,
813
927
  onLayoutHeader,
814
928
  snapToIndices,
929
+ stickyHeaderConfig,
815
930
  stickyHeaderIndices,
816
931
  ...rest
817
932
  }) {
818
933
  const ctx = useStateContext();
934
+ const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
819
935
  const ScrollComponent = renderScrollComponent ? useMemo(
820
936
  () => React2.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
821
937
  [renderScrollComponent]
822
938
  ) : ListComponentScrollView;
823
- React2.useEffect(() => {
824
- if (canRender) {
825
- setTimeout(() => {
826
- scrollAdjustHandler.setMounted();
827
- }, 0);
828
- }
829
- }, [canRender]);
830
939
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
831
940
  return /* @__PURE__ */ React2.createElement(
832
941
  SnapOrScroll,
@@ -840,7 +949,7 @@ var ListComponent = typedMemo(function ListComponent2({
840
949
  ],
841
950
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
842
951
  horizontal,
843
- maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
952
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
844
953
  onLayout,
845
954
  onScroll: onScroll2,
846
955
  ref: refScrollView,
@@ -858,6 +967,7 @@ var ListComponent = typedMemo(function ListComponent2({
858
967
  horizontal,
859
968
  ItemSeparatorComponent,
860
969
  recycleItems,
970
+ stickyHeaderConfig,
861
971
  updateItemSize: updateItemSize2,
862
972
  waitForInitialLayout
863
973
  }
@@ -890,10 +1000,11 @@ function getId(state, index) {
890
1000
  }
891
1001
 
892
1002
  // src/core/calculateOffsetForIndex.ts
893
- function calculateOffsetForIndex(ctx, state, index) {
1003
+ function calculateOffsetForIndex(ctx, index) {
1004
+ const state = ctx.state;
894
1005
  let position = 0;
895
1006
  if (index !== void 0) {
896
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
1007
+ position = state.positions.get(getId(state, index)) || 0;
897
1008
  const paddingTop = peek$(ctx, "stylePaddingTop");
898
1009
  if (paddingTop) {
899
1010
  position += paddingTop;
@@ -907,7 +1018,8 @@ function calculateOffsetForIndex(ctx, state, index) {
907
1018
  }
908
1019
 
909
1020
  // src/utils/setPaddingTop.ts
910
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1021
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1022
+ const state = ctx.state;
911
1023
  if (stylePaddingTop !== void 0) {
912
1024
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
913
1025
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -926,7 +1038,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
926
1038
  }
927
1039
 
928
1040
  // src/utils/updateAlignItemsPaddingTop.ts
929
- function updateAlignItemsPaddingTop(ctx, state) {
1041
+ function updateAlignItemsPaddingTop(ctx) {
1042
+ const state = ctx.state;
930
1043
  const {
931
1044
  scrollLength,
932
1045
  props: { alignItemsAtEnd, data }
@@ -937,12 +1050,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
937
1050
  const contentSize = getContentSize(ctx);
938
1051
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
939
1052
  }
940
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1053
+ setPaddingTop(ctx, { alignItemsPaddingTop });
941
1054
  }
942
1055
  }
943
1056
 
944
1057
  // src/core/addTotalSize.ts
945
- function addTotalSize(ctx, state, key, add) {
1058
+ function addTotalSize(ctx, key, add) {
1059
+ const state = ctx.state;
946
1060
  const { alignItemsAtEnd } = state.props;
947
1061
  const prevTotalSize = state.totalSize;
948
1062
  let totalSize = state.totalSize;
@@ -963,31 +1077,34 @@ function addTotalSize(ctx, state, key, add) {
963
1077
  state.totalSize = totalSize;
964
1078
  set$(ctx, "totalSize", totalSize);
965
1079
  if (alignItemsAtEnd) {
966
- updateAlignItemsPaddingTop(ctx, state);
1080
+ updateAlignItemsPaddingTop(ctx);
967
1081
  }
968
1082
  }
969
1083
  }
970
1084
  }
971
1085
 
972
1086
  // src/core/setSize.ts
973
- function setSize(ctx, state, itemKey, size) {
1087
+ function setSize(ctx, itemKey, size) {
1088
+ const state = ctx.state;
974
1089
  const { sizes } = state;
975
1090
  const previousSize = sizes.get(itemKey);
976
1091
  const diff = previousSize !== void 0 ? size - previousSize : size;
977
1092
  if (diff !== 0) {
978
- addTotalSize(ctx, state, itemKey, diff);
1093
+ addTotalSize(ctx, itemKey, diff);
979
1094
  }
980
1095
  sizes.set(itemKey, size);
981
1096
  }
982
1097
 
983
1098
  // src/utils/getItemSize.ts
984
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1099
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
985
1100
  var _a3, _b;
1101
+ const state = ctx.state;
986
1102
  const {
987
1103
  sizesKnown,
988
1104
  sizes,
989
1105
  averageSizes,
990
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1106
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1107
+ scrollingTo
991
1108
  } = state;
992
1109
  const sizeKnown = sizesKnown.get(key);
993
1110
  if (sizeKnown !== void 0) {
@@ -995,7 +1112,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
995
1112
  }
996
1113
  let size;
997
1114
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
998
- const scrollingTo = peek$(ctx, "scrollingTo");
999
1115
  if (preferCachedSize) {
1000
1116
  const cachedSize = sizes.get(key);
1001
1117
  if (cachedSize !== void 0) {
@@ -1003,7 +1119,7 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1003
1119
  }
1004
1120
  }
1005
1121
  if (getFixedItemSize) {
1006
- size = getFixedItemSize(index, data, itemType);
1122
+ size = getFixedItemSize(data, index, itemType);
1007
1123
  if (size !== void 0) {
1008
1124
  sizesKnown.set(key, size);
1009
1125
  }
@@ -1021,96 +1137,192 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1021
1137
  }
1022
1138
  }
1023
1139
  if (size === void 0) {
1024
- size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1140
+ size = getEstimatedItemSize ? getEstimatedItemSize(data, index, itemType) : estimatedItemSize;
1025
1141
  }
1026
- setSize(ctx, state, key, size);
1142
+ setSize(ctx, key, size);
1027
1143
  return size;
1028
1144
  }
1029
1145
 
1030
1146
  // src/core/calculateOffsetWithOffsetPosition.ts
1031
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1147
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1148
+ const state = ctx.state;
1032
1149
  const { index, viewOffset, viewPosition } = params;
1033
1150
  let offset = offsetParam;
1034
1151
  if (viewOffset) {
1035
1152
  offset -= viewOffset;
1036
1153
  }
1037
1154
  if (viewPosition !== void 0 && index !== void 0) {
1038
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1155
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1156
+ const trailingInset = getContentInsetEnd(state);
1157
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1039
1158
  }
1040
1159
  return offset;
1041
1160
  }
1161
+ var Platform2 = Platform;
1162
+ var PlatformAdjustBreaksScroll = Platform2.OS === "android";
1163
+
1164
+ // src/core/clampScrollOffset.ts
1165
+ function clampScrollOffset(ctx, offset) {
1166
+ const state = ctx.state;
1167
+ const contentSize = getContentSize(ctx);
1168
+ let clampedOffset = offset;
1169
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform2.OS !== "android" || state.lastLayout)) {
1170
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1171
+ clampedOffset = Math.min(offset, maxOffset);
1172
+ }
1173
+ clampedOffset = Math.max(0, clampedOffset);
1174
+ return clampedOffset;
1175
+ }
1176
+
1177
+ // src/utils/setInitialRenderState.ts
1178
+ function setInitialRenderState(ctx, {
1179
+ didLayout,
1180
+ didInitialScroll
1181
+ }) {
1182
+ const { state } = ctx;
1183
+ if (didLayout) {
1184
+ state.didContainersLayout = true;
1185
+ }
1186
+ if (didInitialScroll) {
1187
+ state.didFinishInitialScroll = true;
1188
+ }
1189
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1190
+ set$(ctx, "readyToRender", true);
1191
+ }
1192
+ }
1042
1193
 
1043
1194
  // src/core/finishScrollTo.ts
1044
- function finishScrollTo(ctx, state) {
1195
+ function finishScrollTo(ctx) {
1045
1196
  var _a3, _b;
1046
- if (state) {
1197
+ const state = ctx.state;
1198
+ if (state == null ? void 0 : state.scrollingTo) {
1199
+ const scrollingTo = state.scrollingTo;
1047
1200
  state.scrollHistory.length = 0;
1048
1201
  state.initialScroll = void 0;
1049
1202
  state.initialAnchor = void 0;
1050
- set$(ctx, "scrollingTo", void 0);
1203
+ state.scrollingTo = void 0;
1051
1204
  if (state.pendingTotalSize !== void 0) {
1052
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1205
+ addTotalSize(ctx, null, state.pendingTotalSize);
1053
1206
  }
1054
1207
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1055
1208
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1056
1209
  }
1210
+ if (PlatformAdjustBreaksScroll) {
1211
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1212
+ }
1213
+ setInitialRenderState(ctx, { didInitialScroll: true });
1057
1214
  }
1058
1215
  }
1059
- var Platform2 = Platform;
1060
1216
 
1061
- // src/core/scrollTo.ts
1062
- function scrollTo(ctx, state, params) {
1217
+ // src/core/checkFinishedScroll.ts
1218
+ function checkFinishedScroll(ctx) {
1219
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1220
+ }
1221
+ function checkFinishedScrollFrame(ctx) {
1222
+ const scrollingTo = ctx.state.scrollingTo;
1223
+ if (scrollingTo) {
1224
+ const { state } = ctx;
1225
+ state.animFrameCheckFinishedScroll = void 0;
1226
+ const scroll = state.scrollPending;
1227
+ const adjust = state.scrollAdjustHandler.getAdjust();
1228
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
1229
+ const maxOffset = clampScrollOffset(ctx, scroll);
1230
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
1231
+ const diff2 = Math.abs(diff1 - adjust);
1232
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
1233
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
1234
+ finishScrollTo(ctx);
1235
+ }
1236
+ }
1237
+ }
1238
+ function checkFinishedScrollFallback(ctx) {
1239
+ const state = ctx.state;
1240
+ const scrollingTo = state.scrollingTo;
1241
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
1242
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
1243
+ () => {
1244
+ let numChecks = 0;
1245
+ const checkHasScrolled = () => {
1246
+ state.timeoutCheckFinishedScrollFallback = void 0;
1247
+ const isStillScrollingTo = state.scrollingTo;
1248
+ if (isStillScrollingTo) {
1249
+ numChecks++;
1250
+ if (state.hasScrolled || numChecks > 5) {
1251
+ finishScrollTo(ctx);
1252
+ } else {
1253
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
1254
+ }
1255
+ }
1256
+ };
1257
+ checkHasScrolled();
1258
+ },
1259
+ slowTimeout ? 500 : 100
1260
+ );
1261
+ }
1262
+
1263
+ // src/core/doScrollTo.native.ts
1264
+ function doScrollTo(ctx, params) {
1063
1265
  var _a3;
1064
- const { noScrollingTo, ...scrollTarget } = params;
1266
+ const state = ctx.state;
1267
+ const { animated, horizontal, offset } = params;
1268
+ const { refScroller } = state;
1269
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1270
+ animated: !!animated,
1271
+ x: horizontal ? offset : 0,
1272
+ y: horizontal ? 0 : offset
1273
+ });
1274
+ if (!animated) {
1275
+ state.scroll = offset;
1276
+ checkFinishedScrollFallback(ctx);
1277
+ }
1278
+ }
1279
+
1280
+ // src/core/scrollTo.ts
1281
+ function scrollTo(ctx, params) {
1282
+ const state = ctx.state;
1283
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1065
1284
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1066
1285
  const {
1067
- refScroller,
1068
1286
  props: { horizontal }
1069
1287
  } = state;
1070
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1071
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1072
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1073
- offset = Math.min(offset, maxOffset);
1288
+ if (state.animFrameCheckFinishedScroll) {
1289
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1290
+ }
1291
+ if (state.timeoutCheckFinishedScrollFallback) {
1292
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1074
1293
  }
1294
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1295
+ offset = clampScrollOffset(ctx, offset);
1075
1296
  state.scrollHistory.length = 0;
1076
1297
  if (!noScrollingTo) {
1077
- set$(ctx, "scrollingTo", scrollTarget);
1298
+ state.scrollingTo = scrollTarget;
1078
1299
  }
1079
1300
  state.scrollPending = offset;
1080
- if (!isInitialScroll || Platform2.OS === "android") {
1081
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1082
- animated: !!animated,
1083
- x: horizontal ? offset : 0,
1084
- y: horizontal ? 0 : offset
1085
- });
1086
- }
1087
- if (!animated) {
1301
+ if (forceScroll || !isInitialScroll || Platform2.OS === "android") {
1302
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1303
+ } else {
1088
1304
  state.scroll = offset;
1089
- if (Platform2.OS === "web") {
1090
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1091
- if (value && peek$(ctx, "scrollingTo")) {
1092
- finishScrollTo(ctx, state);
1093
- unlisten();
1094
- }
1095
- });
1096
- } else {
1097
- setTimeout(() => finishScrollTo(ctx, state), 100);
1098
- }
1099
- if (isInitialScroll) {
1100
- setTimeout(() => {
1101
- state.initialScroll = void 0;
1102
- }, 500);
1103
- }
1104
1305
  }
1105
1306
  }
1106
1307
 
1308
+ // src/platform/flushSync.native.ts
1309
+ var flushSync = (fn) => {
1310
+ fn();
1311
+ };
1312
+
1107
1313
  // src/utils/checkThreshold.ts
1108
1314
  var HYSTERESIS_MULTIPLIER = 1.3;
1109
- var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1315
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot, allowReentryOnChange) => {
1110
1316
  const absDistance = Math.abs(distance);
1111
1317
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1318
+ if (wasReached === null) {
1319
+ if (!within && distance >= 0) {
1320
+ return false;
1321
+ }
1322
+ return null;
1323
+ }
1112
1324
  const updateSnapshot = () => {
1113
- setSnapshot == null ? void 0 : setSnapshot({
1325
+ setSnapshot({
1114
1326
  atThreshold,
1115
1327
  contentSize: context.contentSize,
1116
1328
  dataLength: context.dataLength,
@@ -1121,19 +1333,21 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1121
1333
  if (!within) {
1122
1334
  return false;
1123
1335
  }
1124
- onReached == null ? void 0 : onReached(distance);
1336
+ onReached(distance);
1125
1337
  updateSnapshot();
1126
1338
  return true;
1127
1339
  }
1128
1340
  const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1129
1341
  if (reset) {
1130
- setSnapshot == null ? void 0 : setSnapshot(void 0);
1342
+ setSnapshot(void 0);
1131
1343
  return false;
1132
1344
  }
1133
1345
  if (within) {
1134
1346
  const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
1135
1347
  if (changed) {
1136
- onReached == null ? void 0 : onReached(distance);
1348
+ if (allowReentryOnChange) {
1349
+ onReached(distance);
1350
+ }
1137
1351
  updateSnapshot();
1138
1352
  }
1139
1353
  }
@@ -1141,8 +1355,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1141
1355
  };
1142
1356
 
1143
1357
  // src/utils/checkAtBottom.ts
1144
- function checkAtBottom(ctx, state) {
1358
+ function checkAtBottom(ctx) {
1145
1359
  var _a3;
1360
+ const state = ctx.state;
1146
1361
  if (!state) {
1147
1362
  return;
1148
1363
  }
@@ -1175,7 +1390,8 @@ function checkAtBottom(ctx, state) {
1175
1390
  },
1176
1391
  (snapshot) => {
1177
1392
  state.endReachedSnapshot = snapshot;
1178
- }
1393
+ },
1394
+ true
1179
1395
  );
1180
1396
  }
1181
1397
  }
@@ -1210,20 +1426,21 @@ function checkAtTop(state) {
1210
1426
  },
1211
1427
  (snapshot) => {
1212
1428
  state.startReachedSnapshot = snapshot;
1213
- }
1429
+ },
1430
+ false
1214
1431
  );
1215
1432
  }
1216
1433
 
1217
1434
  // src/core/updateScroll.ts
1218
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1219
- var _a3;
1220
- const scrollingTo = peek$(ctx, "scrollingTo");
1435
+ function updateScroll(ctx, newScroll, forceUpdate) {
1436
+ const state = ctx.state;
1437
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1438
+ const prevScroll = state.scroll;
1221
1439
  state.hasScrolled = true;
1222
1440
  state.lastBatchingAction = Date.now();
1223
1441
  const currentTime = Date.now();
1224
- const adjust = state.scrollAdjustHandler.getAdjust();
1225
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1226
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1442
+ const adjust = scrollAdjustHandler.getAdjust();
1443
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1227
1444
  if (adjustChanged) {
1228
1445
  state.scrollHistory.length = 0;
1229
1446
  }
@@ -1236,7 +1453,7 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1236
1453
  if (state.scrollHistory.length > 5) {
1237
1454
  state.scrollHistory.shift();
1238
1455
  }
1239
- state.scrollPrev = state.scroll;
1456
+ state.scrollPrev = prevScroll;
1240
1457
  state.scrollPrevTime = state.scrollTime;
1241
1458
  state.scroll = newScroll;
1242
1459
  state.scrollTime = currentTime;
@@ -1248,22 +1465,38 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1248
1465
  return;
1249
1466
  }
1250
1467
  }
1251
- if (forceUpdate || state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1468
+ const scrollDelta = Math.abs(newScroll - prevScroll);
1469
+ const scrollLength = state.scrollLength;
1470
+ const lastCalculated = state.scrollLastCalculate;
1471
+ const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1472
+ if (shouldUpdate) {
1473
+ state.scrollLastCalculate = state.scroll;
1252
1474
  state.ignoreScrollFromMVCPIgnored = false;
1253
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1254
- checkAtBottom(ctx, state);
1255
- checkAtTop(state);
1475
+ state.lastScrollDelta = scrollDelta;
1476
+ const runCalculateItems = () => {
1477
+ var _a3;
1478
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1479
+ checkAtBottom(ctx);
1480
+ checkAtTop(state);
1481
+ };
1482
+ if (Platform2.OS === "web" && scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
1483
+ flushSync(runCalculateItems);
1484
+ } else {
1485
+ runCalculateItems();
1486
+ }
1256
1487
  state.dataChangeNeedsScrollUpdate = false;
1488
+ state.lastScrollDelta = 0;
1257
1489
  }
1258
1490
  }
1259
1491
 
1260
1492
  // src/utils/requestAdjust.ts
1261
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1493
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1494
+ const state = ctx.state;
1262
1495
  if (Math.abs(positionDiff) > 0.1) {
1263
1496
  const needsScrollWorkaround = Platform2.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
1264
1497
  const doit = () => {
1265
1498
  if (needsScrollWorkaround) {
1266
- scrollTo(ctx, state, {
1499
+ scrollTo(ctx, {
1267
1500
  noScrollingTo: true,
1268
1501
  offset: state.scroll
1269
1502
  });
@@ -1276,8 +1509,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1276
1509
  };
1277
1510
  state.scroll += positionDiff;
1278
1511
  state.scrollForNextCalculateItemsInView = void 0;
1279
- const didLayout = peek$(ctx, "containersDidLayout");
1280
- if (didLayout) {
1512
+ const readyToRender = peek$(ctx, "readyToRender");
1513
+ if (readyToRender) {
1281
1514
  doit();
1282
1515
  if (Platform2.OS !== "web") {
1283
1516
  const threshold = state.scroll - positionDiff / 2;
@@ -1299,7 +1532,7 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1299
1532
  if (shouldForceUpdate) {
1300
1533
  state.ignoreScrollFromMVCPIgnored = false;
1301
1534
  state.scrollPending = state.scroll;
1302
- updateScroll(ctx, state, state.scroll, true);
1535
+ updateScroll(ctx, state.scroll, true);
1303
1536
  }
1304
1537
  }, delay);
1305
1538
  }
@@ -1314,28 +1547,27 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1314
1547
  var INITIAL_ANCHOR_TOLERANCE = 0.5;
1315
1548
  var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1316
1549
  var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1317
- function ensureInitialAnchor(ctx, state) {
1550
+ function ensureInitialAnchor(ctx) {
1318
1551
  var _a3, _b, _c, _d, _e;
1319
- const anchor = state.initialAnchor;
1552
+ const state = ctx.state;
1553
+ const { initialAnchor, didContainersLayout, positions, scroll, scrollLength } = state;
1554
+ const anchor = initialAnchor;
1320
1555
  const item = state.props.data[anchor.index];
1321
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1322
- if (!containersDidLayout) {
1556
+ if (!didContainersLayout) {
1323
1557
  return;
1324
1558
  }
1325
1559
  const id = getId(state, anchor.index);
1326
- if (state.positions.get(id) === void 0) {
1560
+ if (positions.get(id) === void 0) {
1327
1561
  return;
1328
1562
  }
1329
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1563
+ const size = getItemSize(ctx, id, anchor.index, item, true, true);
1330
1564
  if (size === void 0) {
1331
1565
  return;
1332
1566
  }
1333
- const availableSpace = Math.max(0, state.scrollLength - size);
1334
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1335
- const contentSize = getContentSize(ctx);
1336
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1337
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1338
- const delta = clampedDesiredOffset - state.scroll;
1567
+ const availableSpace = Math.max(0, scrollLength - size);
1568
+ const desiredOffset = calculateOffsetForIndex(ctx, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1569
+ const clampedDesiredOffset = clampScrollOffset(ctx, desiredOffset);
1570
+ const delta = clampedDesiredOffset - scroll;
1339
1571
  if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1340
1572
  const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1341
1573
  if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
@@ -1359,19 +1591,24 @@ function ensureInitialAnchor(ctx, state) {
1359
1591
  lastDelta: delta,
1360
1592
  settledTicks: 0
1361
1593
  });
1362
- requestAdjust(ctx, state, delta);
1594
+ requestAdjust(ctx, delta);
1595
+ requestAnimationFrame(() => finishScrollTo(ctx));
1363
1596
  }
1364
1597
 
1365
1598
  // src/core/mvcp.ts
1366
- function prepareMVCP(ctx, state, dataChanged) {
1599
+ function prepareMVCP(ctx, dataChanged) {
1600
+ const state = ctx.state;
1367
1601
  const { idsInView, positions, props } = state;
1368
- const { maintainVisibleContentPosition } = props;
1369
- const scrollingTo = peek$(ctx, "scrollingTo");
1602
+ const {
1603
+ maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll, shouldRestorePosition }
1604
+ } = props;
1605
+ const scrollingTo = state.scrollingTo;
1370
1606
  let prevPosition;
1371
1607
  let targetId;
1372
1608
  const idsInViewWithPositions = [];
1373
1609
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1374
- const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1610
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1611
+ const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1375
1612
  const indexByKey = state.indexByKey;
1376
1613
  if (shouldMVCP) {
1377
1614
  if (scrollTarget !== void 0) {
@@ -1379,7 +1616,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1379
1616
  return void 0;
1380
1617
  }
1381
1618
  targetId = getId(state, scrollTarget);
1382
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1619
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1383
1620
  if (dataChanged) {
1384
1621
  for (let i = 0; i < idsInView.length; i++) {
1385
1622
  const id = idsInView[i];
@@ -1396,10 +1633,18 @@ function prepareMVCP(ctx, state, dataChanged) {
1396
1633
  prevPosition = positions.get(targetId);
1397
1634
  }
1398
1635
  return () => {
1399
- let positionDiff;
1400
- if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1636
+ let positionDiff = 0;
1637
+ if (dataChanged && targetId === void 0 && mvcpData) {
1638
+ const data = state.props.data;
1401
1639
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1402
1640
  const { id, position } = idsInViewWithPositions[i];
1641
+ const index = indexByKey.get(id);
1642
+ if (index !== void 0 && shouldRestorePosition) {
1643
+ const item = data[index];
1644
+ if (item === void 0 || !shouldRestorePosition(item, index, data)) {
1645
+ continue;
1646
+ }
1647
+ }
1403
1648
  const newPosition = positions.get(id);
1404
1649
  if (newPosition !== void 0) {
1405
1650
  positionDiff = newPosition - position;
@@ -1422,16 +1667,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1422
1667
  positionDiff = diff;
1423
1668
  }
1424
1669
  }
1425
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1426
- requestAdjust(ctx, state, positionDiff, dataChanged && maintainVisibleContentPosition);
1670
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1671
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1672
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1673
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1674
+ const diff = newSize - prevSize;
1675
+ if (diff !== 0) {
1676
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1677
+ scrollingTo.itemSize = newSize;
1678
+ }
1679
+ }
1680
+ }
1681
+ if (Math.abs(positionDiff) > 0.1) {
1682
+ requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
1427
1683
  }
1428
1684
  };
1429
1685
  }
1430
1686
  }
1431
1687
 
1432
1688
  // src/core/prepareColumnStartState.ts
1433
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1689
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1434
1690
  var _a3;
1691
+ const state = ctx.state;
1435
1692
  const numColumns = peek$(ctx, "numColumns");
1436
1693
  let rowStartIndex = startIndex;
1437
1694
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1446,7 +1703,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1446
1703
  const prevId = state.idCache[prevIndex];
1447
1704
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1448
1705
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1449
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1706
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1450
1707
  currentRowTop = prevPosition + prevRowHeight;
1451
1708
  }
1452
1709
  return {
@@ -1469,7 +1726,8 @@ function findRowStartIndex(state, numColumns, index) {
1469
1726
  }
1470
1727
  return rowStart;
1471
1728
  }
1472
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1729
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1730
+ const state = ctx.state;
1473
1731
  if (endIndex < startIndex) {
1474
1732
  return 0;
1475
1733
  }
@@ -1483,7 +1741,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1483
1741
  continue;
1484
1742
  }
1485
1743
  const id = state.idCache[i];
1486
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1744
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1487
1745
  if (size > maxSize) {
1488
1746
  maxSize = size;
1489
1747
  }
@@ -1492,22 +1750,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1492
1750
  }
1493
1751
 
1494
1752
  // src/core/updateTotalSize.ts
1495
- function updateTotalSize(ctx, state) {
1753
+ function updateTotalSize(ctx) {
1754
+ const state = ctx.state;
1496
1755
  const {
1497
1756
  positions,
1498
1757
  props: { data }
1499
1758
  } = state;
1500
1759
  if (data.length === 0) {
1501
- addTotalSize(ctx, state, null, 0);
1760
+ addTotalSize(ctx, null, 0);
1502
1761
  } else {
1503
1762
  const lastId = getId(state, data.length - 1);
1504
1763
  if (lastId !== void 0) {
1505
1764
  const lastPosition = positions.get(lastId);
1506
1765
  if (lastPosition !== void 0) {
1507
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1766
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1508
1767
  if (lastSize !== void 0) {
1509
1768
  const totalSize = lastPosition + lastSize;
1510
- addTotalSize(ctx, state, null, totalSize);
1769
+ addTotalSize(ctx, null, totalSize);
1511
1770
  }
1512
1771
  }
1513
1772
  }
@@ -1517,43 +1776,45 @@ function updateTotalSize(ctx, state) {
1517
1776
  // src/utils/getScrollVelocity.ts
1518
1777
  var getScrollVelocity = (state) => {
1519
1778
  const { scrollHistory } = state;
1520
- let velocity = 0;
1521
- if (scrollHistory.length >= 1) {
1522
- const newest = scrollHistory[scrollHistory.length - 1];
1523
- let oldest;
1524
- let start = 0;
1525
- const now = Date.now();
1526
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1527
- const entry = scrollHistory[i];
1528
- const nextEntry = scrollHistory[i + 1];
1529
- if (i > 0) {
1530
- const prevEntry = scrollHistory[i - 1];
1531
- const prevDirection = entry.scroll - prevEntry.scroll;
1532
- const currentDirection = nextEntry.scroll - entry.scroll;
1533
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1534
- start = i;
1535
- break;
1536
- }
1537
- }
1779
+ const newestIndex = scrollHistory.length - 1;
1780
+ if (newestIndex < 1) {
1781
+ return 0;
1782
+ }
1783
+ const newest = scrollHistory[newestIndex];
1784
+ const now = Date.now();
1785
+ let direction = 0;
1786
+ for (let i = newestIndex; i > 0; i--) {
1787
+ const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
1788
+ if (delta !== 0) {
1789
+ direction = Math.sign(delta);
1790
+ break;
1538
1791
  }
1539
- for (let i = start; i < scrollHistory.length - 1; i++) {
1540
- const entry = scrollHistory[i];
1541
- if (now - entry.time <= 1e3) {
1542
- oldest = entry;
1543
- break;
1544
- }
1792
+ }
1793
+ if (direction === 0) {
1794
+ return 0;
1795
+ }
1796
+ let oldest = newest;
1797
+ for (let i = newestIndex - 1; i >= 0; i--) {
1798
+ const current = scrollHistory[i];
1799
+ const next = scrollHistory[i + 1];
1800
+ const delta = next.scroll - current.scroll;
1801
+ const deltaSign = Math.sign(delta);
1802
+ if (deltaSign !== 0 && deltaSign !== direction) {
1803
+ break;
1545
1804
  }
1546
- if (oldest && oldest !== newest) {
1547
- const scrollDiff = newest.scroll - oldest.scroll;
1548
- const timeDiff = newest.time - oldest.time;
1549
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1805
+ if (now - current.time > 1e3) {
1806
+ break;
1550
1807
  }
1808
+ oldest = current;
1551
1809
  }
1552
- return velocity;
1810
+ const scrollDiff = newest.scroll - oldest.scroll;
1811
+ const timeDiff = newest.time - oldest.time;
1812
+ return timeDiff > 0 ? scrollDiff / timeDiff : 0;
1553
1813
  };
1554
1814
 
1555
1815
  // src/utils/updateSnapToOffsets.ts
1556
- function updateSnapToOffsets(ctx, state) {
1816
+ function updateSnapToOffsets(ctx) {
1817
+ const state = ctx.state;
1557
1818
  const {
1558
1819
  positions,
1559
1820
  props: { snapToIndices }
@@ -1568,30 +1829,32 @@ function updateSnapToOffsets(ctx, state) {
1568
1829
  }
1569
1830
 
1570
1831
  // src/core/updateItemPositions.ts
1571
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1832
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1572
1833
  doMVCP: false,
1573
1834
  forceFullUpdate: false,
1574
1835
  scrollBottomBuffered: -1,
1575
1836
  startIndex: 0
1576
1837
  }) {
1577
1838
  var _a3, _b, _c, _d, _e;
1839
+ const state = ctx.state;
1578
1840
  const {
1579
1841
  columns,
1580
1842
  indexByKey,
1581
1843
  positions,
1582
1844
  idCache,
1583
1845
  sizesKnown,
1584
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1846
+ props: { data, getEstimatedItemSize, snapToIndices },
1847
+ scrollingTo
1585
1848
  } = state;
1586
- const data = state.props.data;
1587
1849
  const dataLength = data.length;
1588
1850
  const numColumns = peek$(ctx, "numColumns");
1589
- const scrollingTo = peek$(ctx, "scrollingTo");
1590
1851
  const hasColumns = numColumns > 1;
1591
1852
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1592
- const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1853
+ const lastScrollDelta = state.lastScrollDelta;
1854
+ const velocity = getScrollVelocity(state);
1855
+ const shouldOptimize = !forceFullUpdate && !dataChanged && (Math.abs(velocity) > 0 || Platform2.OS === "web" && state.scrollLength > 0 && lastScrollDelta > state.scrollLength);
1593
1856
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1594
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1857
+ const useAverageSize = !getEstimatedItemSize;
1595
1858
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1596
1859
  let currentRowTop = 0;
1597
1860
  let column = 1;
@@ -1600,7 +1863,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1600
1863
  if (hasColumns) {
1601
1864
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1602
1865
  ctx,
1603
- state,
1604
1866
  startIndex,
1605
1867
  useAverageSize
1606
1868
  );
@@ -1610,7 +1872,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1610
1872
  const prevIndex = startIndex - 1;
1611
1873
  const prevId = getId(state, prevIndex);
1612
1874
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1613
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1875
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1614
1876
  currentRowTop = prevPosition + prevSize;
1615
1877
  }
1616
1878
  }
@@ -1627,7 +1889,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1627
1889
  breakAt = i + itemsPerRow + 10;
1628
1890
  }
1629
1891
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1630
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1892
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1631
1893
  if (IS_DEV && needsIndexByKey) {
1632
1894
  if (indexByKeyForChecking.has(id)) {
1633
1895
  console.error(
@@ -1636,7 +1898,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1636
1898
  }
1637
1899
  indexByKeyForChecking.set(id, i);
1638
1900
  }
1639
- positions.set(id, currentRowTop);
1901
+ if (currentRowTop !== positions.get(id)) {
1902
+ positions.set(id, currentRowTop);
1903
+ notifyPosition$(ctx, id, currentRowTop);
1904
+ }
1640
1905
  if (needsIndexByKey) {
1641
1906
  indexByKey.set(id, i);
1642
1907
  }
@@ -1656,10 +1921,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1656
1921
  }
1657
1922
  }
1658
1923
  if (!didBreakEarly) {
1659
- updateTotalSize(ctx, state);
1924
+ updateTotalSize(ctx);
1660
1925
  }
1661
1926
  if (snapToIndices) {
1662
- updateSnapToOffsets(ctx, state);
1927
+ updateSnapToOffsets(ctx);
1663
1928
  }
1664
1929
  }
1665
1930
 
@@ -1737,7 +2002,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1737
2002
  if (previousViewableItems) {
1738
2003
  for (const viewToken of previousViewableItems) {
1739
2004
  const containerId = findContainerId(ctx, viewToken.key);
1740
- if (!isViewable(
2005
+ if (!checkIsViewable(
1741
2006
  state,
1742
2007
  ctx,
1743
2008
  viewabilityConfig,
@@ -1758,7 +2023,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1758
2023
  if (item) {
1759
2024
  const key = getId(state, i);
1760
2025
  const containerId = findContainerId(ctx, key);
1761
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2026
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1762
2027
  const viewToken = {
1763
2028
  containerId,
1764
2029
  index: i,
@@ -1818,11 +2083,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1818
2083
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
1819
2084
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
1820
2085
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
1821
- const isViewable2 = percent >= viewablePercentThreshold;
2086
+ const isViewable = percent >= viewablePercentThreshold;
1822
2087
  const value = {
1823
2088
  containerId,
1824
2089
  index,
1825
- isViewable: isViewable2,
2090
+ isViewable,
1826
2091
  item,
1827
2092
  key,
1828
2093
  percentOfScroller,
@@ -1841,8 +2106,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1841
2106
  }
1842
2107
  return value;
1843
2108
  }
1844
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
1845
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2109
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2110
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2111
+ if (!value || value.key !== key) {
2112
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2113
+ }
1846
2114
  return value.isViewable;
1847
2115
  }
1848
2116
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -1870,8 +2138,9 @@ function checkAllSizesKnown(state) {
1870
2138
  }
1871
2139
 
1872
2140
  // src/utils/findAvailableContainers.ts
1873
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2141
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
1874
2142
  const numContainers = peek$(ctx, "numContainers");
2143
+ const state = ctx.state;
1875
2144
  const { stickyContainerPool, containerItemTypes } = state;
1876
2145
  const result = [];
1877
2146
  const availableContainers = [];
@@ -1991,21 +2260,26 @@ function comparatorByDistance(a, b) {
1991
2260
  }
1992
2261
 
1993
2262
  // src/core/scrollToIndex.ts
1994
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1995
- if (index >= state.props.data.length) {
1996
- index = state.props.data.length - 1;
2263
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2264
+ const state = ctx.state;
2265
+ const { data } = state.props;
2266
+ if (index >= data.length) {
2267
+ index = data.length - 1;
1997
2268
  } else if (index < 0) {
1998
2269
  index = 0;
1999
2270
  }
2000
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2001
- const isLast = index === state.props.data.length - 1;
2271
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2272
+ const isLast = index === data.length - 1;
2002
2273
  if (isLast && viewPosition === void 0) {
2003
2274
  viewPosition = 1;
2004
2275
  }
2005
2276
  state.scrollForNextCalculateItemsInView = void 0;
2006
- scrollTo(ctx, state, {
2277
+ const targetId = getId(state, index);
2278
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2279
+ scrollTo(ctx, {
2007
2280
  animated,
2008
2281
  index,
2282
+ itemSize,
2009
2283
  offset: firstIndexOffset,
2010
2284
  viewOffset,
2011
2285
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2013,34 +2287,28 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2013
2287
  }
2014
2288
 
2015
2289
  // src/utils/setDidLayout.ts
2016
- function setDidLayout(ctx, state) {
2290
+ function setDidLayout(ctx) {
2291
+ const state = ctx.state;
2017
2292
  const {
2018
2293
  loadStartTime,
2019
2294
  initialScroll,
2020
2295
  props: { onLoad }
2021
2296
  } = state;
2022
2297
  state.queuedInitialLayout = true;
2023
- checkAtBottom(ctx, state);
2298
+ checkAtBottom(ctx);
2024
2299
  const setIt = () => {
2025
- set$(ctx, "containersDidLayout", true);
2300
+ setInitialRenderState(ctx, { didLayout: true });
2026
2301
  if (onLoad) {
2027
2302
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2028
2303
  }
2029
2304
  };
2030
- if (Platform2.OS === "android" && initialScroll) {
2031
- if (IsNewArchitecture) {
2032
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2033
- requestAnimationFrame(() => {
2034
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2035
- setIt();
2036
- });
2037
- } else {
2038
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2039
- setIt();
2040
- }
2041
- } else {
2042
- setIt();
2305
+ if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
2306
+ const target = initialScroll;
2307
+ const runScroll = () => scrollToIndex(ctx, { ...target, animated: false });
2308
+ runScroll();
2309
+ requestAnimationFrame(runScroll);
2043
2310
  }
2311
+ setIt();
2044
2312
  }
2045
2313
 
2046
2314
  // src/core/calculateItemsInView.ts
@@ -2058,31 +2326,36 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2058
2326
  }
2059
2327
  return -1;
2060
2328
  }
2061
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2329
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2330
+ const state = ctx.state;
2062
2331
  return new Set(
2063
2332
  Array.from(state.stickyContainerPool).map((i) => peek$(ctx, `containerItemKey${i}`)).map((key) => key ? state.indexByKey.get(key) : void 0).filter((idx) => idx !== void 0 && stickyHeaderIndices.has(idx))
2064
2333
  );
2065
2334
  }
2066
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2335
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, needNewContainersSet, startBuffered, endBuffered) {
2067
2336
  var _a3;
2068
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2069
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2337
+ const state = ctx.state;
2338
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2339
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2070
2340
  for (let offset = 0; offset <= 1; offset++) {
2071
2341
  const idx = currentStickyIdx - offset;
2072
2342
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
2073
2343
  const stickyIndex = stickyArray[idx];
2074
2344
  const stickyId = (_a3 = state.idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
2075
- if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
2345
+ if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered) && !needNewContainersSet.has(stickyIndex)) {
2346
+ needNewContainersSet.add(stickyIndex);
2076
2347
  needNewContainers.push(stickyIndex);
2077
2348
  }
2078
2349
  }
2079
2350
  }
2080
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2351
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2081
2352
  var _a3, _b, _c;
2353
+ const state = ctx.state;
2082
2354
  for (const containerIndex of state.stickyContainerPool) {
2083
2355
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2084
2356
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
2085
2357
  if (itemIndex === void 0) continue;
2358
+ if (alwaysRenderIndicesSet.has(itemIndex)) continue;
2086
2359
  const arrayIdx = stickyArray.indexOf(itemIndex);
2087
2360
  if (arrayIdx === -1) {
2088
2361
  state.stickyContainerPool.delete(containerIndex);
@@ -2102,7 +2375,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2102
2375
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2103
2376
  if (currentId) {
2104
2377
  const currentPos = state.positions.get(currentId);
2105
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2378
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2106
2379
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2107
2380
  }
2108
2381
  }
@@ -2111,9 +2384,10 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2111
2384
  }
2112
2385
  }
2113
2386
  }
2114
- function calculateItemsInView(ctx, state, params = {}) {
2387
+ function calculateItemsInView(ctx, params = {}) {
2388
+ const state = ctx.state;
2115
2389
  unstable_batchedUpdates(() => {
2116
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2390
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
2117
2391
  const {
2118
2392
  columns,
2119
2393
  containerItemKeys,
@@ -2123,7 +2397,15 @@ function calculateItemsInView(ctx, state, params = {}) {
2123
2397
  initialScroll,
2124
2398
  minIndexSizeChanged,
2125
2399
  positions,
2126
- props: { getItemType, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer },
2400
+ props: {
2401
+ alwaysRenderIndicesArr,
2402
+ alwaysRenderIndicesSet,
2403
+ getItemType,
2404
+ itemsAreEqual,
2405
+ keyExtractor,
2406
+ onStickyHeaderChange,
2407
+ scrollBuffer
2408
+ },
2127
2409
  scrollForNextCalculateItemsInView,
2128
2410
  scrollLength,
2129
2411
  sizes,
@@ -2133,10 +2415,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2133
2415
  const { data } = state.props;
2134
2416
  const stickyIndicesArr = state.props.stickyIndicesArr || [];
2135
2417
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2418
+ const alwaysRenderArr = alwaysRenderIndicesArr || [];
2419
+ const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
2136
2420
  const prevNumContainers = peek$(ctx, "numContainers");
2137
2421
  if (!data || scrollLength === 0 || !prevNumContainers) {
2138
- if (state.initialAnchor) {
2139
- ensureInitialAnchor(ctx, state);
2422
+ if (!IsNewArchitecture && state.initialAnchor) {
2423
+ ensureInitialAnchor(ctx);
2140
2424
  }
2141
2425
  return;
2142
2426
  }
@@ -2151,15 +2435,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2151
2435
  if (!queuedInitialLayout && initialScroll) {
2152
2436
  const updatedOffset = calculateOffsetWithOffsetPosition(
2153
2437
  ctx,
2154
- state,
2155
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2438
+ calculateOffsetForIndex(ctx, initialScroll.index),
2156
2439
  initialScroll
2157
2440
  );
2158
2441
  scrollState = updatedOffset;
2159
2442
  }
2160
2443
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2161
2444
  const scrollAdjustPad = scrollAdjustPending - topPad;
2162
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2445
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2163
2446
  if (scroll + scrollLength > totalSize) {
2164
2447
  scroll = Math.max(0, totalSize - scrollLength);
2165
2448
  }
@@ -2167,11 +2450,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2167
2450
  set$(ctx, "debugRawScroll", scrollState);
2168
2451
  set$(ctx, "debugComputedScroll", scroll);
2169
2452
  }
2170
- const previousStickyIndex = state.activeStickyIndex;
2453
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2171
2454
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2172
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2173
- state.activeStickyIndex = nextActiveStickyIndex;
2174
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2455
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2456
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2457
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2458
+ }
2175
2459
  let scrollBufferTop = scrollBuffer;
2176
2460
  let scrollBufferBottom = scrollBuffer;
2177
2461
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2184,23 +2468,25 @@ function calculateItemsInView(ctx, state, params = {}) {
2184
2468
  const scrollTopBuffered = scroll - scrollBufferTop;
2185
2469
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2186
2470
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2187
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2471
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2188
2472
  const { top, bottom } = scrollForNextCalculateItemsInView;
2189
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2190
- if (state.initialAnchor) {
2191
- ensureInitialAnchor(ctx, state);
2473
+ if (top === null && bottom === null) {
2474
+ state.scrollForNextCalculateItemsInView = void 0;
2475
+ } else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2476
+ if (!IsNewArchitecture && state.initialAnchor) {
2477
+ ensureInitialAnchor(ctx);
2192
2478
  }
2193
2479
  return;
2194
2480
  }
2195
2481
  }
2196
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2482
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2197
2483
  if (dataChanged) {
2198
2484
  indexByKey.clear();
2199
2485
  idCache.length = 0;
2200
2486
  positions.clear();
2201
2487
  }
2202
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2203
- updateItemPositions(ctx, state, dataChanged, {
2488
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2489
+ updateItemPositions(ctx, dataChanged, {
2204
2490
  doMVCP,
2205
2491
  forceFullUpdate: !!forceFullItemPositions,
2206
2492
  scrollBottomBuffered,
@@ -2219,9 +2505,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2219
2505
  for (let i = loopStart; i >= 0; i--) {
2220
2506
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2221
2507
  const top = positions.get(id);
2222
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2508
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2223
2509
  const bottom = top + size;
2224
- if (bottom > scroll - scrollBuffer) {
2510
+ if (bottom > scroll - scrollBufferTop) {
2225
2511
  loopStart = i;
2226
2512
  } else {
2227
2513
  break;
@@ -2246,7 +2532,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2246
2532
  const dataLength = data.length;
2247
2533
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2248
2534
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2249
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2535
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2250
2536
  const top = positions.get(id);
2251
2537
  if (!foundEnd) {
2252
2538
  if (startNoBuffer === null && top + size > scroll) {
@@ -2258,7 +2544,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2258
2544
  if (startBuffered === null && top + size > scrollTopBuffered) {
2259
2545
  startBuffered = i;
2260
2546
  startBufferedId = id;
2261
- nextTop = top;
2547
+ if (scrollTopBuffered < 0) {
2548
+ nextTop = null;
2549
+ } else {
2550
+ nextTop = top;
2551
+ }
2262
2552
  }
2263
2553
  if (startNoBuffer !== null) {
2264
2554
  if (top <= scrollBottom) {
@@ -2266,7 +2556,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2266
2556
  }
2267
2557
  if (top <= scrollBottomBuffered) {
2268
2558
  endBuffered = i;
2269
- nextBottom = top + size;
2559
+ if (scrollBottomBuffered > totalSize) {
2560
+ nextBottom = null;
2561
+ } else {
2562
+ nextBottom = top + size;
2563
+ }
2270
2564
  } else {
2271
2565
  foundEnd = true;
2272
2566
  }
@@ -2288,12 +2582,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2288
2582
  startNoBuffer
2289
2583
  });
2290
2584
  if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
2291
- state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
2585
+ state.scrollForNextCalculateItemsInView = isNullOrUndefined(nextTop) && isNullOrUndefined(nextBottom) ? void 0 : {
2292
2586
  bottom: nextBottom,
2293
2587
  top: nextTop
2294
- } : void 0;
2588
+ };
2295
2589
  }
2296
- const numContainers = peek$(ctx, "numContainers");
2590
+ let numContainers = prevNumContainers;
2297
2591
  const pendingRemoval = [];
2298
2592
  if (dataChanged) {
2299
2593
  for (let i = 0; i < numContainers; i++) {
@@ -2304,37 +2598,46 @@ function calculateItemsInView(ctx, state, params = {}) {
2304
2598
  }
2305
2599
  }
2306
2600
  if (startBuffered !== null && endBuffered !== null) {
2307
- let numContainers2 = prevNumContainers;
2308
2601
  const needNewContainers = [];
2602
+ const needNewContainersSet = /* @__PURE__ */ new Set();
2309
2603
  for (let i = startBuffered; i <= endBuffered; i++) {
2310
2604
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2311
2605
  if (!containerItemKeys.has(id)) {
2606
+ needNewContainersSet.add(i);
2312
2607
  needNewContainers.push(i);
2313
2608
  }
2314
2609
  }
2610
+ if (alwaysRenderArr.length > 0) {
2611
+ for (const index of alwaysRenderArr) {
2612
+ if (index < 0 || index >= dataLength) continue;
2613
+ const id = (_i = idCache[index]) != null ? _i : getId(state, index);
2614
+ if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
2615
+ needNewContainersSet.add(index);
2616
+ needNewContainers.push(index);
2617
+ }
2618
+ }
2619
+ }
2315
2620
  if (stickyIndicesArr.length > 0) {
2316
2621
  handleStickyActivation(
2317
2622
  ctx,
2318
- state,
2319
2623
  stickyIndicesSet,
2320
2624
  stickyIndicesArr,
2321
2625
  currentStickyIdx,
2322
2626
  needNewContainers,
2627
+ needNewContainersSet,
2323
2628
  startBuffered,
2324
2629
  endBuffered
2325
2630
  );
2326
- } else {
2327
- state.activeStickyIndex = void 0;
2328
- set$(ctx, "activeStickyIndex", void 0);
2631
+ } else if (previousStickyIndex !== -1) {
2632
+ set$(ctx, "activeStickyIndex", -1);
2329
2633
  }
2330
2634
  if (needNewContainers.length > 0) {
2331
2635
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2332
2636
  const itemType = getItemType(data[i], i);
2333
- return itemType ? String(itemType) : "";
2637
+ return itemType !== void 0 ? String(itemType) : "";
2334
2638
  }) : void 0;
2335
2639
  const availableContainers = findAvailableContainers(
2336
2640
  ctx,
2337
- state,
2338
2641
  needNewContainers.length,
2339
2642
  startBuffered,
2340
2643
  endBuffered,
@@ -2345,7 +2648,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2345
2648
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2346
2649
  const i = needNewContainers[idx];
2347
2650
  const containerIndex = availableContainers[idx];
2348
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
2651
+ const id = (_j = idCache[i]) != null ? _j : getId(state, i);
2349
2652
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2350
2653
  if (oldKey && oldKey !== id) {
2351
2654
  containerItemKeys.delete(oldKey);
@@ -2355,30 +2658,58 @@ function calculateItemsInView(ctx, state, params = {}) {
2355
2658
  if (requiredItemTypes) {
2356
2659
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2357
2660
  }
2358
- containerItemKeys.add(id);
2359
- if (stickyIndicesSet.has(i)) {
2360
- set$(ctx, `containerSticky${containerIndex}`, true);
2661
+ containerItemKeys.set(id, containerIndex);
2662
+ const containerSticky = `containerSticky${containerIndex}`;
2663
+ const isSticky = stickyIndicesSet.has(i);
2664
+ const isAlwaysRender = alwaysRenderSet.has(i);
2665
+ if (isSticky) {
2666
+ set$(ctx, containerSticky, true);
2361
2667
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2362
2668
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2363
2669
  state.stickyContainerPool.add(containerIndex);
2364
2670
  } else {
2365
- set$(ctx, `containerSticky${containerIndex}`, false);
2366
- state.stickyContainerPool.delete(containerIndex);
2671
+ if (peek$(ctx, containerSticky)) {
2672
+ set$(ctx, containerSticky, false);
2673
+ set$(ctx, `containerStickyOffset${containerIndex}`, void 0);
2674
+ }
2675
+ if (isAlwaysRender) {
2676
+ state.stickyContainerPool.add(containerIndex);
2677
+ } else if (state.stickyContainerPool.has(containerIndex)) {
2678
+ state.stickyContainerPool.delete(containerIndex);
2679
+ }
2367
2680
  }
2368
- if (containerIndex >= numContainers2) {
2369
- numContainers2 = containerIndex + 1;
2681
+ if (containerIndex >= numContainers) {
2682
+ numContainers = containerIndex + 1;
2370
2683
  }
2371
2684
  }
2372
- if (numContainers2 !== prevNumContainers) {
2373
- set$(ctx, "numContainers", numContainers2);
2374
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2375
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2685
+ if (numContainers !== prevNumContainers) {
2686
+ set$(ctx, "numContainers", numContainers);
2687
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2688
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2689
+ }
2690
+ }
2691
+ }
2692
+ if (alwaysRenderArr.length > 0) {
2693
+ for (const index of alwaysRenderArr) {
2694
+ if (index < 0 || index >= dataLength) continue;
2695
+ const id = (_k = idCache[index]) != null ? _k : getId(state, index);
2696
+ const containerIndex = containerItemKeys.get(id);
2697
+ if (containerIndex !== void 0) {
2698
+ state.stickyContainerPool.add(containerIndex);
2376
2699
  }
2377
2700
  }
2378
2701
  }
2379
2702
  }
2380
- if (stickyIndicesArr.length > 0) {
2381
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2703
+ if (state.stickyContainerPool.size > 0) {
2704
+ handleStickyRecycling(
2705
+ ctx,
2706
+ stickyIndicesArr,
2707
+ scroll,
2708
+ scrollBuffer,
2709
+ currentStickyIdx,
2710
+ pendingRemoval,
2711
+ alwaysRenderSet
2712
+ );
2382
2713
  }
2383
2714
  let didChangePositions = false;
2384
2715
  for (let i = 0; i < numContainers; i++) {
@@ -2401,7 +2732,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2401
2732
  const itemIndex = indexByKey.get(itemKey);
2402
2733
  const item = data[itemIndex];
2403
2734
  if (item !== void 0) {
2404
- const id = (_j = idCache[itemIndex]) != null ? _j : getId(state, itemIndex);
2735
+ const id = (_l = idCache[itemIndex]) != null ? _l : getId(state, itemIndex);
2405
2736
  const positionValue = positions.get(id);
2406
2737
  if (positionValue === void 0) {
2407
2738
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
@@ -2430,7 +2761,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2430
2761
  }
2431
2762
  if (!queuedInitialLayout && endBuffered !== null) {
2432
2763
  if (checkAllSizesKnown(state)) {
2433
- setDidLayout(ctx, state);
2764
+ setDidLayout(ctx);
2434
2765
  }
2435
2766
  }
2436
2767
  if (viewabilityConfigCallbackPairs) {
@@ -2443,8 +2774,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2443
2774
  }
2444
2775
  }
2445
2776
  });
2446
- if (state.initialAnchor) {
2447
- ensureInitialAnchor(ctx, state);
2777
+ if (!IsNewArchitecture && state.initialAnchor) {
2778
+ ensureInitialAnchor(ctx);
2448
2779
  }
2449
2780
  }
2450
2781
 
@@ -2469,19 +2800,22 @@ function checkActualChange(state, dataProp, previousData) {
2469
2800
  }
2470
2801
 
2471
2802
  // src/core/doMaintainScrollAtEnd.ts
2472
- function doMaintainScrollAtEnd(ctx, state, animated) {
2803
+ function doMaintainScrollAtEnd(ctx, animated) {
2804
+ const state = ctx.state;
2473
2805
  const {
2806
+ didContainersLayout,
2807
+ isAtEnd,
2474
2808
  refScroller,
2475
2809
  props: { maintainScrollAtEnd }
2476
2810
  } = state;
2477
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2811
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2478
2812
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2479
2813
  if (paddingTop > 0) {
2480
2814
  state.scroll = 0;
2481
2815
  }
2482
2816
  requestAnimationFrame(() => {
2483
2817
  var _a3;
2484
- if (state == null ? void 0 : state.isAtEnd) {
2818
+ if (state.isAtEnd) {
2485
2819
  state.maintainingScrollAtEnd = true;
2486
2820
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2487
2821
  animated
@@ -2552,28 +2886,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2552
2886
  }
2553
2887
 
2554
2888
  // src/core/checkResetContainers.ts
2555
- function checkResetContainers(ctx, state, dataProp) {
2889
+ function checkResetContainers(ctx, dataProp) {
2890
+ const state = ctx.state;
2556
2891
  const { previousData } = state;
2557
2892
  if (previousData) {
2558
2893
  updateAveragesOnDataChange(state, previousData, dataProp);
2559
2894
  }
2560
2895
  const { maintainScrollAtEnd } = state.props;
2561
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2896
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2562
2897
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2563
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2898
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2564
2899
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2565
2900
  state.isEndReached = false;
2566
2901
  }
2567
2902
  if (!didMaintainScrollAtEnd) {
2568
2903
  checkAtTop(state);
2569
- checkAtBottom(ctx, state);
2904
+ checkAtBottom(ctx);
2570
2905
  }
2571
2906
  delete state.previousData;
2572
2907
  }
2573
2908
 
2574
2909
  // src/core/doInitialAllocateContainers.ts
2575
- function doInitialAllocateContainers(ctx, state) {
2910
+ function doInitialAllocateContainers(ctx) {
2576
2911
  var _a3, _b, _c;
2912
+ const state = ctx.state;
2577
2913
  const {
2578
2914
  scrollLength,
2579
2915
  props: {
@@ -2594,8 +2930,10 @@ function doInitialAllocateContainers(ctx, state) {
2594
2930
  const num = Math.min(20, data.length);
2595
2931
  for (let i = 0; i < num; i++) {
2596
2932
  const item = data[i];
2597
- const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2598
- totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2933
+ if (item !== void 0) {
2934
+ const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
2935
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(item, i, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(item, i, itemType)) != null ? _c : estimatedItemSize;
2936
+ }
2599
2937
  }
2600
2938
  averageItemSize = totalSize / num;
2601
2939
  } else {
@@ -2611,10 +2949,10 @@ function doInitialAllocateContainers(ctx, state) {
2611
2949
  if (!IsNewArchitecture || state.lastLayout) {
2612
2950
  if (state.initialScroll) {
2613
2951
  requestAnimationFrame(() => {
2614
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2952
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2615
2953
  });
2616
2954
  } else {
2617
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2955
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2618
2956
  }
2619
2957
  }
2620
2958
  return true;
@@ -2622,7 +2960,8 @@ function doInitialAllocateContainers(ctx, state) {
2622
2960
  }
2623
2961
 
2624
2962
  // src/core/handleLayout.ts
2625
- function handleLayout(ctx, state, layout, setCanRender) {
2963
+ function handleLayout(ctx, layout, setCanRender) {
2964
+ const state = ctx.state;
2626
2965
  const { maintainScrollAtEnd } = state.props;
2627
2966
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2628
2967
  const previousLength = state.scrollLength;
@@ -2638,19 +2977,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2638
2977
  state.lastBatchingAction = Date.now();
2639
2978
  state.scrollForNextCalculateItemsInView = void 0;
2640
2979
  if (scrollLength > 0) {
2641
- doInitialAllocateContainers(ctx, state);
2980
+ doInitialAllocateContainers(ctx);
2642
2981
  }
2643
2982
  if (needsCalculate) {
2644
- calculateItemsInView(ctx, state, { doMVCP: true });
2983
+ calculateItemsInView(ctx, { doMVCP: true });
2645
2984
  }
2646
2985
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2647
2986
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2648
2987
  }
2649
2988
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2650
- doMaintainScrollAtEnd(ctx, state, false);
2989
+ doMaintainScrollAtEnd(ctx, false);
2651
2990
  }
2652
- updateAlignItemsPaddingTop(ctx, state);
2653
- checkAtBottom(ctx, state);
2991
+ updateAlignItemsPaddingTop(ctx);
2992
+ checkAtBottom(ctx);
2654
2993
  checkAtTop(state);
2655
2994
  if (state) {
2656
2995
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2666,8 +3005,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2666
3005
  }
2667
3006
 
2668
3007
  // src/core/onScroll.ts
2669
- function onScroll(ctx, state, event) {
3008
+ function onScroll(ctx, event) {
2670
3009
  var _a3, _b, _c;
3010
+ const state = ctx.state;
2671
3011
  const {
2672
3012
  scrollProcessingEnabled,
2673
3013
  props: { onScroll: onScrollProp }
@@ -2678,9 +3018,25 @@ function onScroll(ctx, state, event) {
2678
3018
  if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2679
3019
  return;
2680
3020
  }
2681
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3021
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3022
+ if (state.scrollingTo) {
3023
+ const maxOffset = clampScrollOffset(ctx, newScroll);
3024
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3025
+ newScroll = maxOffset;
3026
+ scrollTo(ctx, {
3027
+ forceScroll: true,
3028
+ isInitialScroll: true,
3029
+ noScrollingTo: true,
3030
+ offset: newScroll
3031
+ });
3032
+ return;
3033
+ }
3034
+ }
2682
3035
  state.scrollPending = newScroll;
2683
- updateScroll(ctx, state, newScroll);
3036
+ updateScroll(ctx, newScroll);
3037
+ if (state.scrollingTo) {
3038
+ checkFinishedScroll(ctx);
3039
+ }
2684
3040
  onScrollProp == null ? void 0 : onScrollProp(event);
2685
3041
  }
2686
3042
 
@@ -2689,51 +3045,58 @@ var ScrollAdjustHandler = class {
2689
3045
  constructor(ctx) {
2690
3046
  this.appliedAdjust = 0;
2691
3047
  this.pendingAdjust = 0;
2692
- this.mounted = false;
2693
- this.context = ctx;
2694
- if (Platform2.OS === "web") {
2695
- const commitPendingAdjust = () => {
2696
- const state = this.context.internalState;
2697
- const pending = this.pendingAdjust;
2698
- if (pending !== 0) {
2699
- this.pendingAdjust = 0;
2700
- this.appliedAdjust += pending;
2701
- state.scroll += pending;
2702
- state.scrollForNextCalculateItemsInView = void 0;
2703
- set$(this.context, "scrollAdjustPending", 0);
2704
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2705
- calculateItemsInView(this.context, this.context.internalState);
2706
- }
2707
- };
2708
- listen$(this.context, "scrollingTo", (value) => {
2709
- if (value === void 0) {
2710
- commitPendingAdjust();
2711
- }
2712
- });
2713
- }
3048
+ this.ctx = ctx;
2714
3049
  }
2715
3050
  requestAdjust(add) {
2716
- const scrollingTo = peek$(this.context, "scrollingTo");
2717
- if (Platform2.OS === "web" && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
3051
+ const scrollingTo = this.ctx.state.scrollingTo;
3052
+ if (PlatformAdjustBreaksScroll && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2718
3053
  this.pendingAdjust += add;
2719
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
3054
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2720
3055
  } else {
2721
3056
  this.appliedAdjust += add;
2722
- set$(this.context, "scrollAdjust", this.appliedAdjust);
3057
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3058
+ }
3059
+ if (this.ctx.state.scrollingTo) {
3060
+ checkFinishedScroll(this.ctx);
2723
3061
  }
2724
- }
2725
- setMounted() {
2726
- this.mounted = true;
2727
3062
  }
2728
3063
  getAdjust() {
2729
3064
  return this.appliedAdjust;
2730
3065
  }
3066
+ commitPendingAdjust(scrollTarget) {
3067
+ if (PlatformAdjustBreaksScroll) {
3068
+ const state = this.ctx.state;
3069
+ const pending = this.pendingAdjust;
3070
+ this.pendingAdjust = 0;
3071
+ if (pending !== 0) {
3072
+ let targetScroll;
3073
+ if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3074
+ const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3075
+ targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3076
+ targetScroll = clampScrollOffset(this.ctx, targetScroll);
3077
+ } else {
3078
+ targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3079
+ }
3080
+ const adjustment = targetScroll - state.scroll;
3081
+ if (Math.abs(adjustment) > 0.1 || Math.abs(pending) > 0.1) {
3082
+ this.appliedAdjust += adjustment;
3083
+ state.scroll = targetScroll;
3084
+ state.scrollForNextCalculateItemsInView = void 0;
3085
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3086
+ }
3087
+ set$(this.ctx, "scrollAdjustPending", 0);
3088
+ calculateItemsInView(this.ctx);
3089
+ }
3090
+ }
3091
+ }
2731
3092
  };
2732
3093
 
2733
3094
  // src/core/updateItemSize.ts
2734
- function updateItemSize(ctx, state, itemKey, sizeObj) {
3095
+ function updateItemSize(ctx, itemKey, sizeObj) {
2735
3096
  var _a3;
3097
+ const state = ctx.state;
2736
3098
  const {
3099
+ didContainersLayout,
2737
3100
  sizesKnown,
2738
3101
  props: {
2739
3102
  getFixedItemSize,
@@ -2756,31 +3119,24 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2756
3119
  return;
2757
3120
  }
2758
3121
  const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
2759
- const size2 = getFixedItemSize(index, itemData, type);
3122
+ const size2 = getFixedItemSize(itemData, index, type);
2760
3123
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
2761
3124
  return;
2762
3125
  }
2763
3126
  }
2764
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2765
- let needsRecalculate = !containersDidLayout;
3127
+ let needsRecalculate = !didContainersLayout;
2766
3128
  let shouldMaintainScrollAtEnd = false;
2767
3129
  let minIndexSizeChanged;
2768
3130
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2769
3131
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2770
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3132
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
2771
3133
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2772
3134
  if (diff !== 0) {
2773
3135
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2774
3136
  const { startBuffered, endBuffered } = state;
2775
3137
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2776
- if (!needsRecalculate) {
2777
- const numContainers = ctx.values.get("numContainers");
2778
- for (let i = 0; i < numContainers; i++) {
2779
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2780
- needsRecalculate = true;
2781
- break;
2782
- }
2783
- }
3138
+ if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
3139
+ needsRecalculate = true;
2784
3140
  }
2785
3141
  if (state.needsOtherAxisSize) {
2786
3142
  const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
@@ -2816,22 +3172,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2816
3172
  if (!cur || maxOtherAxisSize > cur) {
2817
3173
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
2818
3174
  }
2819
- if (containersDidLayout || checkAllSizesKnown(state)) {
3175
+ if (didContainersLayout || checkAllSizesKnown(state)) {
2820
3176
  if (needsRecalculate) {
2821
3177
  state.scrollForNextCalculateItemsInView = void 0;
2822
- calculateItemsInView(ctx, state, { doMVCP: true });
3178
+ calculateItemsInView(ctx, { doMVCP: true });
2823
3179
  }
2824
3180
  if (shouldMaintainScrollAtEnd) {
2825
3181
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2826
- doMaintainScrollAtEnd(ctx, state, false);
3182
+ doMaintainScrollAtEnd(ctx, false);
2827
3183
  }
2828
3184
  }
2829
3185
  }
2830
3186
  }
2831
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3187
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
2832
3188
  var _a3;
3189
+ const state = ctx.state;
2833
3190
  const {
2834
- sizes,
2835
3191
  indexByKey,
2836
3192
  sizesKnown,
2837
3193
  averageSizes,
@@ -2839,9 +3195,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2839
3195
  } = state;
2840
3196
  if (!data) return 0;
2841
3197
  const index = indexByKey.get(itemKey);
2842
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3198
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
2843
3199
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2844
3200
  const size = Platform2.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
3201
+ const prevSizeKnown = sizesKnown.get(itemKey);
2845
3202
  sizesKnown.set(itemKey, size);
2846
3203
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2847
3204
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -2849,15 +3206,25 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2849
3206
  if (!averages) {
2850
3207
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
2851
3208
  }
2852
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2853
- averages.num++;
3209
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3210
+ averages.avg += (size - prevSizeKnown) / averages.num;
3211
+ } else {
3212
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3213
+ averages.num++;
3214
+ }
2854
3215
  }
2855
3216
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2856
- setSize(ctx, state, itemKey, size);
3217
+ setSize(ctx, itemKey, size);
2857
3218
  return size - prevSize;
2858
3219
  }
2859
3220
  return 0;
2860
3221
  }
3222
+ function useWrapIfItem(fn) {
3223
+ return useMemo(
3224
+ () => fn ? (arg1, arg2, arg3) => arg1 !== void 0 && arg2 !== void 0 ? fn(arg1, arg2, arg3) : void 0 : void 0,
3225
+ [fn]
3226
+ );
3227
+ }
2861
3228
  var useCombinedRef = (...refs) => {
2862
3229
  const callback = useCallback((element) => {
2863
3230
  for (const ref of refs) {
@@ -2919,14 +3286,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
2919
3286
  }
2920
3287
 
2921
3288
  // src/utils/createImperativeHandle.ts
2922
- function createImperativeHandle(ctx, state) {
3289
+ function createImperativeHandle(ctx) {
3290
+ const state = ctx.state;
2923
3291
  const scrollIndexIntoView = (options) => {
2924
3292
  if (state) {
2925
3293
  const { index, ...rest } = options;
2926
3294
  const { startNoBuffer, endNoBuffer } = state;
2927
3295
  if (index < startNoBuffer || index > endNoBuffer) {
2928
3296
  const viewPosition = index < startNoBuffer ? 0 : 1;
2929
- scrollToIndex(ctx, state, {
3297
+ scrollToIndex(ctx, {
2930
3298
  ...rest,
2931
3299
  index,
2932
3300
  viewPosition
@@ -2941,7 +3309,7 @@ function createImperativeHandle(ctx, state) {
2941
3309
  getScrollableNode: () => refScroller.current.getScrollableNode(),
2942
3310
  getScrollResponder: () => refScroller.current.getScrollResponder(),
2943
3311
  getState: () => ({
2944
- activeStickyIndex: state.activeStickyIndex,
3312
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
2945
3313
  contentLength: state.totalSize,
2946
3314
  data: state.props.data,
2947
3315
  elementAtIndex: (index) => {
@@ -2952,6 +3320,8 @@ function createImperativeHandle(ctx, state) {
2952
3320
  endBuffered: state.endBuffered,
2953
3321
  isAtEnd: state.isAtEnd,
2954
3322
  isAtStart: state.isAtStart,
3323
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3324
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
2955
3325
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
2956
3326
  positions: state.positions,
2957
3327
  scroll: state.scroll,
@@ -2976,23 +3346,23 @@ function createImperativeHandle(ctx, state) {
2976
3346
  if (index !== -1) {
2977
3347
  const paddingBottom = stylePaddingBottom || 0;
2978
3348
  const footerSize = peek$(ctx, "footerSize") || 0;
2979
- scrollToIndex(ctx, state, {
3349
+ scrollToIndex(ctx, {
3350
+ ...options,
2980
3351
  index,
2981
3352
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
2982
- viewPosition: 1,
2983
- ...options
3353
+ viewPosition: 1
2984
3354
  });
2985
3355
  }
2986
3356
  },
2987
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3357
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
2988
3358
  scrollToItem: ({ item, ...props }) => {
2989
3359
  const data = state.props.data;
2990
3360
  const index = data.indexOf(item);
2991
3361
  if (index !== -1) {
2992
- scrollToIndex(ctx, state, { index, ...props });
3362
+ scrollToIndex(ctx, { index, ...props });
2993
3363
  }
2994
3364
  },
2995
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3365
+ scrollToOffset: (params) => scrollTo(ctx, params),
2996
3366
  setScrollProcessingEnabled: (enabled) => {
2997
3367
  state.scrollProcessingEnabled = enabled;
2998
3368
  },
@@ -3002,8 +3372,57 @@ function createImperativeHandle(ctx, state) {
3002
3372
  }
3003
3373
  };
3004
3374
  }
3005
- function getRenderedItem(ctx, state, key) {
3375
+
3376
+ // src/utils/getAlwaysRenderIndices.ts
3377
+ var sortAsc = (a, b) => a - b;
3378
+ var toCount = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
3379
+ var addIndex = (result, dataLength, index) => {
3380
+ if (index >= 0 && index < dataLength) {
3381
+ result.add(index);
3382
+ }
3383
+ };
3384
+ function getAlwaysRenderIndices(config, data, keyExtractor) {
3385
+ var _a3, _b;
3386
+ if (!config || data.length === 0) {
3387
+ return [];
3388
+ }
3389
+ const result = /* @__PURE__ */ new Set();
3390
+ const dataLength = data.length;
3391
+ const topCount = toCount(config.top);
3392
+ if (topCount > 0) {
3393
+ for (let i = 0; i < Math.min(topCount, dataLength); i++) {
3394
+ addIndex(result, dataLength, i);
3395
+ }
3396
+ }
3397
+ const bottomCount = toCount(config.bottom);
3398
+ if (bottomCount > 0) {
3399
+ for (let i = Math.max(0, dataLength - bottomCount); i < dataLength; i++) {
3400
+ addIndex(result, dataLength, i);
3401
+ }
3402
+ }
3403
+ if ((_a3 = config.indices) == null ? void 0 : _a3.length) {
3404
+ for (const index of config.indices) {
3405
+ if (!Number.isFinite(index)) continue;
3406
+ addIndex(result, dataLength, Math.floor(index));
3407
+ }
3408
+ }
3409
+ if ((_b = config.keys) == null ? void 0 : _b.length) {
3410
+ const keys = new Set(config.keys);
3411
+ for (let i = 0; i < dataLength && keys.size > 0; i++) {
3412
+ const key = keyExtractor(data[i], i);
3413
+ if (keys.has(key)) {
3414
+ addIndex(result, dataLength, i);
3415
+ keys.delete(key);
3416
+ }
3417
+ }
3418
+ }
3419
+ const indices = Array.from(result);
3420
+ indices.sort(sortAsc);
3421
+ return indices;
3422
+ }
3423
+ function getRenderedItem(ctx, key) {
3006
3424
  var _a3;
3425
+ const state = ctx.state;
3007
3426
  if (!state) {
3008
3427
  return null;
3009
3428
  }
@@ -3030,6 +3449,25 @@ function getRenderedItem(ctx, state, key) {
3030
3449
  }
3031
3450
  return { index, item: data[index], renderedItem };
3032
3451
  }
3452
+
3453
+ // src/utils/normalizeMaintainVisibleContentPosition.ts
3454
+ function normalizeMaintainVisibleContentPosition(value) {
3455
+ var _a3, _b;
3456
+ if (value === true) {
3457
+ return { data: true, size: true };
3458
+ }
3459
+ if (value && typeof value === "object") {
3460
+ return {
3461
+ data: (_a3 = value.data) != null ? _a3 : false,
3462
+ size: (_b = value.size) != null ? _b : true,
3463
+ shouldRestorePosition: value.shouldRestorePosition
3464
+ };
3465
+ }
3466
+ if (value === false) {
3467
+ return { data: false, size: false };
3468
+ }
3469
+ return { data: false, size: true };
3470
+ }
3033
3471
  function useThrottleDebounce(mode) {
3034
3472
  const timeoutRef = useRef(null);
3035
3473
  const lastCallTimeRef = useRef(0);
@@ -3080,6 +3518,7 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3080
3518
  var DEFAULT_DRAW_DISTANCE = 250;
3081
3519
  var DEFAULT_ITEM_SIZE = 100;
3082
3520
  var LegendList = typedMemo(
3521
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3083
3522
  typedForwardRef(function LegendList2(props, forwardedRef) {
3084
3523
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3085
3524
  const isChildrenMode = children !== void 0 && dataProp === void 0;
@@ -3097,15 +3536,16 @@ var LegendList = typedMemo(
3097
3536
  })
3098
3537
  );
3099
3538
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3100
- var _a3, _b;
3539
+ var _a3, _b, _c, _d;
3101
3540
  const {
3102
3541
  alignItemsAtEnd = false,
3542
+ alwaysRender,
3103
3543
  columnWrapperStyle,
3104
3544
  contentContainerStyle: contentContainerStyleProp,
3545
+ contentInset,
3105
3546
  data: dataProp = [],
3106
3547
  dataVersion,
3107
3548
  drawDistance = 250,
3108
- enableAverages = true,
3109
3549
  estimatedItemSize: estimatedItemSizeProp,
3110
3550
  estimatedListSize,
3111
3551
  extraData,
@@ -3123,11 +3563,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3123
3563
  ListHeaderComponent,
3124
3564
  maintainScrollAtEnd = false,
3125
3565
  maintainScrollAtEndThreshold = 0.1,
3126
- maintainVisibleContentPosition = false,
3566
+ maintainVisibleContentPosition: maintainVisibleContentPositionProp,
3127
3567
  numColumns: numColumnsProp = 1,
3128
3568
  onEndReached,
3129
3569
  onEndReachedThreshold = 0.5,
3130
3570
  onItemSizeChanged,
3571
+ onMetricsChange,
3131
3572
  onLayout: onLayoutProp,
3132
3573
  onLoad,
3133
3574
  onMomentumScrollEnd,
@@ -3147,20 +3588,26 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3147
3588
  snapToIndices,
3148
3589
  stickyHeaderIndices: stickyHeaderIndicesProp,
3149
3590
  stickyIndices: stickyIndicesDeprecated,
3591
+ // TODOV3: Remove from v3 release
3150
3592
  style: styleProp,
3151
3593
  suggestEstimatedItemSize,
3152
3594
  viewabilityConfig,
3153
3595
  viewabilityConfigCallbackPairs,
3154
3596
  waitForInitialLayout = true,
3597
+ stickyHeaderConfig,
3155
3598
  ...rest
3156
3599
  } = props;
3600
+ const animatedPropsInternal = props.animatedPropsInternal;
3157
3601
  const { childrenMode } = rest;
3158
3602
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3159
3603
  const style = { ...StyleSheet.flatten(styleProp) };
3160
3604
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
3161
3605
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
3606
+ const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
3607
+ maintainVisibleContentPositionProp
3608
+ );
3162
3609
  const [renderNum, setRenderNum] = useState(0);
3163
- const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState } : initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3610
+ const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState, viewPosition: 1 } : initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3164
3611
  const [canRender, setCanRender] = React2.useState(!IsNewArchitecture);
3165
3612
  const ctx = useStateContext();
3166
3613
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
@@ -3170,6 +3617,18 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3170
3617
  const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
3171
3618
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
3172
3619
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
3620
+ const alwaysRenderIndices = useMemo(() => {
3621
+ const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor);
3622
+ return { arr: indices, set: new Set(indices) };
3623
+ }, [
3624
+ alwaysRender == null ? void 0 : alwaysRender.top,
3625
+ alwaysRender == null ? void 0 : alwaysRender.bottom,
3626
+ (_a3 = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _a3.join(","),
3627
+ (_b = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _b.join(","),
3628
+ dataProp,
3629
+ dataVersion,
3630
+ keyExtractor
3631
+ ]);
3173
3632
  if (IS_DEV && stickyIndicesDeprecated && !stickyHeaderIndicesProp) {
3174
3633
  warnDevOnce(
3175
3634
  "stickyIndices",
@@ -3178,13 +3637,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3178
3637
  }
3179
3638
  const refState = useRef();
3180
3639
  if (!refState.current) {
3181
- if (!ctx.internalState) {
3640
+ if (!ctx.state) {
3182
3641
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : getWindowSize())[horizontal ? "width" : "height"];
3183
- ctx.internalState = {
3184
- activeStickyIndex: void 0,
3642
+ ctx.state = {
3643
+ activeStickyIndex: -1,
3185
3644
  averageSizes: {},
3186
3645
  columns: /* @__PURE__ */ new Map(),
3187
- containerItemKeys: /* @__PURE__ */ new Set(),
3646
+ containerItemKeys: /* @__PURE__ */ new Map(),
3188
3647
  containerItemTypes: /* @__PURE__ */ new Map(),
3189
3648
  dataChangeNeedsScrollUpdate: false,
3190
3649
  didColumnsChange: false,
@@ -3201,17 +3660,18 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3201
3660
  attempts: 0,
3202
3661
  index: initialScrollProp.index,
3203
3662
  settledTicks: 0,
3204
- viewOffset: (_a3 = initialScrollProp.viewOffset) != null ? _a3 : 0,
3663
+ viewOffset: (_c = initialScrollProp.viewOffset) != null ? _c : 0,
3205
3664
  viewPosition: initialScrollProp.viewPosition
3206
3665
  } : void 0,
3207
3666
  initialScroll: initialScrollProp,
3208
3667
  isAtEnd: false,
3209
3668
  isAtStart: false,
3210
- isEndReached: false,
3669
+ isEndReached: null,
3211
3670
  isFirst: true,
3212
- isStartReached: false,
3671
+ isStartReached: null,
3213
3672
  lastBatchingAction: Date.now(),
3214
3673
  lastLayout: void 0,
3674
+ lastScrollDelta: 0,
3215
3675
  loadStartTime: Date.now(),
3216
3676
  minIndexSizeChanged: 0,
3217
3677
  nativeMarginTop: 0,
@@ -3241,12 +3701,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3241
3701
  totalSize: 0,
3242
3702
  viewabilityConfigCallbackPairs: void 0
3243
3703
  };
3244
- const internalState = ctx.internalState;
3245
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3246
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3704
+ const internalState = ctx.state;
3705
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3706
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
3247
3707
  set$(ctx, "extraData", extraData);
3248
3708
  }
3249
- refState.current = ctx.internalState;
3709
+ refState.current = ctx.state;
3250
3710
  }
3251
3711
  const state = refState.current;
3252
3712
  const isFirstLocal = state.isFirst;
@@ -3260,20 +3720,24 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3260
3720
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3261
3721
  state.props = {
3262
3722
  alignItemsAtEnd,
3723
+ alwaysRender,
3724
+ alwaysRenderIndicesArr: alwaysRenderIndices.arr,
3725
+ alwaysRenderIndicesSet: alwaysRenderIndices.set,
3726
+ animatedProps: animatedPropsInternal,
3727
+ contentInset,
3263
3728
  data: dataProp,
3264
3729
  dataVersion,
3265
- enableAverages,
3266
3730
  estimatedItemSize,
3267
- getEstimatedItemSize,
3268
- getFixedItemSize,
3269
- getItemType,
3731
+ getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3732
+ getFixedItemSize: useWrapIfItem(getFixedItemSize),
3733
+ getItemType: useWrapIfItem(getItemType),
3270
3734
  horizontal: !!horizontal,
3271
3735
  initialContainerPoolRatio,
3272
3736
  itemsAreEqual,
3273
- keyExtractor,
3737
+ keyExtractor: useWrapIfItem(keyExtractor),
3274
3738
  maintainScrollAtEnd,
3275
3739
  maintainScrollAtEndThreshold,
3276
- maintainVisibleContentPosition,
3740
+ maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
3277
3741
  numColumns: numColumnsProp,
3278
3742
  onEndReached,
3279
3743
  onEndReachedThreshold,
@@ -3305,57 +3769,57 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3305
3769
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3306
3770
  set$(ctx, "numColumns", numColumnsProp);
3307
3771
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3308
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3772
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3309
3773
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3310
3774
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3311
- if (paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3775
+ if (maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3312
3776
  if (state.scroll < 0) {
3313
3777
  paddingDiff += state.scroll;
3314
3778
  }
3315
- requestAdjust(ctx, state, paddingDiff);
3779
+ requestAdjust(ctx, paddingDiff);
3316
3780
  }
3317
3781
  };
3318
3782
  if (isFirstLocal) {
3319
3783
  initializeStateVars();
3320
3784
  updateItemPositions(
3321
3785
  ctx,
3322
- state,
3323
3786
  /*dataChanged*/
3324
3787
  true
3325
3788
  );
3326
3789
  }
3327
3790
  const initialContentOffset = useMemo(() => {
3328
- var _a4, _b2;
3329
- const { initialScroll } = refState.current;
3330
- if (!initialScroll) {
3791
+ var _a4;
3792
+ let value;
3793
+ const { initialScroll, initialAnchor } = refState.current;
3794
+ if (initialScroll) {
3795
+ if (!IsNewArchitecture && initialScroll.index !== void 0 && (!initialAnchor || (initialAnchor == null ? void 0 : initialAnchor.index) !== initialScroll.index)) {
3796
+ refState.current.initialAnchor = {
3797
+ attempts: 0,
3798
+ index: initialScroll.index,
3799
+ settledTicks: 0,
3800
+ viewOffset: (_a4 = initialScroll.viewOffset) != null ? _a4 : 0,
3801
+ viewPosition: initialScroll.viewPosition
3802
+ };
3803
+ }
3804
+ if (initialScroll.contentOffset !== void 0) {
3805
+ value = initialScroll.contentOffset;
3806
+ } else {
3807
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3808
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3809
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3810
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3811
+ refState.current.initialScroll = updatedInitialScroll;
3812
+ state.initialScroll = updatedInitialScroll;
3813
+ value = clampedOffset;
3814
+ }
3815
+ } else {
3331
3816
  refState.current.initialAnchor = void 0;
3332
- return 0;
3333
- }
3334
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3335
- refState.current.initialAnchor = {
3336
- attempts: 0,
3337
- index: initialScroll.index,
3338
- settledTicks: 0,
3339
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3340
- viewPosition: initialScroll.viewPosition
3341
- };
3817
+ value = 0;
3818
+ }
3819
+ if (!value) {
3820
+ setInitialRenderState(ctx, { didInitialScroll: true });
3342
3821
  }
3343
- if (initialScroll.contentOffset !== void 0) {
3344
- return initialScroll.contentOffset;
3345
- }
3346
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3347
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3348
- let clampedOffset = resolvedOffset;
3349
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3350
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3351
- clampedOffset = Math.min(clampedOffset, maxOffset);
3352
- }
3353
- clampedOffset = Math.max(0, clampedOffset);
3354
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3355
- refState.current.initialScroll = updatedInitialScroll;
3356
- state.initialScroll = updatedInitialScroll;
3357
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3358
- return clampedOffset;
3822
+ return value;
3359
3823
  }, [renderNum]);
3360
3824
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3361
3825
  refState.current.lastBatchingAction = Date.now();
@@ -3385,12 +3849,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3385
3849
  }
3386
3850
  }, []);
3387
3851
  const doInitialScroll = useCallback(() => {
3388
- var _a4;
3389
- const initialScroll = state.initialScroll;
3390
- if (initialScroll) {
3391
- scrollTo(ctx, state, {
3852
+ const { initialScroll, didFinishInitialScroll, queuedInitialLayout, scrollingTo } = state;
3853
+ if (initialScroll && !queuedInitialLayout && !didFinishInitialScroll && !scrollingTo) {
3854
+ scrollTo(ctx, {
3392
3855
  animated: false,
3393
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3856
+ index: initialScroll == null ? void 0 : initialScroll.index,
3394
3857
  isInitialScroll: true,
3395
3858
  offset: initialContentOffset,
3396
3859
  precomputedWithViewOffset: true
@@ -3399,7 +3862,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3399
3862
  }, [initialContentOffset]);
3400
3863
  const onLayoutChange = useCallback((layout) => {
3401
3864
  doInitialScroll();
3402
- handleLayout(ctx, state, layout, setCanRender);
3865
+ handleLayout(ctx, layout, setCanRender);
3403
3866
  }, []);
3404
3867
  const { onLayout } = useOnLayoutSync({
3405
3868
  onLayoutChange,
@@ -3409,7 +3872,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3409
3872
  });
3410
3873
  useLayoutEffect(() => {
3411
3874
  if (snapToIndices) {
3412
- updateSnapToOffsets(ctx, state);
3875
+ updateSnapToOffsets(ctx);
3413
3876
  }
3414
3877
  }, [snapToIndices]);
3415
3878
  useLayoutEffect(() => {
@@ -3419,9 +3882,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3419
3882
  isFirst,
3420
3883
  props: { data }
3421
3884
  } = state;
3422
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3885
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3423
3886
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3424
- checkResetContainers(ctx, state, data);
3887
+ checkResetContainers(ctx, data);
3425
3888
  }
3426
3889
  state.didColumnsChange = false;
3427
3890
  state.didDataChange = false;
@@ -3437,6 +3900,34 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3437
3900
  stylePaddingBottomState,
3438
3901
  stylePaddingTopState
3439
3902
  ]);
3903
+ useEffect(() => {
3904
+ if (!onMetricsChange) {
3905
+ return;
3906
+ }
3907
+ let lastMetrics;
3908
+ const emitMetrics = () => {
3909
+ const metrics = {
3910
+ alignItemsAtEndPadding: peek$(ctx, "alignItemsPaddingTop") || 0,
3911
+ footerSize: peek$(ctx, "footerSize") || 0,
3912
+ headerSize: peek$(ctx, "headerSize") || 0
3913
+ };
3914
+ if (!lastMetrics || metrics.alignItemsAtEndPadding !== lastMetrics.alignItemsAtEndPadding || metrics.headerSize !== lastMetrics.headerSize || metrics.footerSize !== lastMetrics.footerSize) {
3915
+ lastMetrics = metrics;
3916
+ onMetricsChange(metrics);
3917
+ }
3918
+ };
3919
+ emitMetrics();
3920
+ const unsubscribe = [
3921
+ listen$(ctx, "alignItemsPaddingTop", emitMetrics),
3922
+ listen$(ctx, "headerSize", emitMetrics),
3923
+ listen$(ctx, "footerSize", emitMetrics)
3924
+ ];
3925
+ return () => {
3926
+ for (const unsub of unsubscribe) {
3927
+ unsub();
3928
+ }
3929
+ };
3930
+ }, [ctx, onMetricsChange]);
3440
3931
  useEffect(() => {
3441
3932
  const viewability = setupViewability({
3442
3933
  onViewableItemsChanged,
@@ -3448,18 +3939,24 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3448
3939
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3449
3940
  if (!IsNewArchitecture) {
3450
3941
  useInit(() => {
3451
- doInitialAllocateContainers(ctx, state);
3942
+ doInitialAllocateContainers(ctx);
3452
3943
  });
3453
3944
  }
3454
- useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3945
+ useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3455
3946
  if (Platform2.OS === "web") {
3456
3947
  useEffect(doInitialScroll, []);
3457
3948
  }
3458
3949
  const fns = useMemo(
3459
3950
  () => ({
3460
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3461
- onScroll: (event) => onScroll(ctx, state, event),
3462
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3951
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
3952
+ onMomentumScrollEnd: (event) => {
3953
+ checkFinishedScrollFallback(ctx);
3954
+ if (onMomentumScrollEnd) {
3955
+ onMomentumScrollEnd(event);
3956
+ }
3957
+ },
3958
+ onScroll: (event) => onScroll(ctx, event),
3959
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3463
3960
  }),
3464
3961
  []
3465
3962
  );
@@ -3471,28 +3968,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3471
3968
  alignItemsAtEnd,
3472
3969
  canRender,
3473
3970
  contentContainerStyle,
3971
+ contentInset,
3474
3972
  getRenderedItem: fns.getRenderedItem,
3475
3973
  horizontal,
3476
3974
  initialContentOffset,
3477
3975
  ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
3478
3976
  ListHeaderComponent,
3479
- maintainVisibleContentPosition,
3480
3977
  onLayout,
3481
3978
  onLayoutHeader,
3482
- onMomentumScrollEnd: (event) => {
3483
- if (IsNewArchitecture) {
3484
- requestAnimationFrame(() => {
3485
- finishScrollTo(ctx, refState.current);
3486
- });
3487
- } else {
3488
- setTimeout(() => {
3489
- finishScrollTo(ctx, refState.current);
3490
- }, 1e3);
3491
- }
3492
- if (onMomentumScrollEnd) {
3493
- onMomentumScrollEnd(event);
3494
- }
3495
- },
3979
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3496
3980
  onScroll: onScrollHandler,
3497
3981
  recycleItems,
3498
3982
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControl, {
@@ -3506,9 +3990,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3506
3990
  }
3507
3991
  ),
3508
3992
  refScrollView: combinedRef,
3509
- scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3510
- scrollEventThrottle: Platform2.OS === "web" ? 16 : void 0,
3993
+ scrollAdjustHandler: (_d = refState.current) == null ? void 0 : _d.scrollAdjustHandler,
3994
+ scrollEventThrottle: 0,
3511
3995
  snapToIndices,
3996
+ stickyHeaderConfig,
3512
3997
  stickyHeaderIndices,
3513
3998
  style,
3514
3999
  updateItemSize: fns.updateItemSize,
@@ -3517,4 +4002,4 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3517
4002
  ), IS_DEV && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React2.createElement(DebugView, { state: refState.current }));
3518
4003
  });
3519
4004
 
3520
- export { LegendList, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
4005
+ export { LegendList, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };