@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.js CHANGED
@@ -28,30 +28,64 @@ var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
28
28
  reactNative.Animated.View;
29
29
  var View = reactNative.View;
30
30
  var Text = reactNative.Text;
31
+
32
+ // src/state/getContentInsetEnd.ts
33
+ function getContentInsetEnd(state) {
34
+ var _a3;
35
+ const { props } = state;
36
+ const horizontal = props.horizontal;
37
+ let contentInset = props.contentInset;
38
+ if (!contentInset) {
39
+ const animatedInset = (_a3 = props.animatedProps) == null ? void 0 : _a3.contentInset;
40
+ if (animatedInset) {
41
+ if ("get" in animatedInset) {
42
+ contentInset = animatedInset.get();
43
+ } else {
44
+ contentInset = animatedInset;
45
+ }
46
+ }
47
+ }
48
+ return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
49
+ }
50
+
51
+ // src/state/getContentSize.ts
52
+ function getContentSize(ctx) {
53
+ var _a3;
54
+ const { values, state } = ctx;
55
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
56
+ const stylePaddingBottom = state.props.stylePaddingBottom || 0;
57
+ const headerSize = values.get("headerSize") || 0;
58
+ const footerSize = values.get("footerSize") || 0;
59
+ const contentInsetBottom = getContentInsetEnd(state);
60
+ const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
61
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
62
+ }
31
63
  var createAnimatedValue = (value) => new reactNative.Animated.Value(value);
32
64
 
33
65
  // src/state/state.tsx
34
66
  var ContextState = React2__namespace.createContext(null);
67
+ var contextNum = 0;
35
68
  function StateProvider({ children }) {
36
69
  const [value] = React2__namespace.useState(() => ({
37
70
  animatedScrollY: createAnimatedValue(0),
38
71
  columnWrapperStyle: void 0,
39
- internalState: void 0,
72
+ contextNum: contextNum++,
40
73
  listeners: /* @__PURE__ */ new Map(),
41
74
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
42
75
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
43
76
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
44
77
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
45
78
  mapViewabilityValues: /* @__PURE__ */ new Map(),
79
+ positionListeners: /* @__PURE__ */ new Map(),
80
+ state: void 0,
46
81
  values: /* @__PURE__ */ new Map([
47
82
  ["alignItemsPaddingTop", 0],
48
83
  ["stylePaddingTop", 0],
49
84
  ["headerSize", 0],
50
85
  ["numContainers", 0],
51
- ["activeStickyIndex", void 0],
86
+ ["activeStickyIndex", -1],
52
87
  ["totalSize", 0],
53
- ["scrollAdjustPending", 0],
54
- ["scrollingTo", void 0]
88
+ ["scrollAdjustPending", 0]
55
89
  ]),
56
90
  viewRefs: /* @__PURE__ */ new Map()
57
91
  }));
@@ -119,15 +153,24 @@ function set$(ctx, signalName, value) {
119
153
  }
120
154
  }
121
155
  }
122
- function getContentSize(ctx) {
123
- var _a3, _b;
124
- const { values, internalState } = ctx;
125
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
126
- const stylePaddingBottom = (internalState == null ? void 0 : internalState.props.stylePaddingBottom) || 0;
127
- const headerSize = values.get("headerSize") || 0;
128
- const footerSize = values.get("footerSize") || 0;
129
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
130
- return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom;
156
+ function listenPosition$(ctx, key, cb) {
157
+ const { positionListeners } = ctx;
158
+ let setListeners = positionListeners.get(key);
159
+ if (!setListeners) {
160
+ setListeners = /* @__PURE__ */ new Set();
161
+ positionListeners.set(key, setListeners);
162
+ }
163
+ setListeners.add(cb);
164
+ return () => setListeners.delete(cb);
165
+ }
166
+ function notifyPosition$(ctx, key, value) {
167
+ const { positionListeners } = ctx;
168
+ const setListeners = positionListeners.get(key);
169
+ if (setListeners) {
170
+ for (const listener of setListeners) {
171
+ listener(value);
172
+ }
173
+ }
131
174
  }
132
175
  function useArr$(signalNames) {
133
176
  const ctx = React2__namespace.useContext(ContextState);
@@ -206,9 +249,11 @@ var ENABLE_DEVMODE = IS_DEV && false;
206
249
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
207
250
 
208
251
  // src/constants-platform.native.ts
209
- var IsNewArchitecture = global.nativeFabricUIManager != null;
252
+ var f = global.nativeFabricUIManager;
253
+ var IsNewArchitecture = f !== void 0 && f != null;
210
254
  var useAnimatedValue = (initialValue) => {
211
- return React2.useRef(new reactNative.Animated.Value(initialValue)).current;
255
+ const [animAnimatedValue] = React2.useState(() => new reactNative.Animated.Value(initialValue));
256
+ return animAnimatedValue;
212
257
  };
213
258
 
214
259
  // src/utils/helpers.ts
@@ -242,6 +287,11 @@ function extractPadding(style, contentContainerStyle, type) {
242
287
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
243
288
  }
244
289
  function findContainerId(ctx, key) {
290
+ var _a3, _b;
291
+ const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
292
+ if (directMatch !== void 0) {
293
+ return directMatch;
294
+ }
245
295
  const numContainers = peek$(ctx, "numContainers");
246
296
  for (let i = 0; i < numContainers; i++) {
247
297
  const itemKey = peek$(ctx, `containerItemKey${i}`);
@@ -295,9 +345,18 @@ function useValue$(key, params) {
295
345
  }
296
346
  var typedForwardRef = React2.forwardRef;
297
347
  var typedMemo = React2.memo;
348
+ var getComponent = (Component) => {
349
+ if (React2__namespace.isValidElement(Component)) {
350
+ return Component;
351
+ }
352
+ if (Component) {
353
+ return /* @__PURE__ */ React2__namespace.createElement(Component, null);
354
+ }
355
+ return null;
356
+ };
298
357
 
299
358
  // src/components/PositionView.native.tsx
300
- var PositionViewState = typedMemo(function PositionView({
359
+ var PositionViewState = typedMemo(function PositionViewState2({
301
360
  id,
302
361
  horizontal,
303
362
  style,
@@ -317,7 +376,7 @@ var PositionViewState = typedMemo(function PositionView({
317
376
  }
318
377
  );
319
378
  });
320
- var PositionViewAnimated = typedMemo(function PositionView2({
379
+ var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
321
380
  id,
322
381
  horizontal,
323
382
  style,
@@ -343,77 +402,117 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
343
402
  animatedScrollY,
344
403
  stickyOffset,
345
404
  index,
405
+ stickyHeaderConfig,
406
+ children,
346
407
  ...rest
347
408
  }) {
348
409
  const [position = POSITION_OUT_OF_VIEW, headerSize] = useArr$([`containerPosition${id}`, "headerSize"]);
349
410
  const transform = React2__namespace.useMemo(() => {
411
+ var _a3;
350
412
  if (animatedScrollY && stickyOffset !== void 0) {
413
+ const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
351
414
  const stickyPosition = animatedScrollY.interpolate({
352
415
  extrapolateLeft: "clamp",
353
416
  extrapolateRight: "extend",
354
- inputRange: [position + headerSize, position + 5e3 + headerSize],
417
+ inputRange: [
418
+ position + headerSize - stickyConfigOffset - stickyOffset,
419
+ position + 5e3 + headerSize - stickyConfigOffset - stickyOffset
420
+ ],
355
421
  outputRange: [position, position + 5e3]
356
422
  });
357
423
  return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
358
424
  }
359
- }, [animatedScrollY, headerSize, horizontal, stickyOffset, position]);
425
+ }, [animatedScrollY, headerSize, horizontal, stickyOffset, position, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
360
426
  const viewStyle = React2__namespace.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
361
- return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { ref: refView, style: viewStyle, ...rest });
427
+ const renderStickyHeaderBackdrop = React2__namespace.useMemo(() => {
428
+ if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
429
+ return null;
430
+ }
431
+ return /* @__PURE__ */ React2__namespace.createElement(
432
+ reactNative.View,
433
+ {
434
+ style: {
435
+ inset: 0,
436
+ pointerEvents: "none",
437
+ position: "absolute"
438
+ }
439
+ },
440
+ getComponent(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)
441
+ );
442
+ }, [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]);
443
+ return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { ref: refView, style: viewStyle, ...rest }, renderStickyHeaderBackdrop, children);
362
444
  });
363
- var PositionView3 = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
364
- var symbolFirst = Symbol();
445
+ var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
365
446
  function useInit(cb) {
366
- const refValue = React2.useRef(symbolFirst);
367
- if (refValue.current === symbolFirst) {
368
- refValue.current = cb();
369
- }
370
- return refValue.current;
447
+ React2.useState(() => cb());
371
448
  }
372
449
 
373
450
  // src/state/ContextContainer.ts
374
451
  var ContextContainer = React2.createContext(null);
452
+ function useContextContainer() {
453
+ return React2.useContext(ContextContainer);
454
+ }
375
455
  function useViewability(callback, configId) {
376
456
  const ctx = useStateContext();
377
- const { containerId } = React2.useContext(ContextContainer);
378
- const key = containerId + (configId != null ? configId : "");
457
+ const containerContext = useContextContainer();
379
458
  useInit(() => {
459
+ if (!containerContext) {
460
+ return;
461
+ }
462
+ const { containerId } = containerContext;
463
+ const key = containerId + (configId != null ? configId : "");
380
464
  const value = ctx.mapViewabilityValues.get(key);
381
465
  if (value) {
382
466
  callback(value);
383
467
  }
384
468
  });
385
- ctx.mapViewabilityCallbacks.set(key, callback);
386
- React2.useEffect(
387
- () => () => {
469
+ React2.useEffect(() => {
470
+ if (!containerContext) {
471
+ return;
472
+ }
473
+ const { containerId } = containerContext;
474
+ const key = containerId + (configId != null ? configId : "");
475
+ ctx.mapViewabilityCallbacks.set(key, callback);
476
+ return () => {
388
477
  ctx.mapViewabilityCallbacks.delete(key);
389
- },
390
- []
391
- );
478
+ };
479
+ }, [ctx, callback, configId, containerContext]);
392
480
  }
393
481
  function useViewabilityAmount(callback) {
394
482
  const ctx = useStateContext();
395
- const { containerId } = React2.useContext(ContextContainer);
483
+ const containerContext = useContextContainer();
396
484
  useInit(() => {
485
+ if (!containerContext) {
486
+ return;
487
+ }
488
+ const { containerId } = containerContext;
397
489
  const value = ctx.mapViewabilityAmountValues.get(containerId);
398
490
  if (value) {
399
491
  callback(value);
400
492
  }
401
493
  });
402
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
403
- React2.useEffect(
404
- () => () => {
494
+ React2.useEffect(() => {
495
+ if (!containerContext) {
496
+ return;
497
+ }
498
+ const { containerId } = containerContext;
499
+ ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
500
+ return () => {
405
501
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
406
- },
407
- []
408
- );
502
+ };
503
+ }, [ctx, callback, containerContext]);
409
504
  }
410
505
  function useRecyclingEffect(effect) {
411
- const { index, value } = React2.useContext(ContextContainer);
506
+ const containerContext = useContextContainer();
412
507
  const prevValues = React2.useRef({
413
508
  prevIndex: void 0,
414
509
  prevItem: void 0
415
510
  });
416
511
  React2.useEffect(() => {
512
+ if (!containerContext) {
513
+ return;
514
+ }
515
+ const { index, value } = containerContext;
417
516
  let ret;
418
517
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
419
518
  ret = effect({
@@ -428,38 +527,58 @@ function useRecyclingEffect(effect) {
428
527
  prevItem: value
429
528
  };
430
529
  return ret;
431
- }, [index, value, effect]);
530
+ }, [effect, containerContext]);
432
531
  }
433
532
  function useRecyclingState(valueOrFun) {
434
- const { index, value, itemKey, triggerLayout } = React2.useContext(ContextContainer);
435
- const refState = React2.useRef({
436
- itemKey: null,
437
- value: null
533
+ var _a3, _b;
534
+ const containerContext = useContextContainer();
535
+ const computeValue = (ctx) => {
536
+ if (isFunction(valueOrFun)) {
537
+ const initializer = valueOrFun;
538
+ return ctx ? initializer({
539
+ index: ctx.index,
540
+ item: ctx.value,
541
+ prevIndex: void 0,
542
+ prevItem: void 0
543
+ }) : initializer();
544
+ }
545
+ return valueOrFun;
546
+ };
547
+ const [stateValue, setStateValue] = React2.useState(() => {
548
+ return computeValue(containerContext);
438
549
  });
439
- const [_, setRenderNum] = React2.useState(0);
440
- const state = refState.current;
441
- if (state.itemKey !== itemKey) {
442
- state.itemKey = itemKey;
443
- state.value = isFunction(valueOrFun) ? valueOrFun({
444
- index,
445
- item: value,
446
- prevIndex: void 0,
447
- prevItem: void 0
448
- }) : valueOrFun;
550
+ const prevItemKeyRef = React2.useRef((_a3 = containerContext == null ? void 0 : containerContext.itemKey) != null ? _a3 : null);
551
+ const currentItemKey = (_b = containerContext == null ? void 0 : containerContext.itemKey) != null ? _b : null;
552
+ if (currentItemKey !== null && prevItemKeyRef.current !== currentItemKey) {
553
+ prevItemKeyRef.current = currentItemKey;
554
+ setStateValue(computeValue(containerContext));
449
555
  }
556
+ const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
450
557
  const setState = React2.useCallback(
451
558
  (newState) => {
452
- state.value = isFunction(newState) ? newState(state.value) : newState;
453
- setRenderNum((v) => v + 1);
559
+ if (!triggerLayout) {
560
+ return;
561
+ }
562
+ setStateValue((prevValue) => {
563
+ return isFunction(newState) ? newState(prevValue) : newState;
564
+ });
454
565
  triggerLayout();
455
566
  },
456
- [triggerLayout, state]
567
+ [triggerLayout]
457
568
  );
458
- return [state.value, setState];
569
+ return [stateValue, setState];
459
570
  }
460
571
  function useIsLastItem() {
461
- const { itemKey } = React2.useContext(ContextContainer);
462
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
572
+ const containerContext = useContextContainer();
573
+ const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
574
+ if (containerContext) {
575
+ const { itemKey } = containerContext;
576
+ if (!isNullOrUndefined(itemKey)) {
577
+ return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
578
+ }
579
+ }
580
+ return false;
581
+ });
463
582
  return isLast;
464
583
  }
465
584
  function useListScrollSize() {
@@ -469,8 +588,9 @@ function useListScrollSize() {
469
588
  var noop = () => {
470
589
  };
471
590
  function useSyncLayout() {
472
- if (IsNewArchitecture) {
473
- const { triggerLayout: syncLayout } = React2.useContext(ContextContainer);
591
+ const containerContext = useContextContainer();
592
+ if (IsNewArchitecture && containerContext) {
593
+ const { triggerLayout: syncLayout } = containerContext;
474
594
  return syncLayout;
475
595
  } else {
476
596
  return noop;
@@ -521,7 +641,8 @@ var Container = typedMemo(function Container2({
521
641
  horizontal,
522
642
  getRenderedItem: getRenderedItem2,
523
643
  updateItemSize: updateItemSize2,
524
- ItemSeparatorComponent
644
+ ItemSeparatorComponent,
645
+ stickyHeaderConfig
525
646
  }) {
526
647
  const ctx = useStateContext();
527
648
  const { columnWrapperStyle, animatedScrollY } = ctx;
@@ -633,6 +754,7 @@ var Container = typedMemo(function Container2({
633
754
  if (!IsNewArchitecture) {
634
755
  React2.useEffect(() => {
635
756
  if (!isNullOrUndefined(itemKey)) {
757
+ didLayoutRef.current = false;
636
758
  const timeout = setTimeout(() => {
637
759
  if (!didLayoutRef.current) {
638
760
  const {
@@ -652,7 +774,7 @@ var Container = typedMemo(function Container2({
652
774
  }
653
775
  }, [itemKey]);
654
776
  }
655
- const PositionComponent = isSticky ? PositionViewSticky : PositionView3;
777
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
656
778
  return /* @__PURE__ */ React2__namespace.createElement(
657
779
  PositionComponent,
658
780
  {
@@ -663,6 +785,7 @@ var Container = typedMemo(function Container2({
663
785
  key: recycleItems ? void 0 : itemKey,
664
786
  onLayout,
665
787
  refView: ref,
788
+ stickyHeaderConfig,
666
789
  stickyOffset: isSticky ? stickyOffset : void 0,
667
790
  style
668
791
  },
@@ -687,10 +810,10 @@ var Containers = typedMemo(function Containers2({
687
810
  // If this is the initial scroll, we don't want to delay because we want to update the size immediately
688
811
  delay: (value, prevValue) => {
689
812
  var _a3;
690
- return !((_a3 = ctx.internalState) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
813
+ return !((_a3 = ctx.state) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
691
814
  }
692
815
  });
693
- const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("containersDidLayout", { getValue: (value) => value ? 1 : 0 }) : void 0;
816
+ const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("readyToRender", { getValue: (value) => value ? 1 : 0 }) : void 0;
694
817
  const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
695
818
  const containers = [];
696
819
  for (let i = 0; i < numContainers; i++) {
@@ -733,7 +856,8 @@ var Containers = typedMemo(function Containers2({
733
856
  return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { style }, containers);
734
857
  });
735
858
  function DevNumbers() {
736
- return IS_DEV && React2__namespace.memo(function DevNumbers2() {
859
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
860
+ React2__namespace.memo(function DevNumbers2() {
737
861
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React2__namespace.createElement(
738
862
  reactNative.View,
739
863
  {
@@ -799,15 +923,6 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
799
923
  };
800
924
 
801
925
  // src/components/ListComponent.tsx
802
- var getComponent = (Component) => {
803
- if (React2__namespace.isValidElement(Component)) {
804
- return Component;
805
- }
806
- if (Component) {
807
- return /* @__PURE__ */ React2__namespace.createElement(Component, null);
808
- }
809
- return null;
810
- };
811
926
  var ListComponent = typedMemo(function ListComponent2({
812
927
  canRender,
813
928
  style,
@@ -828,26 +943,20 @@ var ListComponent = typedMemo(function ListComponent2({
828
943
  getRenderedItem: getRenderedItem2,
829
944
  updateItemSize: updateItemSize2,
830
945
  refScrollView,
831
- maintainVisibleContentPosition,
832
946
  renderScrollComponent,
833
947
  scrollAdjustHandler,
834
948
  onLayoutHeader,
835
949
  snapToIndices,
950
+ stickyHeaderConfig,
836
951
  stickyHeaderIndices,
837
952
  ...rest
838
953
  }) {
839
954
  const ctx = useStateContext();
955
+ const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
840
956
  const ScrollComponent = renderScrollComponent ? React2.useMemo(
841
957
  () => React2__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
842
958
  [renderScrollComponent]
843
959
  ) : ListComponentScrollView;
844
- React2__namespace.useEffect(() => {
845
- if (canRender) {
846
- setTimeout(() => {
847
- scrollAdjustHandler.setMounted();
848
- }, 0);
849
- }
850
- }, [canRender]);
851
960
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
852
961
  return /* @__PURE__ */ React2__namespace.createElement(
853
962
  SnapOrScroll,
@@ -861,7 +970,7 @@ var ListComponent = typedMemo(function ListComponent2({
861
970
  ],
862
971
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
863
972
  horizontal,
864
- maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
973
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
865
974
  onLayout,
866
975
  onScroll: onScroll2,
867
976
  ref: refScrollView,
@@ -879,6 +988,7 @@ var ListComponent = typedMemo(function ListComponent2({
879
988
  horizontal,
880
989
  ItemSeparatorComponent,
881
990
  recycleItems,
991
+ stickyHeaderConfig,
882
992
  updateItemSize: updateItemSize2,
883
993
  waitForInitialLayout
884
994
  }
@@ -911,10 +1021,11 @@ function getId(state, index) {
911
1021
  }
912
1022
 
913
1023
  // src/core/calculateOffsetForIndex.ts
914
- function calculateOffsetForIndex(ctx, state, index) {
1024
+ function calculateOffsetForIndex(ctx, index) {
1025
+ const state = ctx.state;
915
1026
  let position = 0;
916
1027
  if (index !== void 0) {
917
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
1028
+ position = state.positions.get(getId(state, index)) || 0;
918
1029
  const paddingTop = peek$(ctx, "stylePaddingTop");
919
1030
  if (paddingTop) {
920
1031
  position += paddingTop;
@@ -928,7 +1039,8 @@ function calculateOffsetForIndex(ctx, state, index) {
928
1039
  }
929
1040
 
930
1041
  // src/utils/setPaddingTop.ts
931
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1042
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1043
+ const state = ctx.state;
932
1044
  if (stylePaddingTop !== void 0) {
933
1045
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
934
1046
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -947,7 +1059,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
947
1059
  }
948
1060
 
949
1061
  // src/utils/updateAlignItemsPaddingTop.ts
950
- function updateAlignItemsPaddingTop(ctx, state) {
1062
+ function updateAlignItemsPaddingTop(ctx) {
1063
+ const state = ctx.state;
951
1064
  const {
952
1065
  scrollLength,
953
1066
  props: { alignItemsAtEnd, data }
@@ -958,12 +1071,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
958
1071
  const contentSize = getContentSize(ctx);
959
1072
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
960
1073
  }
961
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1074
+ setPaddingTop(ctx, { alignItemsPaddingTop });
962
1075
  }
963
1076
  }
964
1077
 
965
1078
  // src/core/addTotalSize.ts
966
- function addTotalSize(ctx, state, key, add) {
1079
+ function addTotalSize(ctx, key, add) {
1080
+ const state = ctx.state;
967
1081
  const { alignItemsAtEnd } = state.props;
968
1082
  const prevTotalSize = state.totalSize;
969
1083
  let totalSize = state.totalSize;
@@ -984,31 +1098,34 @@ function addTotalSize(ctx, state, key, add) {
984
1098
  state.totalSize = totalSize;
985
1099
  set$(ctx, "totalSize", totalSize);
986
1100
  if (alignItemsAtEnd) {
987
- updateAlignItemsPaddingTop(ctx, state);
1101
+ updateAlignItemsPaddingTop(ctx);
988
1102
  }
989
1103
  }
990
1104
  }
991
1105
  }
992
1106
 
993
1107
  // src/core/setSize.ts
994
- function setSize(ctx, state, itemKey, size) {
1108
+ function setSize(ctx, itemKey, size) {
1109
+ const state = ctx.state;
995
1110
  const { sizes } = state;
996
1111
  const previousSize = sizes.get(itemKey);
997
1112
  const diff = previousSize !== void 0 ? size - previousSize : size;
998
1113
  if (diff !== 0) {
999
- addTotalSize(ctx, state, itemKey, diff);
1114
+ addTotalSize(ctx, itemKey, diff);
1000
1115
  }
1001
1116
  sizes.set(itemKey, size);
1002
1117
  }
1003
1118
 
1004
1119
  // src/utils/getItemSize.ts
1005
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1120
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1006
1121
  var _a3, _b;
1122
+ const state = ctx.state;
1007
1123
  const {
1008
1124
  sizesKnown,
1009
1125
  sizes,
1010
1126
  averageSizes,
1011
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1127
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1128
+ scrollingTo
1012
1129
  } = state;
1013
1130
  const sizeKnown = sizesKnown.get(key);
1014
1131
  if (sizeKnown !== void 0) {
@@ -1016,7 +1133,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1016
1133
  }
1017
1134
  let size;
1018
1135
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1019
- const scrollingTo = peek$(ctx, "scrollingTo");
1020
1136
  if (preferCachedSize) {
1021
1137
  const cachedSize = sizes.get(key);
1022
1138
  if (cachedSize !== void 0) {
@@ -1024,7 +1140,7 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1024
1140
  }
1025
1141
  }
1026
1142
  if (getFixedItemSize) {
1027
- size = getFixedItemSize(index, data, itemType);
1143
+ size = getFixedItemSize(data, index, itemType);
1028
1144
  if (size !== void 0) {
1029
1145
  sizesKnown.set(key, size);
1030
1146
  }
@@ -1042,96 +1158,192 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1042
1158
  }
1043
1159
  }
1044
1160
  if (size === void 0) {
1045
- size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1161
+ size = getEstimatedItemSize ? getEstimatedItemSize(data, index, itemType) : estimatedItemSize;
1046
1162
  }
1047
- setSize(ctx, state, key, size);
1163
+ setSize(ctx, key, size);
1048
1164
  return size;
1049
1165
  }
1050
1166
 
1051
1167
  // src/core/calculateOffsetWithOffsetPosition.ts
1052
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1168
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1169
+ const state = ctx.state;
1053
1170
  const { index, viewOffset, viewPosition } = params;
1054
1171
  let offset = offsetParam;
1055
1172
  if (viewOffset) {
1056
1173
  offset -= viewOffset;
1057
1174
  }
1058
1175
  if (viewPosition !== void 0 && index !== void 0) {
1059
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1176
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1177
+ const trailingInset = getContentInsetEnd(state);
1178
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1060
1179
  }
1061
1180
  return offset;
1062
1181
  }
1182
+ var Platform2 = reactNative.Platform;
1183
+ var PlatformAdjustBreaksScroll = Platform2.OS === "android";
1184
+
1185
+ // src/core/clampScrollOffset.ts
1186
+ function clampScrollOffset(ctx, offset) {
1187
+ const state = ctx.state;
1188
+ const contentSize = getContentSize(ctx);
1189
+ let clampedOffset = offset;
1190
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform2.OS !== "android" || state.lastLayout)) {
1191
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1192
+ clampedOffset = Math.min(offset, maxOffset);
1193
+ }
1194
+ clampedOffset = Math.max(0, clampedOffset);
1195
+ return clampedOffset;
1196
+ }
1197
+
1198
+ // src/utils/setInitialRenderState.ts
1199
+ function setInitialRenderState(ctx, {
1200
+ didLayout,
1201
+ didInitialScroll
1202
+ }) {
1203
+ const { state } = ctx;
1204
+ if (didLayout) {
1205
+ state.didContainersLayout = true;
1206
+ }
1207
+ if (didInitialScroll) {
1208
+ state.didFinishInitialScroll = true;
1209
+ }
1210
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1211
+ set$(ctx, "readyToRender", true);
1212
+ }
1213
+ }
1063
1214
 
1064
1215
  // src/core/finishScrollTo.ts
1065
- function finishScrollTo(ctx, state) {
1216
+ function finishScrollTo(ctx) {
1066
1217
  var _a3, _b;
1067
- if (state) {
1218
+ const state = ctx.state;
1219
+ if (state == null ? void 0 : state.scrollingTo) {
1220
+ const scrollingTo = state.scrollingTo;
1068
1221
  state.scrollHistory.length = 0;
1069
1222
  state.initialScroll = void 0;
1070
1223
  state.initialAnchor = void 0;
1071
- set$(ctx, "scrollingTo", void 0);
1224
+ state.scrollingTo = void 0;
1072
1225
  if (state.pendingTotalSize !== void 0) {
1073
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1226
+ addTotalSize(ctx, null, state.pendingTotalSize);
1074
1227
  }
1075
1228
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1076
1229
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1077
1230
  }
1231
+ if (PlatformAdjustBreaksScroll) {
1232
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1233
+ }
1234
+ setInitialRenderState(ctx, { didInitialScroll: true });
1078
1235
  }
1079
1236
  }
1080
- var Platform2 = reactNative.Platform;
1081
1237
 
1082
- // src/core/scrollTo.ts
1083
- function scrollTo(ctx, state, params) {
1238
+ // src/core/checkFinishedScroll.ts
1239
+ function checkFinishedScroll(ctx) {
1240
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1241
+ }
1242
+ function checkFinishedScrollFrame(ctx) {
1243
+ const scrollingTo = ctx.state.scrollingTo;
1244
+ if (scrollingTo) {
1245
+ const { state } = ctx;
1246
+ state.animFrameCheckFinishedScroll = void 0;
1247
+ const scroll = state.scrollPending;
1248
+ const adjust = state.scrollAdjustHandler.getAdjust();
1249
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
1250
+ const maxOffset = clampScrollOffset(ctx, scroll);
1251
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
1252
+ const diff2 = Math.abs(diff1 - adjust);
1253
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
1254
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
1255
+ finishScrollTo(ctx);
1256
+ }
1257
+ }
1258
+ }
1259
+ function checkFinishedScrollFallback(ctx) {
1260
+ const state = ctx.state;
1261
+ const scrollingTo = state.scrollingTo;
1262
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
1263
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
1264
+ () => {
1265
+ let numChecks = 0;
1266
+ const checkHasScrolled = () => {
1267
+ state.timeoutCheckFinishedScrollFallback = void 0;
1268
+ const isStillScrollingTo = state.scrollingTo;
1269
+ if (isStillScrollingTo) {
1270
+ numChecks++;
1271
+ if (state.hasScrolled || numChecks > 5) {
1272
+ finishScrollTo(ctx);
1273
+ } else {
1274
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
1275
+ }
1276
+ }
1277
+ };
1278
+ checkHasScrolled();
1279
+ },
1280
+ slowTimeout ? 500 : 100
1281
+ );
1282
+ }
1283
+
1284
+ // src/core/doScrollTo.native.ts
1285
+ function doScrollTo(ctx, params) {
1084
1286
  var _a3;
1085
- const { noScrollingTo, ...scrollTarget } = params;
1287
+ const state = ctx.state;
1288
+ const { animated, horizontal, offset } = params;
1289
+ const { refScroller } = state;
1290
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1291
+ animated: !!animated,
1292
+ x: horizontal ? offset : 0,
1293
+ y: horizontal ? 0 : offset
1294
+ });
1295
+ if (!animated) {
1296
+ state.scroll = offset;
1297
+ checkFinishedScrollFallback(ctx);
1298
+ }
1299
+ }
1300
+
1301
+ // src/core/scrollTo.ts
1302
+ function scrollTo(ctx, params) {
1303
+ const state = ctx.state;
1304
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1086
1305
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1087
1306
  const {
1088
- refScroller,
1089
1307
  props: { horizontal }
1090
1308
  } = state;
1091
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1092
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1093
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1094
- offset = Math.min(offset, maxOffset);
1309
+ if (state.animFrameCheckFinishedScroll) {
1310
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1311
+ }
1312
+ if (state.timeoutCheckFinishedScrollFallback) {
1313
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1095
1314
  }
1315
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1316
+ offset = clampScrollOffset(ctx, offset);
1096
1317
  state.scrollHistory.length = 0;
1097
1318
  if (!noScrollingTo) {
1098
- set$(ctx, "scrollingTo", scrollTarget);
1319
+ state.scrollingTo = scrollTarget;
1099
1320
  }
1100
1321
  state.scrollPending = offset;
1101
- if (!isInitialScroll || Platform2.OS === "android") {
1102
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1103
- animated: !!animated,
1104
- x: horizontal ? offset : 0,
1105
- y: horizontal ? 0 : offset
1106
- });
1107
- }
1108
- if (!animated) {
1322
+ if (forceScroll || !isInitialScroll || Platform2.OS === "android") {
1323
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1324
+ } else {
1109
1325
  state.scroll = offset;
1110
- if (Platform2.OS === "web") {
1111
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1112
- if (value && peek$(ctx, "scrollingTo")) {
1113
- finishScrollTo(ctx, state);
1114
- unlisten();
1115
- }
1116
- });
1117
- } else {
1118
- setTimeout(() => finishScrollTo(ctx, state), 100);
1119
- }
1120
- if (isInitialScroll) {
1121
- setTimeout(() => {
1122
- state.initialScroll = void 0;
1123
- }, 500);
1124
- }
1125
1326
  }
1126
1327
  }
1127
1328
 
1329
+ // src/platform/flushSync.native.ts
1330
+ var flushSync = (fn) => {
1331
+ fn();
1332
+ };
1333
+
1128
1334
  // src/utils/checkThreshold.ts
1129
1335
  var HYSTERESIS_MULTIPLIER = 1.3;
1130
- var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1336
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot, allowReentryOnChange) => {
1131
1337
  const absDistance = Math.abs(distance);
1132
1338
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1339
+ if (wasReached === null) {
1340
+ if (!within && distance >= 0) {
1341
+ return false;
1342
+ }
1343
+ return null;
1344
+ }
1133
1345
  const updateSnapshot = () => {
1134
- setSnapshot == null ? void 0 : setSnapshot({
1346
+ setSnapshot({
1135
1347
  atThreshold,
1136
1348
  contentSize: context.contentSize,
1137
1349
  dataLength: context.dataLength,
@@ -1142,19 +1354,21 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1142
1354
  if (!within) {
1143
1355
  return false;
1144
1356
  }
1145
- onReached == null ? void 0 : onReached(distance);
1357
+ onReached(distance);
1146
1358
  updateSnapshot();
1147
1359
  return true;
1148
1360
  }
1149
1361
  const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1150
1362
  if (reset) {
1151
- setSnapshot == null ? void 0 : setSnapshot(void 0);
1363
+ setSnapshot(void 0);
1152
1364
  return false;
1153
1365
  }
1154
1366
  if (within) {
1155
1367
  const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
1156
1368
  if (changed) {
1157
- onReached == null ? void 0 : onReached(distance);
1369
+ if (allowReentryOnChange) {
1370
+ onReached(distance);
1371
+ }
1158
1372
  updateSnapshot();
1159
1373
  }
1160
1374
  }
@@ -1162,8 +1376,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1162
1376
  };
1163
1377
 
1164
1378
  // src/utils/checkAtBottom.ts
1165
- function checkAtBottom(ctx, state) {
1379
+ function checkAtBottom(ctx) {
1166
1380
  var _a3;
1381
+ const state = ctx.state;
1167
1382
  if (!state) {
1168
1383
  return;
1169
1384
  }
@@ -1196,7 +1411,8 @@ function checkAtBottom(ctx, state) {
1196
1411
  },
1197
1412
  (snapshot) => {
1198
1413
  state.endReachedSnapshot = snapshot;
1199
- }
1414
+ },
1415
+ true
1200
1416
  );
1201
1417
  }
1202
1418
  }
@@ -1231,20 +1447,21 @@ function checkAtTop(state) {
1231
1447
  },
1232
1448
  (snapshot) => {
1233
1449
  state.startReachedSnapshot = snapshot;
1234
- }
1450
+ },
1451
+ false
1235
1452
  );
1236
1453
  }
1237
1454
 
1238
1455
  // src/core/updateScroll.ts
1239
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1240
- var _a3;
1241
- const scrollingTo = peek$(ctx, "scrollingTo");
1456
+ function updateScroll(ctx, newScroll, forceUpdate) {
1457
+ const state = ctx.state;
1458
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1459
+ const prevScroll = state.scroll;
1242
1460
  state.hasScrolled = true;
1243
1461
  state.lastBatchingAction = Date.now();
1244
1462
  const currentTime = Date.now();
1245
- const adjust = state.scrollAdjustHandler.getAdjust();
1246
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1247
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1463
+ const adjust = scrollAdjustHandler.getAdjust();
1464
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1248
1465
  if (adjustChanged) {
1249
1466
  state.scrollHistory.length = 0;
1250
1467
  }
@@ -1257,7 +1474,7 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1257
1474
  if (state.scrollHistory.length > 5) {
1258
1475
  state.scrollHistory.shift();
1259
1476
  }
1260
- state.scrollPrev = state.scroll;
1477
+ state.scrollPrev = prevScroll;
1261
1478
  state.scrollPrevTime = state.scrollTime;
1262
1479
  state.scroll = newScroll;
1263
1480
  state.scrollTime = currentTime;
@@ -1269,22 +1486,38 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1269
1486
  return;
1270
1487
  }
1271
1488
  }
1272
- if (forceUpdate || state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1489
+ const scrollDelta = Math.abs(newScroll - prevScroll);
1490
+ const scrollLength = state.scrollLength;
1491
+ const lastCalculated = state.scrollLastCalculate;
1492
+ const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1493
+ if (shouldUpdate) {
1494
+ state.scrollLastCalculate = state.scroll;
1273
1495
  state.ignoreScrollFromMVCPIgnored = false;
1274
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1275
- checkAtBottom(ctx, state);
1276
- checkAtTop(state);
1496
+ state.lastScrollDelta = scrollDelta;
1497
+ const runCalculateItems = () => {
1498
+ var _a3;
1499
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1500
+ checkAtBottom(ctx);
1501
+ checkAtTop(state);
1502
+ };
1503
+ if (Platform2.OS === "web" && scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
1504
+ flushSync(runCalculateItems);
1505
+ } else {
1506
+ runCalculateItems();
1507
+ }
1277
1508
  state.dataChangeNeedsScrollUpdate = false;
1509
+ state.lastScrollDelta = 0;
1278
1510
  }
1279
1511
  }
1280
1512
 
1281
1513
  // src/utils/requestAdjust.ts
1282
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1514
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1515
+ const state = ctx.state;
1283
1516
  if (Math.abs(positionDiff) > 0.1) {
1284
1517
  const needsScrollWorkaround = Platform2.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
1285
1518
  const doit = () => {
1286
1519
  if (needsScrollWorkaround) {
1287
- scrollTo(ctx, state, {
1520
+ scrollTo(ctx, {
1288
1521
  noScrollingTo: true,
1289
1522
  offset: state.scroll
1290
1523
  });
@@ -1297,8 +1530,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1297
1530
  };
1298
1531
  state.scroll += positionDiff;
1299
1532
  state.scrollForNextCalculateItemsInView = void 0;
1300
- const didLayout = peek$(ctx, "containersDidLayout");
1301
- if (didLayout) {
1533
+ const readyToRender = peek$(ctx, "readyToRender");
1534
+ if (readyToRender) {
1302
1535
  doit();
1303
1536
  if (Platform2.OS !== "web") {
1304
1537
  const threshold = state.scroll - positionDiff / 2;
@@ -1320,7 +1553,7 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1320
1553
  if (shouldForceUpdate) {
1321
1554
  state.ignoreScrollFromMVCPIgnored = false;
1322
1555
  state.scrollPending = state.scroll;
1323
- updateScroll(ctx, state, state.scroll, true);
1556
+ updateScroll(ctx, state.scroll, true);
1324
1557
  }
1325
1558
  }, delay);
1326
1559
  }
@@ -1335,28 +1568,27 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1335
1568
  var INITIAL_ANCHOR_TOLERANCE = 0.5;
1336
1569
  var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1337
1570
  var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1338
- function ensureInitialAnchor(ctx, state) {
1571
+ function ensureInitialAnchor(ctx) {
1339
1572
  var _a3, _b, _c, _d, _e;
1340
- const anchor = state.initialAnchor;
1573
+ const state = ctx.state;
1574
+ const { initialAnchor, didContainersLayout, positions, scroll, scrollLength } = state;
1575
+ const anchor = initialAnchor;
1341
1576
  const item = state.props.data[anchor.index];
1342
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1343
- if (!containersDidLayout) {
1577
+ if (!didContainersLayout) {
1344
1578
  return;
1345
1579
  }
1346
1580
  const id = getId(state, anchor.index);
1347
- if (state.positions.get(id) === void 0) {
1581
+ if (positions.get(id) === void 0) {
1348
1582
  return;
1349
1583
  }
1350
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1584
+ const size = getItemSize(ctx, id, anchor.index, item, true, true);
1351
1585
  if (size === void 0) {
1352
1586
  return;
1353
1587
  }
1354
- const availableSpace = Math.max(0, state.scrollLength - size);
1355
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1356
- const contentSize = getContentSize(ctx);
1357
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1358
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1359
- const delta = clampedDesiredOffset - state.scroll;
1588
+ const availableSpace = Math.max(0, scrollLength - size);
1589
+ const desiredOffset = calculateOffsetForIndex(ctx, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1590
+ const clampedDesiredOffset = clampScrollOffset(ctx, desiredOffset);
1591
+ const delta = clampedDesiredOffset - scroll;
1360
1592
  if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1361
1593
  const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1362
1594
  if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
@@ -1380,19 +1612,24 @@ function ensureInitialAnchor(ctx, state) {
1380
1612
  lastDelta: delta,
1381
1613
  settledTicks: 0
1382
1614
  });
1383
- requestAdjust(ctx, state, delta);
1615
+ requestAdjust(ctx, delta);
1616
+ requestAnimationFrame(() => finishScrollTo(ctx));
1384
1617
  }
1385
1618
 
1386
1619
  // src/core/mvcp.ts
1387
- function prepareMVCP(ctx, state, dataChanged) {
1620
+ function prepareMVCP(ctx, dataChanged) {
1621
+ const state = ctx.state;
1388
1622
  const { idsInView, positions, props } = state;
1389
- const { maintainVisibleContentPosition } = props;
1390
- const scrollingTo = peek$(ctx, "scrollingTo");
1623
+ const {
1624
+ maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll, shouldRestorePosition }
1625
+ } = props;
1626
+ const scrollingTo = state.scrollingTo;
1391
1627
  let prevPosition;
1392
1628
  let targetId;
1393
1629
  const idsInViewWithPositions = [];
1394
1630
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1395
- const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1631
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1632
+ const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1396
1633
  const indexByKey = state.indexByKey;
1397
1634
  if (shouldMVCP) {
1398
1635
  if (scrollTarget !== void 0) {
@@ -1400,7 +1637,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1400
1637
  return void 0;
1401
1638
  }
1402
1639
  targetId = getId(state, scrollTarget);
1403
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1640
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1404
1641
  if (dataChanged) {
1405
1642
  for (let i = 0; i < idsInView.length; i++) {
1406
1643
  const id = idsInView[i];
@@ -1417,10 +1654,18 @@ function prepareMVCP(ctx, state, dataChanged) {
1417
1654
  prevPosition = positions.get(targetId);
1418
1655
  }
1419
1656
  return () => {
1420
- let positionDiff;
1421
- if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1657
+ let positionDiff = 0;
1658
+ if (dataChanged && targetId === void 0 && mvcpData) {
1659
+ const data = state.props.data;
1422
1660
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1423
1661
  const { id, position } = idsInViewWithPositions[i];
1662
+ const index = indexByKey.get(id);
1663
+ if (index !== void 0 && shouldRestorePosition) {
1664
+ const item = data[index];
1665
+ if (item === void 0 || !shouldRestorePosition(item, index, data)) {
1666
+ continue;
1667
+ }
1668
+ }
1424
1669
  const newPosition = positions.get(id);
1425
1670
  if (newPosition !== void 0) {
1426
1671
  positionDiff = newPosition - position;
@@ -1443,16 +1688,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1443
1688
  positionDiff = diff;
1444
1689
  }
1445
1690
  }
1446
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1447
- requestAdjust(ctx, state, positionDiff, dataChanged && maintainVisibleContentPosition);
1691
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1692
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1693
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1694
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1695
+ const diff = newSize - prevSize;
1696
+ if (diff !== 0) {
1697
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1698
+ scrollingTo.itemSize = newSize;
1699
+ }
1700
+ }
1701
+ }
1702
+ if (Math.abs(positionDiff) > 0.1) {
1703
+ requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
1448
1704
  }
1449
1705
  };
1450
1706
  }
1451
1707
  }
1452
1708
 
1453
1709
  // src/core/prepareColumnStartState.ts
1454
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1710
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1455
1711
  var _a3;
1712
+ const state = ctx.state;
1456
1713
  const numColumns = peek$(ctx, "numColumns");
1457
1714
  let rowStartIndex = startIndex;
1458
1715
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1467,7 +1724,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1467
1724
  const prevId = state.idCache[prevIndex];
1468
1725
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1469
1726
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1470
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1727
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1471
1728
  currentRowTop = prevPosition + prevRowHeight;
1472
1729
  }
1473
1730
  return {
@@ -1490,7 +1747,8 @@ function findRowStartIndex(state, numColumns, index) {
1490
1747
  }
1491
1748
  return rowStart;
1492
1749
  }
1493
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1750
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1751
+ const state = ctx.state;
1494
1752
  if (endIndex < startIndex) {
1495
1753
  return 0;
1496
1754
  }
@@ -1504,7 +1762,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1504
1762
  continue;
1505
1763
  }
1506
1764
  const id = state.idCache[i];
1507
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1765
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1508
1766
  if (size > maxSize) {
1509
1767
  maxSize = size;
1510
1768
  }
@@ -1513,22 +1771,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1513
1771
  }
1514
1772
 
1515
1773
  // src/core/updateTotalSize.ts
1516
- function updateTotalSize(ctx, state) {
1774
+ function updateTotalSize(ctx) {
1775
+ const state = ctx.state;
1517
1776
  const {
1518
1777
  positions,
1519
1778
  props: { data }
1520
1779
  } = state;
1521
1780
  if (data.length === 0) {
1522
- addTotalSize(ctx, state, null, 0);
1781
+ addTotalSize(ctx, null, 0);
1523
1782
  } else {
1524
1783
  const lastId = getId(state, data.length - 1);
1525
1784
  if (lastId !== void 0) {
1526
1785
  const lastPosition = positions.get(lastId);
1527
1786
  if (lastPosition !== void 0) {
1528
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1787
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1529
1788
  if (lastSize !== void 0) {
1530
1789
  const totalSize = lastPosition + lastSize;
1531
- addTotalSize(ctx, state, null, totalSize);
1790
+ addTotalSize(ctx, null, totalSize);
1532
1791
  }
1533
1792
  }
1534
1793
  }
@@ -1538,43 +1797,45 @@ function updateTotalSize(ctx, state) {
1538
1797
  // src/utils/getScrollVelocity.ts
1539
1798
  var getScrollVelocity = (state) => {
1540
1799
  const { scrollHistory } = state;
1541
- let velocity = 0;
1542
- if (scrollHistory.length >= 1) {
1543
- const newest = scrollHistory[scrollHistory.length - 1];
1544
- let oldest;
1545
- let start = 0;
1546
- const now = Date.now();
1547
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1548
- const entry = scrollHistory[i];
1549
- const nextEntry = scrollHistory[i + 1];
1550
- if (i > 0) {
1551
- const prevEntry = scrollHistory[i - 1];
1552
- const prevDirection = entry.scroll - prevEntry.scroll;
1553
- const currentDirection = nextEntry.scroll - entry.scroll;
1554
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1555
- start = i;
1556
- break;
1557
- }
1558
- }
1800
+ const newestIndex = scrollHistory.length - 1;
1801
+ if (newestIndex < 1) {
1802
+ return 0;
1803
+ }
1804
+ const newest = scrollHistory[newestIndex];
1805
+ const now = Date.now();
1806
+ let direction = 0;
1807
+ for (let i = newestIndex; i > 0; i--) {
1808
+ const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
1809
+ if (delta !== 0) {
1810
+ direction = Math.sign(delta);
1811
+ break;
1559
1812
  }
1560
- for (let i = start; i < scrollHistory.length - 1; i++) {
1561
- const entry = scrollHistory[i];
1562
- if (now - entry.time <= 1e3) {
1563
- oldest = entry;
1564
- break;
1565
- }
1813
+ }
1814
+ if (direction === 0) {
1815
+ return 0;
1816
+ }
1817
+ let oldest = newest;
1818
+ for (let i = newestIndex - 1; i >= 0; i--) {
1819
+ const current = scrollHistory[i];
1820
+ const next = scrollHistory[i + 1];
1821
+ const delta = next.scroll - current.scroll;
1822
+ const deltaSign = Math.sign(delta);
1823
+ if (deltaSign !== 0 && deltaSign !== direction) {
1824
+ break;
1566
1825
  }
1567
- if (oldest && oldest !== newest) {
1568
- const scrollDiff = newest.scroll - oldest.scroll;
1569
- const timeDiff = newest.time - oldest.time;
1570
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1826
+ if (now - current.time > 1e3) {
1827
+ break;
1571
1828
  }
1829
+ oldest = current;
1572
1830
  }
1573
- return velocity;
1831
+ const scrollDiff = newest.scroll - oldest.scroll;
1832
+ const timeDiff = newest.time - oldest.time;
1833
+ return timeDiff > 0 ? scrollDiff / timeDiff : 0;
1574
1834
  };
1575
1835
 
1576
1836
  // src/utils/updateSnapToOffsets.ts
1577
- function updateSnapToOffsets(ctx, state) {
1837
+ function updateSnapToOffsets(ctx) {
1838
+ const state = ctx.state;
1578
1839
  const {
1579
1840
  positions,
1580
1841
  props: { snapToIndices }
@@ -1589,30 +1850,32 @@ function updateSnapToOffsets(ctx, state) {
1589
1850
  }
1590
1851
 
1591
1852
  // src/core/updateItemPositions.ts
1592
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1853
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1593
1854
  doMVCP: false,
1594
1855
  forceFullUpdate: false,
1595
1856
  scrollBottomBuffered: -1,
1596
1857
  startIndex: 0
1597
1858
  }) {
1598
1859
  var _a3, _b, _c, _d, _e;
1860
+ const state = ctx.state;
1599
1861
  const {
1600
1862
  columns,
1601
1863
  indexByKey,
1602
1864
  positions,
1603
1865
  idCache,
1604
1866
  sizesKnown,
1605
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1867
+ props: { data, getEstimatedItemSize, snapToIndices },
1868
+ scrollingTo
1606
1869
  } = state;
1607
- const data = state.props.data;
1608
1870
  const dataLength = data.length;
1609
1871
  const numColumns = peek$(ctx, "numColumns");
1610
- const scrollingTo = peek$(ctx, "scrollingTo");
1611
1872
  const hasColumns = numColumns > 1;
1612
1873
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1613
- const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1874
+ const lastScrollDelta = state.lastScrollDelta;
1875
+ const velocity = getScrollVelocity(state);
1876
+ const shouldOptimize = !forceFullUpdate && !dataChanged && (Math.abs(velocity) > 0 || Platform2.OS === "web" && state.scrollLength > 0 && lastScrollDelta > state.scrollLength);
1614
1877
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1615
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1878
+ const useAverageSize = !getEstimatedItemSize;
1616
1879
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1617
1880
  let currentRowTop = 0;
1618
1881
  let column = 1;
@@ -1621,7 +1884,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1621
1884
  if (hasColumns) {
1622
1885
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1623
1886
  ctx,
1624
- state,
1625
1887
  startIndex,
1626
1888
  useAverageSize
1627
1889
  );
@@ -1631,7 +1893,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1631
1893
  const prevIndex = startIndex - 1;
1632
1894
  const prevId = getId(state, prevIndex);
1633
1895
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1634
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1896
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1635
1897
  currentRowTop = prevPosition + prevSize;
1636
1898
  }
1637
1899
  }
@@ -1648,7 +1910,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1648
1910
  breakAt = i + itemsPerRow + 10;
1649
1911
  }
1650
1912
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1651
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1913
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1652
1914
  if (IS_DEV && needsIndexByKey) {
1653
1915
  if (indexByKeyForChecking.has(id)) {
1654
1916
  console.error(
@@ -1657,7 +1919,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1657
1919
  }
1658
1920
  indexByKeyForChecking.set(id, i);
1659
1921
  }
1660
- positions.set(id, currentRowTop);
1922
+ if (currentRowTop !== positions.get(id)) {
1923
+ positions.set(id, currentRowTop);
1924
+ notifyPosition$(ctx, id, currentRowTop);
1925
+ }
1661
1926
  if (needsIndexByKey) {
1662
1927
  indexByKey.set(id, i);
1663
1928
  }
@@ -1677,10 +1942,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1677
1942
  }
1678
1943
  }
1679
1944
  if (!didBreakEarly) {
1680
- updateTotalSize(ctx, state);
1945
+ updateTotalSize(ctx);
1681
1946
  }
1682
1947
  if (snapToIndices) {
1683
- updateSnapToOffsets(ctx, state);
1948
+ updateSnapToOffsets(ctx);
1684
1949
  }
1685
1950
  }
1686
1951
 
@@ -1758,7 +2023,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1758
2023
  if (previousViewableItems) {
1759
2024
  for (const viewToken of previousViewableItems) {
1760
2025
  const containerId = findContainerId(ctx, viewToken.key);
1761
- if (!isViewable(
2026
+ if (!checkIsViewable(
1762
2027
  state,
1763
2028
  ctx,
1764
2029
  viewabilityConfig,
@@ -1779,7 +2044,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1779
2044
  if (item) {
1780
2045
  const key = getId(state, i);
1781
2046
  const containerId = findContainerId(ctx, key);
1782
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2047
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1783
2048
  const viewToken = {
1784
2049
  containerId,
1785
2050
  index: i,
@@ -1839,11 +2104,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1839
2104
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
1840
2105
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
1841
2106
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
1842
- const isViewable2 = percent >= viewablePercentThreshold;
2107
+ const isViewable = percent >= viewablePercentThreshold;
1843
2108
  const value = {
1844
2109
  containerId,
1845
2110
  index,
1846
- isViewable: isViewable2,
2111
+ isViewable,
1847
2112
  item,
1848
2113
  key,
1849
2114
  percentOfScroller,
@@ -1862,8 +2127,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1862
2127
  }
1863
2128
  return value;
1864
2129
  }
1865
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
1866
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2130
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2131
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2132
+ if (!value || value.key !== key) {
2133
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2134
+ }
1867
2135
  return value.isViewable;
1868
2136
  }
1869
2137
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -1891,8 +2159,9 @@ function checkAllSizesKnown(state) {
1891
2159
  }
1892
2160
 
1893
2161
  // src/utils/findAvailableContainers.ts
1894
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2162
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
1895
2163
  const numContainers = peek$(ctx, "numContainers");
2164
+ const state = ctx.state;
1896
2165
  const { stickyContainerPool, containerItemTypes } = state;
1897
2166
  const result = [];
1898
2167
  const availableContainers = [];
@@ -2012,21 +2281,26 @@ function comparatorByDistance(a, b) {
2012
2281
  }
2013
2282
 
2014
2283
  // src/core/scrollToIndex.ts
2015
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2016
- if (index >= state.props.data.length) {
2017
- index = state.props.data.length - 1;
2284
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2285
+ const state = ctx.state;
2286
+ const { data } = state.props;
2287
+ if (index >= data.length) {
2288
+ index = data.length - 1;
2018
2289
  } else if (index < 0) {
2019
2290
  index = 0;
2020
2291
  }
2021
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2022
- const isLast = index === state.props.data.length - 1;
2292
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2293
+ const isLast = index === data.length - 1;
2023
2294
  if (isLast && viewPosition === void 0) {
2024
2295
  viewPosition = 1;
2025
2296
  }
2026
2297
  state.scrollForNextCalculateItemsInView = void 0;
2027
- scrollTo(ctx, state, {
2298
+ const targetId = getId(state, index);
2299
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2300
+ scrollTo(ctx, {
2028
2301
  animated,
2029
2302
  index,
2303
+ itemSize,
2030
2304
  offset: firstIndexOffset,
2031
2305
  viewOffset,
2032
2306
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2034,34 +2308,28 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2034
2308
  }
2035
2309
 
2036
2310
  // src/utils/setDidLayout.ts
2037
- function setDidLayout(ctx, state) {
2311
+ function setDidLayout(ctx) {
2312
+ const state = ctx.state;
2038
2313
  const {
2039
2314
  loadStartTime,
2040
2315
  initialScroll,
2041
2316
  props: { onLoad }
2042
2317
  } = state;
2043
2318
  state.queuedInitialLayout = true;
2044
- checkAtBottom(ctx, state);
2319
+ checkAtBottom(ctx);
2045
2320
  const setIt = () => {
2046
- set$(ctx, "containersDidLayout", true);
2321
+ setInitialRenderState(ctx, { didLayout: true });
2047
2322
  if (onLoad) {
2048
2323
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2049
2324
  }
2050
2325
  };
2051
- if (Platform2.OS === "android" && initialScroll) {
2052
- if (IsNewArchitecture) {
2053
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2054
- requestAnimationFrame(() => {
2055
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2056
- setIt();
2057
- });
2058
- } else {
2059
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2060
- setIt();
2061
- }
2062
- } else {
2063
- setIt();
2326
+ if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
2327
+ const target = initialScroll;
2328
+ const runScroll = () => scrollToIndex(ctx, { ...target, animated: false });
2329
+ runScroll();
2330
+ requestAnimationFrame(runScroll);
2064
2331
  }
2332
+ setIt();
2065
2333
  }
2066
2334
 
2067
2335
  // src/core/calculateItemsInView.ts
@@ -2079,31 +2347,36 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2079
2347
  }
2080
2348
  return -1;
2081
2349
  }
2082
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2350
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2351
+ const state = ctx.state;
2083
2352
  return new Set(
2084
2353
  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))
2085
2354
  );
2086
2355
  }
2087
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2356
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, needNewContainersSet, startBuffered, endBuffered) {
2088
2357
  var _a3;
2089
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2090
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2358
+ const state = ctx.state;
2359
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2360
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2091
2361
  for (let offset = 0; offset <= 1; offset++) {
2092
2362
  const idx = currentStickyIdx - offset;
2093
2363
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
2094
2364
  const stickyIndex = stickyArray[idx];
2095
2365
  const stickyId = (_a3 = state.idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
2096
- if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
2366
+ if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered) && !needNewContainersSet.has(stickyIndex)) {
2367
+ needNewContainersSet.add(stickyIndex);
2097
2368
  needNewContainers.push(stickyIndex);
2098
2369
  }
2099
2370
  }
2100
2371
  }
2101
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2372
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2102
2373
  var _a3, _b, _c;
2374
+ const state = ctx.state;
2103
2375
  for (const containerIndex of state.stickyContainerPool) {
2104
2376
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2105
2377
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
2106
2378
  if (itemIndex === void 0) continue;
2379
+ if (alwaysRenderIndicesSet.has(itemIndex)) continue;
2107
2380
  const arrayIdx = stickyArray.indexOf(itemIndex);
2108
2381
  if (arrayIdx === -1) {
2109
2382
  state.stickyContainerPool.delete(containerIndex);
@@ -2123,7 +2396,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2123
2396
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2124
2397
  if (currentId) {
2125
2398
  const currentPos = state.positions.get(currentId);
2126
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2399
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2127
2400
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2128
2401
  }
2129
2402
  }
@@ -2132,9 +2405,10 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2132
2405
  }
2133
2406
  }
2134
2407
  }
2135
- function calculateItemsInView(ctx, state, params = {}) {
2408
+ function calculateItemsInView(ctx, params = {}) {
2409
+ const state = ctx.state;
2136
2410
  reactNative.unstable_batchedUpdates(() => {
2137
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2411
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
2138
2412
  const {
2139
2413
  columns,
2140
2414
  containerItemKeys,
@@ -2144,7 +2418,15 @@ function calculateItemsInView(ctx, state, params = {}) {
2144
2418
  initialScroll,
2145
2419
  minIndexSizeChanged,
2146
2420
  positions,
2147
- props: { getItemType, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer },
2421
+ props: {
2422
+ alwaysRenderIndicesArr,
2423
+ alwaysRenderIndicesSet,
2424
+ getItemType,
2425
+ itemsAreEqual,
2426
+ keyExtractor,
2427
+ onStickyHeaderChange,
2428
+ scrollBuffer
2429
+ },
2148
2430
  scrollForNextCalculateItemsInView,
2149
2431
  scrollLength,
2150
2432
  sizes,
@@ -2154,10 +2436,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2154
2436
  const { data } = state.props;
2155
2437
  const stickyIndicesArr = state.props.stickyIndicesArr || [];
2156
2438
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2439
+ const alwaysRenderArr = alwaysRenderIndicesArr || [];
2440
+ const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
2157
2441
  const prevNumContainers = peek$(ctx, "numContainers");
2158
2442
  if (!data || scrollLength === 0 || !prevNumContainers) {
2159
- if (state.initialAnchor) {
2160
- ensureInitialAnchor(ctx, state);
2443
+ if (!IsNewArchitecture && state.initialAnchor) {
2444
+ ensureInitialAnchor(ctx);
2161
2445
  }
2162
2446
  return;
2163
2447
  }
@@ -2172,15 +2456,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2172
2456
  if (!queuedInitialLayout && initialScroll) {
2173
2457
  const updatedOffset = calculateOffsetWithOffsetPosition(
2174
2458
  ctx,
2175
- state,
2176
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2459
+ calculateOffsetForIndex(ctx, initialScroll.index),
2177
2460
  initialScroll
2178
2461
  );
2179
2462
  scrollState = updatedOffset;
2180
2463
  }
2181
2464
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2182
2465
  const scrollAdjustPad = scrollAdjustPending - topPad;
2183
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2466
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2184
2467
  if (scroll + scrollLength > totalSize) {
2185
2468
  scroll = Math.max(0, totalSize - scrollLength);
2186
2469
  }
@@ -2188,11 +2471,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2188
2471
  set$(ctx, "debugRawScroll", scrollState);
2189
2472
  set$(ctx, "debugComputedScroll", scroll);
2190
2473
  }
2191
- const previousStickyIndex = state.activeStickyIndex;
2474
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2192
2475
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2193
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2194
- state.activeStickyIndex = nextActiveStickyIndex;
2195
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2476
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2477
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2478
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2479
+ }
2196
2480
  let scrollBufferTop = scrollBuffer;
2197
2481
  let scrollBufferBottom = scrollBuffer;
2198
2482
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2205,23 +2489,25 @@ function calculateItemsInView(ctx, state, params = {}) {
2205
2489
  const scrollTopBuffered = scroll - scrollBufferTop;
2206
2490
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2207
2491
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2208
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2492
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2209
2493
  const { top, bottom } = scrollForNextCalculateItemsInView;
2210
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2211
- if (state.initialAnchor) {
2212
- ensureInitialAnchor(ctx, state);
2494
+ if (top === null && bottom === null) {
2495
+ state.scrollForNextCalculateItemsInView = void 0;
2496
+ } else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2497
+ if (!IsNewArchitecture && state.initialAnchor) {
2498
+ ensureInitialAnchor(ctx);
2213
2499
  }
2214
2500
  return;
2215
2501
  }
2216
2502
  }
2217
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2503
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2218
2504
  if (dataChanged) {
2219
2505
  indexByKey.clear();
2220
2506
  idCache.length = 0;
2221
2507
  positions.clear();
2222
2508
  }
2223
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2224
- updateItemPositions(ctx, state, dataChanged, {
2509
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2510
+ updateItemPositions(ctx, dataChanged, {
2225
2511
  doMVCP,
2226
2512
  forceFullUpdate: !!forceFullItemPositions,
2227
2513
  scrollBottomBuffered,
@@ -2240,9 +2526,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2240
2526
  for (let i = loopStart; i >= 0; i--) {
2241
2527
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2242
2528
  const top = positions.get(id);
2243
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2529
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2244
2530
  const bottom = top + size;
2245
- if (bottom > scroll - scrollBuffer) {
2531
+ if (bottom > scroll - scrollBufferTop) {
2246
2532
  loopStart = i;
2247
2533
  } else {
2248
2534
  break;
@@ -2267,7 +2553,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2267
2553
  const dataLength = data.length;
2268
2554
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2269
2555
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2270
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2556
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2271
2557
  const top = positions.get(id);
2272
2558
  if (!foundEnd) {
2273
2559
  if (startNoBuffer === null && top + size > scroll) {
@@ -2279,7 +2565,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2279
2565
  if (startBuffered === null && top + size > scrollTopBuffered) {
2280
2566
  startBuffered = i;
2281
2567
  startBufferedId = id;
2282
- nextTop = top;
2568
+ if (scrollTopBuffered < 0) {
2569
+ nextTop = null;
2570
+ } else {
2571
+ nextTop = top;
2572
+ }
2283
2573
  }
2284
2574
  if (startNoBuffer !== null) {
2285
2575
  if (top <= scrollBottom) {
@@ -2287,7 +2577,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2287
2577
  }
2288
2578
  if (top <= scrollBottomBuffered) {
2289
2579
  endBuffered = i;
2290
- nextBottom = top + size;
2580
+ if (scrollBottomBuffered > totalSize) {
2581
+ nextBottom = null;
2582
+ } else {
2583
+ nextBottom = top + size;
2584
+ }
2291
2585
  } else {
2292
2586
  foundEnd = true;
2293
2587
  }
@@ -2309,12 +2603,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2309
2603
  startNoBuffer
2310
2604
  });
2311
2605
  if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
2312
- state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
2606
+ state.scrollForNextCalculateItemsInView = isNullOrUndefined(nextTop) && isNullOrUndefined(nextBottom) ? void 0 : {
2313
2607
  bottom: nextBottom,
2314
2608
  top: nextTop
2315
- } : void 0;
2609
+ };
2316
2610
  }
2317
- const numContainers = peek$(ctx, "numContainers");
2611
+ let numContainers = prevNumContainers;
2318
2612
  const pendingRemoval = [];
2319
2613
  if (dataChanged) {
2320
2614
  for (let i = 0; i < numContainers; i++) {
@@ -2325,37 +2619,46 @@ function calculateItemsInView(ctx, state, params = {}) {
2325
2619
  }
2326
2620
  }
2327
2621
  if (startBuffered !== null && endBuffered !== null) {
2328
- let numContainers2 = prevNumContainers;
2329
2622
  const needNewContainers = [];
2623
+ const needNewContainersSet = /* @__PURE__ */ new Set();
2330
2624
  for (let i = startBuffered; i <= endBuffered; i++) {
2331
2625
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2332
2626
  if (!containerItemKeys.has(id)) {
2627
+ needNewContainersSet.add(i);
2333
2628
  needNewContainers.push(i);
2334
2629
  }
2335
2630
  }
2631
+ if (alwaysRenderArr.length > 0) {
2632
+ for (const index of alwaysRenderArr) {
2633
+ if (index < 0 || index >= dataLength) continue;
2634
+ const id = (_i = idCache[index]) != null ? _i : getId(state, index);
2635
+ if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
2636
+ needNewContainersSet.add(index);
2637
+ needNewContainers.push(index);
2638
+ }
2639
+ }
2640
+ }
2336
2641
  if (stickyIndicesArr.length > 0) {
2337
2642
  handleStickyActivation(
2338
2643
  ctx,
2339
- state,
2340
2644
  stickyIndicesSet,
2341
2645
  stickyIndicesArr,
2342
2646
  currentStickyIdx,
2343
2647
  needNewContainers,
2648
+ needNewContainersSet,
2344
2649
  startBuffered,
2345
2650
  endBuffered
2346
2651
  );
2347
- } else {
2348
- state.activeStickyIndex = void 0;
2349
- set$(ctx, "activeStickyIndex", void 0);
2652
+ } else if (previousStickyIndex !== -1) {
2653
+ set$(ctx, "activeStickyIndex", -1);
2350
2654
  }
2351
2655
  if (needNewContainers.length > 0) {
2352
2656
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2353
2657
  const itemType = getItemType(data[i], i);
2354
- return itemType ? String(itemType) : "";
2658
+ return itemType !== void 0 ? String(itemType) : "";
2355
2659
  }) : void 0;
2356
2660
  const availableContainers = findAvailableContainers(
2357
2661
  ctx,
2358
- state,
2359
2662
  needNewContainers.length,
2360
2663
  startBuffered,
2361
2664
  endBuffered,
@@ -2366,7 +2669,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2366
2669
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2367
2670
  const i = needNewContainers[idx];
2368
2671
  const containerIndex = availableContainers[idx];
2369
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
2672
+ const id = (_j = idCache[i]) != null ? _j : getId(state, i);
2370
2673
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2371
2674
  if (oldKey && oldKey !== id) {
2372
2675
  containerItemKeys.delete(oldKey);
@@ -2376,30 +2679,58 @@ function calculateItemsInView(ctx, state, params = {}) {
2376
2679
  if (requiredItemTypes) {
2377
2680
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2378
2681
  }
2379
- containerItemKeys.add(id);
2380
- if (stickyIndicesSet.has(i)) {
2381
- set$(ctx, `containerSticky${containerIndex}`, true);
2682
+ containerItemKeys.set(id, containerIndex);
2683
+ const containerSticky = `containerSticky${containerIndex}`;
2684
+ const isSticky = stickyIndicesSet.has(i);
2685
+ const isAlwaysRender = alwaysRenderSet.has(i);
2686
+ if (isSticky) {
2687
+ set$(ctx, containerSticky, true);
2382
2688
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2383
2689
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2384
2690
  state.stickyContainerPool.add(containerIndex);
2385
2691
  } else {
2386
- set$(ctx, `containerSticky${containerIndex}`, false);
2387
- state.stickyContainerPool.delete(containerIndex);
2692
+ if (peek$(ctx, containerSticky)) {
2693
+ set$(ctx, containerSticky, false);
2694
+ set$(ctx, `containerStickyOffset${containerIndex}`, void 0);
2695
+ }
2696
+ if (isAlwaysRender) {
2697
+ state.stickyContainerPool.add(containerIndex);
2698
+ } else if (state.stickyContainerPool.has(containerIndex)) {
2699
+ state.stickyContainerPool.delete(containerIndex);
2700
+ }
2388
2701
  }
2389
- if (containerIndex >= numContainers2) {
2390
- numContainers2 = containerIndex + 1;
2702
+ if (containerIndex >= numContainers) {
2703
+ numContainers = containerIndex + 1;
2391
2704
  }
2392
2705
  }
2393
- if (numContainers2 !== prevNumContainers) {
2394
- set$(ctx, "numContainers", numContainers2);
2395
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2396
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2706
+ if (numContainers !== prevNumContainers) {
2707
+ set$(ctx, "numContainers", numContainers);
2708
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2709
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2710
+ }
2711
+ }
2712
+ }
2713
+ if (alwaysRenderArr.length > 0) {
2714
+ for (const index of alwaysRenderArr) {
2715
+ if (index < 0 || index >= dataLength) continue;
2716
+ const id = (_k = idCache[index]) != null ? _k : getId(state, index);
2717
+ const containerIndex = containerItemKeys.get(id);
2718
+ if (containerIndex !== void 0) {
2719
+ state.stickyContainerPool.add(containerIndex);
2397
2720
  }
2398
2721
  }
2399
2722
  }
2400
2723
  }
2401
- if (stickyIndicesArr.length > 0) {
2402
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2724
+ if (state.stickyContainerPool.size > 0) {
2725
+ handleStickyRecycling(
2726
+ ctx,
2727
+ stickyIndicesArr,
2728
+ scroll,
2729
+ scrollBuffer,
2730
+ currentStickyIdx,
2731
+ pendingRemoval,
2732
+ alwaysRenderSet
2733
+ );
2403
2734
  }
2404
2735
  let didChangePositions = false;
2405
2736
  for (let i = 0; i < numContainers; i++) {
@@ -2422,7 +2753,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2422
2753
  const itemIndex = indexByKey.get(itemKey);
2423
2754
  const item = data[itemIndex];
2424
2755
  if (item !== void 0) {
2425
- const id = (_j = idCache[itemIndex]) != null ? _j : getId(state, itemIndex);
2756
+ const id = (_l = idCache[itemIndex]) != null ? _l : getId(state, itemIndex);
2426
2757
  const positionValue = positions.get(id);
2427
2758
  if (positionValue === void 0) {
2428
2759
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
@@ -2451,7 +2782,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2451
2782
  }
2452
2783
  if (!queuedInitialLayout && endBuffered !== null) {
2453
2784
  if (checkAllSizesKnown(state)) {
2454
- setDidLayout(ctx, state);
2785
+ setDidLayout(ctx);
2455
2786
  }
2456
2787
  }
2457
2788
  if (viewabilityConfigCallbackPairs) {
@@ -2464,8 +2795,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2464
2795
  }
2465
2796
  }
2466
2797
  });
2467
- if (state.initialAnchor) {
2468
- ensureInitialAnchor(ctx, state);
2798
+ if (!IsNewArchitecture && state.initialAnchor) {
2799
+ ensureInitialAnchor(ctx);
2469
2800
  }
2470
2801
  }
2471
2802
 
@@ -2490,19 +2821,22 @@ function checkActualChange(state, dataProp, previousData) {
2490
2821
  }
2491
2822
 
2492
2823
  // src/core/doMaintainScrollAtEnd.ts
2493
- function doMaintainScrollAtEnd(ctx, state, animated) {
2824
+ function doMaintainScrollAtEnd(ctx, animated) {
2825
+ const state = ctx.state;
2494
2826
  const {
2827
+ didContainersLayout,
2828
+ isAtEnd,
2495
2829
  refScroller,
2496
2830
  props: { maintainScrollAtEnd }
2497
2831
  } = state;
2498
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2832
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2499
2833
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2500
2834
  if (paddingTop > 0) {
2501
2835
  state.scroll = 0;
2502
2836
  }
2503
2837
  requestAnimationFrame(() => {
2504
2838
  var _a3;
2505
- if (state == null ? void 0 : state.isAtEnd) {
2839
+ if (state.isAtEnd) {
2506
2840
  state.maintainingScrollAtEnd = true;
2507
2841
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2508
2842
  animated
@@ -2573,28 +2907,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2573
2907
  }
2574
2908
 
2575
2909
  // src/core/checkResetContainers.ts
2576
- function checkResetContainers(ctx, state, dataProp) {
2910
+ function checkResetContainers(ctx, dataProp) {
2911
+ const state = ctx.state;
2577
2912
  const { previousData } = state;
2578
2913
  if (previousData) {
2579
2914
  updateAveragesOnDataChange(state, previousData, dataProp);
2580
2915
  }
2581
2916
  const { maintainScrollAtEnd } = state.props;
2582
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2917
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2583
2918
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2584
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2919
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2585
2920
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2586
2921
  state.isEndReached = false;
2587
2922
  }
2588
2923
  if (!didMaintainScrollAtEnd) {
2589
2924
  checkAtTop(state);
2590
- checkAtBottom(ctx, state);
2925
+ checkAtBottom(ctx);
2591
2926
  }
2592
2927
  delete state.previousData;
2593
2928
  }
2594
2929
 
2595
2930
  // src/core/doInitialAllocateContainers.ts
2596
- function doInitialAllocateContainers(ctx, state) {
2931
+ function doInitialAllocateContainers(ctx) {
2597
2932
  var _a3, _b, _c;
2933
+ const state = ctx.state;
2598
2934
  const {
2599
2935
  scrollLength,
2600
2936
  props: {
@@ -2615,8 +2951,10 @@ function doInitialAllocateContainers(ctx, state) {
2615
2951
  const num = Math.min(20, data.length);
2616
2952
  for (let i = 0; i < num; i++) {
2617
2953
  const item = data[i];
2618
- const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2619
- totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2954
+ if (item !== void 0) {
2955
+ const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
2956
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(item, i, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(item, i, itemType)) != null ? _c : estimatedItemSize;
2957
+ }
2620
2958
  }
2621
2959
  averageItemSize = totalSize / num;
2622
2960
  } else {
@@ -2632,10 +2970,10 @@ function doInitialAllocateContainers(ctx, state) {
2632
2970
  if (!IsNewArchitecture || state.lastLayout) {
2633
2971
  if (state.initialScroll) {
2634
2972
  requestAnimationFrame(() => {
2635
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2973
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2636
2974
  });
2637
2975
  } else {
2638
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2976
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2639
2977
  }
2640
2978
  }
2641
2979
  return true;
@@ -2643,7 +2981,8 @@ function doInitialAllocateContainers(ctx, state) {
2643
2981
  }
2644
2982
 
2645
2983
  // src/core/handleLayout.ts
2646
- function handleLayout(ctx, state, layout, setCanRender) {
2984
+ function handleLayout(ctx, layout, setCanRender) {
2985
+ const state = ctx.state;
2647
2986
  const { maintainScrollAtEnd } = state.props;
2648
2987
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2649
2988
  const previousLength = state.scrollLength;
@@ -2659,19 +2998,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2659
2998
  state.lastBatchingAction = Date.now();
2660
2999
  state.scrollForNextCalculateItemsInView = void 0;
2661
3000
  if (scrollLength > 0) {
2662
- doInitialAllocateContainers(ctx, state);
3001
+ doInitialAllocateContainers(ctx);
2663
3002
  }
2664
3003
  if (needsCalculate) {
2665
- calculateItemsInView(ctx, state, { doMVCP: true });
3004
+ calculateItemsInView(ctx, { doMVCP: true });
2666
3005
  }
2667
3006
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2668
3007
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2669
3008
  }
2670
3009
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2671
- doMaintainScrollAtEnd(ctx, state, false);
3010
+ doMaintainScrollAtEnd(ctx, false);
2672
3011
  }
2673
- updateAlignItemsPaddingTop(ctx, state);
2674
- checkAtBottom(ctx, state);
3012
+ updateAlignItemsPaddingTop(ctx);
3013
+ checkAtBottom(ctx);
2675
3014
  checkAtTop(state);
2676
3015
  if (state) {
2677
3016
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2687,8 +3026,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2687
3026
  }
2688
3027
 
2689
3028
  // src/core/onScroll.ts
2690
- function onScroll(ctx, state, event) {
3029
+ function onScroll(ctx, event) {
2691
3030
  var _a3, _b, _c;
3031
+ const state = ctx.state;
2692
3032
  const {
2693
3033
  scrollProcessingEnabled,
2694
3034
  props: { onScroll: onScrollProp }
@@ -2699,9 +3039,25 @@ function onScroll(ctx, state, event) {
2699
3039
  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) {
2700
3040
  return;
2701
3041
  }
2702
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3042
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3043
+ if (state.scrollingTo) {
3044
+ const maxOffset = clampScrollOffset(ctx, newScroll);
3045
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3046
+ newScroll = maxOffset;
3047
+ scrollTo(ctx, {
3048
+ forceScroll: true,
3049
+ isInitialScroll: true,
3050
+ noScrollingTo: true,
3051
+ offset: newScroll
3052
+ });
3053
+ return;
3054
+ }
3055
+ }
2703
3056
  state.scrollPending = newScroll;
2704
- updateScroll(ctx, state, newScroll);
3057
+ updateScroll(ctx, newScroll);
3058
+ if (state.scrollingTo) {
3059
+ checkFinishedScroll(ctx);
3060
+ }
2705
3061
  onScrollProp == null ? void 0 : onScrollProp(event);
2706
3062
  }
2707
3063
 
@@ -2710,51 +3066,58 @@ var ScrollAdjustHandler = class {
2710
3066
  constructor(ctx) {
2711
3067
  this.appliedAdjust = 0;
2712
3068
  this.pendingAdjust = 0;
2713
- this.mounted = false;
2714
- this.context = ctx;
2715
- if (Platform2.OS === "web") {
2716
- const commitPendingAdjust = () => {
2717
- const state = this.context.internalState;
2718
- const pending = this.pendingAdjust;
2719
- if (pending !== 0) {
2720
- this.pendingAdjust = 0;
2721
- this.appliedAdjust += pending;
2722
- state.scroll += pending;
2723
- state.scrollForNextCalculateItemsInView = void 0;
2724
- set$(this.context, "scrollAdjustPending", 0);
2725
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2726
- calculateItemsInView(this.context, this.context.internalState);
2727
- }
2728
- };
2729
- listen$(this.context, "scrollingTo", (value) => {
2730
- if (value === void 0) {
2731
- commitPendingAdjust();
2732
- }
2733
- });
2734
- }
3069
+ this.ctx = ctx;
2735
3070
  }
2736
3071
  requestAdjust(add) {
2737
- const scrollingTo = peek$(this.context, "scrollingTo");
2738
- if (Platform2.OS === "web" && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
3072
+ const scrollingTo = this.ctx.state.scrollingTo;
3073
+ if (PlatformAdjustBreaksScroll && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2739
3074
  this.pendingAdjust += add;
2740
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
3075
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2741
3076
  } else {
2742
3077
  this.appliedAdjust += add;
2743
- set$(this.context, "scrollAdjust", this.appliedAdjust);
3078
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3079
+ }
3080
+ if (this.ctx.state.scrollingTo) {
3081
+ checkFinishedScroll(this.ctx);
2744
3082
  }
2745
- }
2746
- setMounted() {
2747
- this.mounted = true;
2748
3083
  }
2749
3084
  getAdjust() {
2750
3085
  return this.appliedAdjust;
2751
3086
  }
3087
+ commitPendingAdjust(scrollTarget) {
3088
+ if (PlatformAdjustBreaksScroll) {
3089
+ const state = this.ctx.state;
3090
+ const pending = this.pendingAdjust;
3091
+ this.pendingAdjust = 0;
3092
+ if (pending !== 0) {
3093
+ let targetScroll;
3094
+ if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3095
+ const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3096
+ targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3097
+ targetScroll = clampScrollOffset(this.ctx, targetScroll);
3098
+ } else {
3099
+ targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3100
+ }
3101
+ const adjustment = targetScroll - state.scroll;
3102
+ if (Math.abs(adjustment) > 0.1 || Math.abs(pending) > 0.1) {
3103
+ this.appliedAdjust += adjustment;
3104
+ state.scroll = targetScroll;
3105
+ state.scrollForNextCalculateItemsInView = void 0;
3106
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3107
+ }
3108
+ set$(this.ctx, "scrollAdjustPending", 0);
3109
+ calculateItemsInView(this.ctx);
3110
+ }
3111
+ }
3112
+ }
2752
3113
  };
2753
3114
 
2754
3115
  // src/core/updateItemSize.ts
2755
- function updateItemSize(ctx, state, itemKey, sizeObj) {
3116
+ function updateItemSize(ctx, itemKey, sizeObj) {
2756
3117
  var _a3;
3118
+ const state = ctx.state;
2757
3119
  const {
3120
+ didContainersLayout,
2758
3121
  sizesKnown,
2759
3122
  props: {
2760
3123
  getFixedItemSize,
@@ -2777,31 +3140,24 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2777
3140
  return;
2778
3141
  }
2779
3142
  const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
2780
- const size2 = getFixedItemSize(index, itemData, type);
3143
+ const size2 = getFixedItemSize(itemData, index, type);
2781
3144
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
2782
3145
  return;
2783
3146
  }
2784
3147
  }
2785
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2786
- let needsRecalculate = !containersDidLayout;
3148
+ let needsRecalculate = !didContainersLayout;
2787
3149
  let shouldMaintainScrollAtEnd = false;
2788
3150
  let minIndexSizeChanged;
2789
3151
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2790
3152
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2791
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3153
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
2792
3154
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2793
3155
  if (diff !== 0) {
2794
3156
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2795
3157
  const { startBuffered, endBuffered } = state;
2796
3158
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2797
- if (!needsRecalculate) {
2798
- const numContainers = ctx.values.get("numContainers");
2799
- for (let i = 0; i < numContainers; i++) {
2800
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2801
- needsRecalculate = true;
2802
- break;
2803
- }
2804
- }
3159
+ if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
3160
+ needsRecalculate = true;
2805
3161
  }
2806
3162
  if (state.needsOtherAxisSize) {
2807
3163
  const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
@@ -2837,22 +3193,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2837
3193
  if (!cur || maxOtherAxisSize > cur) {
2838
3194
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
2839
3195
  }
2840
- if (containersDidLayout || checkAllSizesKnown(state)) {
3196
+ if (didContainersLayout || checkAllSizesKnown(state)) {
2841
3197
  if (needsRecalculate) {
2842
3198
  state.scrollForNextCalculateItemsInView = void 0;
2843
- calculateItemsInView(ctx, state, { doMVCP: true });
3199
+ calculateItemsInView(ctx, { doMVCP: true });
2844
3200
  }
2845
3201
  if (shouldMaintainScrollAtEnd) {
2846
3202
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2847
- doMaintainScrollAtEnd(ctx, state, false);
3203
+ doMaintainScrollAtEnd(ctx, false);
2848
3204
  }
2849
3205
  }
2850
3206
  }
2851
3207
  }
2852
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3208
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
2853
3209
  var _a3;
3210
+ const state = ctx.state;
2854
3211
  const {
2855
- sizes,
2856
3212
  indexByKey,
2857
3213
  sizesKnown,
2858
3214
  averageSizes,
@@ -2860,9 +3216,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2860
3216
  } = state;
2861
3217
  if (!data) return 0;
2862
3218
  const index = indexByKey.get(itemKey);
2863
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3219
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
2864
3220
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2865
3221
  const size = Platform2.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
3222
+ const prevSizeKnown = sizesKnown.get(itemKey);
2866
3223
  sizesKnown.set(itemKey, size);
2867
3224
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2868
3225
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -2870,15 +3227,25 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2870
3227
  if (!averages) {
2871
3228
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
2872
3229
  }
2873
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2874
- averages.num++;
3230
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3231
+ averages.avg += (size - prevSizeKnown) / averages.num;
3232
+ } else {
3233
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3234
+ averages.num++;
3235
+ }
2875
3236
  }
2876
3237
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2877
- setSize(ctx, state, itemKey, size);
3238
+ setSize(ctx, itemKey, size);
2878
3239
  return size - prevSize;
2879
3240
  }
2880
3241
  return 0;
2881
3242
  }
3243
+ function useWrapIfItem(fn) {
3244
+ return React2.useMemo(
3245
+ () => fn ? (arg1, arg2, arg3) => arg1 !== void 0 && arg2 !== void 0 ? fn(arg1, arg2, arg3) : void 0 : void 0,
3246
+ [fn]
3247
+ );
3248
+ }
2882
3249
  var useCombinedRef = (...refs) => {
2883
3250
  const callback = React2.useCallback((element) => {
2884
3251
  for (const ref of refs) {
@@ -2940,14 +3307,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
2940
3307
  }
2941
3308
 
2942
3309
  // src/utils/createImperativeHandle.ts
2943
- function createImperativeHandle(ctx, state) {
3310
+ function createImperativeHandle(ctx) {
3311
+ const state = ctx.state;
2944
3312
  const scrollIndexIntoView = (options) => {
2945
3313
  if (state) {
2946
3314
  const { index, ...rest } = options;
2947
3315
  const { startNoBuffer, endNoBuffer } = state;
2948
3316
  if (index < startNoBuffer || index > endNoBuffer) {
2949
3317
  const viewPosition = index < startNoBuffer ? 0 : 1;
2950
- scrollToIndex(ctx, state, {
3318
+ scrollToIndex(ctx, {
2951
3319
  ...rest,
2952
3320
  index,
2953
3321
  viewPosition
@@ -2962,7 +3330,7 @@ function createImperativeHandle(ctx, state) {
2962
3330
  getScrollableNode: () => refScroller.current.getScrollableNode(),
2963
3331
  getScrollResponder: () => refScroller.current.getScrollResponder(),
2964
3332
  getState: () => ({
2965
- activeStickyIndex: state.activeStickyIndex,
3333
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
2966
3334
  contentLength: state.totalSize,
2967
3335
  data: state.props.data,
2968
3336
  elementAtIndex: (index) => {
@@ -2973,6 +3341,8 @@ function createImperativeHandle(ctx, state) {
2973
3341
  endBuffered: state.endBuffered,
2974
3342
  isAtEnd: state.isAtEnd,
2975
3343
  isAtStart: state.isAtStart,
3344
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3345
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
2976
3346
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
2977
3347
  positions: state.positions,
2978
3348
  scroll: state.scroll,
@@ -2997,23 +3367,23 @@ function createImperativeHandle(ctx, state) {
2997
3367
  if (index !== -1) {
2998
3368
  const paddingBottom = stylePaddingBottom || 0;
2999
3369
  const footerSize = peek$(ctx, "footerSize") || 0;
3000
- scrollToIndex(ctx, state, {
3370
+ scrollToIndex(ctx, {
3371
+ ...options,
3001
3372
  index,
3002
3373
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3003
- viewPosition: 1,
3004
- ...options
3374
+ viewPosition: 1
3005
3375
  });
3006
3376
  }
3007
3377
  },
3008
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3378
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
3009
3379
  scrollToItem: ({ item, ...props }) => {
3010
3380
  const data = state.props.data;
3011
3381
  const index = data.indexOf(item);
3012
3382
  if (index !== -1) {
3013
- scrollToIndex(ctx, state, { index, ...props });
3383
+ scrollToIndex(ctx, { index, ...props });
3014
3384
  }
3015
3385
  },
3016
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3386
+ scrollToOffset: (params) => scrollTo(ctx, params),
3017
3387
  setScrollProcessingEnabled: (enabled) => {
3018
3388
  state.scrollProcessingEnabled = enabled;
3019
3389
  },
@@ -3023,8 +3393,57 @@ function createImperativeHandle(ctx, state) {
3023
3393
  }
3024
3394
  };
3025
3395
  }
3026
- function getRenderedItem(ctx, state, key) {
3396
+
3397
+ // src/utils/getAlwaysRenderIndices.ts
3398
+ var sortAsc = (a, b) => a - b;
3399
+ var toCount = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
3400
+ var addIndex = (result, dataLength, index) => {
3401
+ if (index >= 0 && index < dataLength) {
3402
+ result.add(index);
3403
+ }
3404
+ };
3405
+ function getAlwaysRenderIndices(config, data, keyExtractor) {
3406
+ var _a3, _b;
3407
+ if (!config || data.length === 0) {
3408
+ return [];
3409
+ }
3410
+ const result = /* @__PURE__ */ new Set();
3411
+ const dataLength = data.length;
3412
+ const topCount = toCount(config.top);
3413
+ if (topCount > 0) {
3414
+ for (let i = 0; i < Math.min(topCount, dataLength); i++) {
3415
+ addIndex(result, dataLength, i);
3416
+ }
3417
+ }
3418
+ const bottomCount = toCount(config.bottom);
3419
+ if (bottomCount > 0) {
3420
+ for (let i = Math.max(0, dataLength - bottomCount); i < dataLength; i++) {
3421
+ addIndex(result, dataLength, i);
3422
+ }
3423
+ }
3424
+ if ((_a3 = config.indices) == null ? void 0 : _a3.length) {
3425
+ for (const index of config.indices) {
3426
+ if (!Number.isFinite(index)) continue;
3427
+ addIndex(result, dataLength, Math.floor(index));
3428
+ }
3429
+ }
3430
+ if ((_b = config.keys) == null ? void 0 : _b.length) {
3431
+ const keys = new Set(config.keys);
3432
+ for (let i = 0; i < dataLength && keys.size > 0; i++) {
3433
+ const key = keyExtractor(data[i], i);
3434
+ if (keys.has(key)) {
3435
+ addIndex(result, dataLength, i);
3436
+ keys.delete(key);
3437
+ }
3438
+ }
3439
+ }
3440
+ const indices = Array.from(result);
3441
+ indices.sort(sortAsc);
3442
+ return indices;
3443
+ }
3444
+ function getRenderedItem(ctx, key) {
3027
3445
  var _a3;
3446
+ const state = ctx.state;
3028
3447
  if (!state) {
3029
3448
  return null;
3030
3449
  }
@@ -3051,6 +3470,25 @@ function getRenderedItem(ctx, state, key) {
3051
3470
  }
3052
3471
  return { index, item: data[index], renderedItem };
3053
3472
  }
3473
+
3474
+ // src/utils/normalizeMaintainVisibleContentPosition.ts
3475
+ function normalizeMaintainVisibleContentPosition(value) {
3476
+ var _a3, _b;
3477
+ if (value === true) {
3478
+ return { data: true, size: true };
3479
+ }
3480
+ if (value && typeof value === "object") {
3481
+ return {
3482
+ data: (_a3 = value.data) != null ? _a3 : false,
3483
+ size: (_b = value.size) != null ? _b : true,
3484
+ shouldRestorePosition: value.shouldRestorePosition
3485
+ };
3486
+ }
3487
+ if (value === false) {
3488
+ return { data: false, size: false };
3489
+ }
3490
+ return { data: false, size: true };
3491
+ }
3054
3492
  function useThrottleDebounce(mode) {
3055
3493
  const timeoutRef = React2.useRef(null);
3056
3494
  const lastCallTimeRef = React2.useRef(0);
@@ -3101,6 +3539,7 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3101
3539
  var DEFAULT_DRAW_DISTANCE = 250;
3102
3540
  var DEFAULT_ITEM_SIZE = 100;
3103
3541
  var LegendList = typedMemo(
3542
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3104
3543
  typedForwardRef(function LegendList2(props, forwardedRef) {
3105
3544
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3106
3545
  const isChildrenMode = children !== void 0 && dataProp === void 0;
@@ -3118,15 +3557,16 @@ var LegendList = typedMemo(
3118
3557
  })
3119
3558
  );
3120
3559
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3121
- var _a3, _b;
3560
+ var _a3, _b, _c, _d;
3122
3561
  const {
3123
3562
  alignItemsAtEnd = false,
3563
+ alwaysRender,
3124
3564
  columnWrapperStyle,
3125
3565
  contentContainerStyle: contentContainerStyleProp,
3566
+ contentInset,
3126
3567
  data: dataProp = [],
3127
3568
  dataVersion,
3128
3569
  drawDistance = 250,
3129
- enableAverages = true,
3130
3570
  estimatedItemSize: estimatedItemSizeProp,
3131
3571
  estimatedListSize,
3132
3572
  extraData,
@@ -3144,11 +3584,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3144
3584
  ListHeaderComponent,
3145
3585
  maintainScrollAtEnd = false,
3146
3586
  maintainScrollAtEndThreshold = 0.1,
3147
- maintainVisibleContentPosition = false,
3587
+ maintainVisibleContentPosition: maintainVisibleContentPositionProp,
3148
3588
  numColumns: numColumnsProp = 1,
3149
3589
  onEndReached,
3150
3590
  onEndReachedThreshold = 0.5,
3151
3591
  onItemSizeChanged,
3592
+ onMetricsChange,
3152
3593
  onLayout: onLayoutProp,
3153
3594
  onLoad,
3154
3595
  onMomentumScrollEnd,
@@ -3168,20 +3609,26 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3168
3609
  snapToIndices,
3169
3610
  stickyHeaderIndices: stickyHeaderIndicesProp,
3170
3611
  stickyIndices: stickyIndicesDeprecated,
3612
+ // TODOV3: Remove from v3 release
3171
3613
  style: styleProp,
3172
3614
  suggestEstimatedItemSize,
3173
3615
  viewabilityConfig,
3174
3616
  viewabilityConfigCallbackPairs,
3175
3617
  waitForInitialLayout = true,
3618
+ stickyHeaderConfig,
3176
3619
  ...rest
3177
3620
  } = props;
3621
+ const animatedPropsInternal = props.animatedPropsInternal;
3178
3622
  const { childrenMode } = rest;
3179
3623
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3180
3624
  const style = { ...StyleSheet.flatten(styleProp) };
3181
3625
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
3182
3626
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
3627
+ const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
3628
+ maintainVisibleContentPositionProp
3629
+ );
3183
3630
  const [renderNum, setRenderNum] = React2.useState(0);
3184
- 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;
3631
+ 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;
3185
3632
  const [canRender, setCanRender] = React2__namespace.useState(!IsNewArchitecture);
3186
3633
  const ctx = useStateContext();
3187
3634
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
@@ -3191,6 +3638,18 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3191
3638
  const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
3192
3639
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
3193
3640
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
3641
+ const alwaysRenderIndices = React2.useMemo(() => {
3642
+ const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor);
3643
+ return { arr: indices, set: new Set(indices) };
3644
+ }, [
3645
+ alwaysRender == null ? void 0 : alwaysRender.top,
3646
+ alwaysRender == null ? void 0 : alwaysRender.bottom,
3647
+ (_a3 = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _a3.join(","),
3648
+ (_b = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _b.join(","),
3649
+ dataProp,
3650
+ dataVersion,
3651
+ keyExtractor
3652
+ ]);
3194
3653
  if (IS_DEV && stickyIndicesDeprecated && !stickyHeaderIndicesProp) {
3195
3654
  warnDevOnce(
3196
3655
  "stickyIndices",
@@ -3199,13 +3658,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3199
3658
  }
3200
3659
  const refState = React2.useRef();
3201
3660
  if (!refState.current) {
3202
- if (!ctx.internalState) {
3661
+ if (!ctx.state) {
3203
3662
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : getWindowSize())[horizontal ? "width" : "height"];
3204
- ctx.internalState = {
3205
- activeStickyIndex: void 0,
3663
+ ctx.state = {
3664
+ activeStickyIndex: -1,
3206
3665
  averageSizes: {},
3207
3666
  columns: /* @__PURE__ */ new Map(),
3208
- containerItemKeys: /* @__PURE__ */ new Set(),
3667
+ containerItemKeys: /* @__PURE__ */ new Map(),
3209
3668
  containerItemTypes: /* @__PURE__ */ new Map(),
3210
3669
  dataChangeNeedsScrollUpdate: false,
3211
3670
  didColumnsChange: false,
@@ -3222,17 +3681,18 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3222
3681
  attempts: 0,
3223
3682
  index: initialScrollProp.index,
3224
3683
  settledTicks: 0,
3225
- viewOffset: (_a3 = initialScrollProp.viewOffset) != null ? _a3 : 0,
3684
+ viewOffset: (_c = initialScrollProp.viewOffset) != null ? _c : 0,
3226
3685
  viewPosition: initialScrollProp.viewPosition
3227
3686
  } : void 0,
3228
3687
  initialScroll: initialScrollProp,
3229
3688
  isAtEnd: false,
3230
3689
  isAtStart: false,
3231
- isEndReached: false,
3690
+ isEndReached: null,
3232
3691
  isFirst: true,
3233
- isStartReached: false,
3692
+ isStartReached: null,
3234
3693
  lastBatchingAction: Date.now(),
3235
3694
  lastLayout: void 0,
3695
+ lastScrollDelta: 0,
3236
3696
  loadStartTime: Date.now(),
3237
3697
  minIndexSizeChanged: 0,
3238
3698
  nativeMarginTop: 0,
@@ -3262,12 +3722,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3262
3722
  totalSize: 0,
3263
3723
  viewabilityConfigCallbackPairs: void 0
3264
3724
  };
3265
- const internalState = ctx.internalState;
3266
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3267
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3725
+ const internalState = ctx.state;
3726
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3727
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
3268
3728
  set$(ctx, "extraData", extraData);
3269
3729
  }
3270
- refState.current = ctx.internalState;
3730
+ refState.current = ctx.state;
3271
3731
  }
3272
3732
  const state = refState.current;
3273
3733
  const isFirstLocal = state.isFirst;
@@ -3281,20 +3741,24 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3281
3741
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3282
3742
  state.props = {
3283
3743
  alignItemsAtEnd,
3744
+ alwaysRender,
3745
+ alwaysRenderIndicesArr: alwaysRenderIndices.arr,
3746
+ alwaysRenderIndicesSet: alwaysRenderIndices.set,
3747
+ animatedProps: animatedPropsInternal,
3748
+ contentInset,
3284
3749
  data: dataProp,
3285
3750
  dataVersion,
3286
- enableAverages,
3287
3751
  estimatedItemSize,
3288
- getEstimatedItemSize,
3289
- getFixedItemSize,
3290
- getItemType,
3752
+ getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3753
+ getFixedItemSize: useWrapIfItem(getFixedItemSize),
3754
+ getItemType: useWrapIfItem(getItemType),
3291
3755
  horizontal: !!horizontal,
3292
3756
  initialContainerPoolRatio,
3293
3757
  itemsAreEqual,
3294
- keyExtractor,
3758
+ keyExtractor: useWrapIfItem(keyExtractor),
3295
3759
  maintainScrollAtEnd,
3296
3760
  maintainScrollAtEndThreshold,
3297
- maintainVisibleContentPosition,
3761
+ maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
3298
3762
  numColumns: numColumnsProp,
3299
3763
  onEndReached,
3300
3764
  onEndReachedThreshold,
@@ -3326,57 +3790,57 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3326
3790
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3327
3791
  set$(ctx, "numColumns", numColumnsProp);
3328
3792
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3329
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3793
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3330
3794
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3331
3795
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3332
- if (paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3796
+ if (maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3333
3797
  if (state.scroll < 0) {
3334
3798
  paddingDiff += state.scroll;
3335
3799
  }
3336
- requestAdjust(ctx, state, paddingDiff);
3800
+ requestAdjust(ctx, paddingDiff);
3337
3801
  }
3338
3802
  };
3339
3803
  if (isFirstLocal) {
3340
3804
  initializeStateVars();
3341
3805
  updateItemPositions(
3342
3806
  ctx,
3343
- state,
3344
3807
  /*dataChanged*/
3345
3808
  true
3346
3809
  );
3347
3810
  }
3348
3811
  const initialContentOffset = React2.useMemo(() => {
3349
- var _a4, _b2;
3350
- const { initialScroll } = refState.current;
3351
- if (!initialScroll) {
3812
+ var _a4;
3813
+ let value;
3814
+ const { initialScroll, initialAnchor } = refState.current;
3815
+ if (initialScroll) {
3816
+ if (!IsNewArchitecture && initialScroll.index !== void 0 && (!initialAnchor || (initialAnchor == null ? void 0 : initialAnchor.index) !== initialScroll.index)) {
3817
+ refState.current.initialAnchor = {
3818
+ attempts: 0,
3819
+ index: initialScroll.index,
3820
+ settledTicks: 0,
3821
+ viewOffset: (_a4 = initialScroll.viewOffset) != null ? _a4 : 0,
3822
+ viewPosition: initialScroll.viewPosition
3823
+ };
3824
+ }
3825
+ if (initialScroll.contentOffset !== void 0) {
3826
+ value = initialScroll.contentOffset;
3827
+ } else {
3828
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3829
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3830
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3831
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3832
+ refState.current.initialScroll = updatedInitialScroll;
3833
+ state.initialScroll = updatedInitialScroll;
3834
+ value = clampedOffset;
3835
+ }
3836
+ } else {
3352
3837
  refState.current.initialAnchor = void 0;
3353
- return 0;
3354
- }
3355
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3356
- refState.current.initialAnchor = {
3357
- attempts: 0,
3358
- index: initialScroll.index,
3359
- settledTicks: 0,
3360
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3361
- viewPosition: initialScroll.viewPosition
3362
- };
3838
+ value = 0;
3839
+ }
3840
+ if (!value) {
3841
+ setInitialRenderState(ctx, { didInitialScroll: true });
3363
3842
  }
3364
- if (initialScroll.contentOffset !== void 0) {
3365
- return initialScroll.contentOffset;
3366
- }
3367
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3368
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3369
- let clampedOffset = resolvedOffset;
3370
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3371
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3372
- clampedOffset = Math.min(clampedOffset, maxOffset);
3373
- }
3374
- clampedOffset = Math.max(0, clampedOffset);
3375
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3376
- refState.current.initialScroll = updatedInitialScroll;
3377
- state.initialScroll = updatedInitialScroll;
3378
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3379
- return clampedOffset;
3843
+ return value;
3380
3844
  }, [renderNum]);
3381
3845
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3382
3846
  refState.current.lastBatchingAction = Date.now();
@@ -3406,12 +3870,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3406
3870
  }
3407
3871
  }, []);
3408
3872
  const doInitialScroll = React2.useCallback(() => {
3409
- var _a4;
3410
- const initialScroll = state.initialScroll;
3411
- if (initialScroll) {
3412
- scrollTo(ctx, state, {
3873
+ const { initialScroll, didFinishInitialScroll, queuedInitialLayout, scrollingTo } = state;
3874
+ if (initialScroll && !queuedInitialLayout && !didFinishInitialScroll && !scrollingTo) {
3875
+ scrollTo(ctx, {
3413
3876
  animated: false,
3414
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3877
+ index: initialScroll == null ? void 0 : initialScroll.index,
3415
3878
  isInitialScroll: true,
3416
3879
  offset: initialContentOffset,
3417
3880
  precomputedWithViewOffset: true
@@ -3420,7 +3883,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3420
3883
  }, [initialContentOffset]);
3421
3884
  const onLayoutChange = React2.useCallback((layout) => {
3422
3885
  doInitialScroll();
3423
- handleLayout(ctx, state, layout, setCanRender);
3886
+ handleLayout(ctx, layout, setCanRender);
3424
3887
  }, []);
3425
3888
  const { onLayout } = useOnLayoutSync({
3426
3889
  onLayoutChange,
@@ -3430,7 +3893,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3430
3893
  });
3431
3894
  React2.useLayoutEffect(() => {
3432
3895
  if (snapToIndices) {
3433
- updateSnapToOffsets(ctx, state);
3896
+ updateSnapToOffsets(ctx);
3434
3897
  }
3435
3898
  }, [snapToIndices]);
3436
3899
  React2.useLayoutEffect(() => {
@@ -3440,9 +3903,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3440
3903
  isFirst,
3441
3904
  props: { data }
3442
3905
  } = state;
3443
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3906
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3444
3907
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3445
- checkResetContainers(ctx, state, data);
3908
+ checkResetContainers(ctx, data);
3446
3909
  }
3447
3910
  state.didColumnsChange = false;
3448
3911
  state.didDataChange = false;
@@ -3458,6 +3921,34 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3458
3921
  stylePaddingBottomState,
3459
3922
  stylePaddingTopState
3460
3923
  ]);
3924
+ React2.useEffect(() => {
3925
+ if (!onMetricsChange) {
3926
+ return;
3927
+ }
3928
+ let lastMetrics;
3929
+ const emitMetrics = () => {
3930
+ const metrics = {
3931
+ alignItemsAtEndPadding: peek$(ctx, "alignItemsPaddingTop") || 0,
3932
+ footerSize: peek$(ctx, "footerSize") || 0,
3933
+ headerSize: peek$(ctx, "headerSize") || 0
3934
+ };
3935
+ if (!lastMetrics || metrics.alignItemsAtEndPadding !== lastMetrics.alignItemsAtEndPadding || metrics.headerSize !== lastMetrics.headerSize || metrics.footerSize !== lastMetrics.footerSize) {
3936
+ lastMetrics = metrics;
3937
+ onMetricsChange(metrics);
3938
+ }
3939
+ };
3940
+ emitMetrics();
3941
+ const unsubscribe = [
3942
+ listen$(ctx, "alignItemsPaddingTop", emitMetrics),
3943
+ listen$(ctx, "headerSize", emitMetrics),
3944
+ listen$(ctx, "footerSize", emitMetrics)
3945
+ ];
3946
+ return () => {
3947
+ for (const unsub of unsubscribe) {
3948
+ unsub();
3949
+ }
3950
+ };
3951
+ }, [ctx, onMetricsChange]);
3461
3952
  React2.useEffect(() => {
3462
3953
  const viewability = setupViewability({
3463
3954
  onViewableItemsChanged,
@@ -3469,18 +3960,24 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3469
3960
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3470
3961
  if (!IsNewArchitecture) {
3471
3962
  useInit(() => {
3472
- doInitialAllocateContainers(ctx, state);
3963
+ doInitialAllocateContainers(ctx);
3473
3964
  });
3474
3965
  }
3475
- React2.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3966
+ React2.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3476
3967
  if (Platform2.OS === "web") {
3477
3968
  React2.useEffect(doInitialScroll, []);
3478
3969
  }
3479
3970
  const fns = React2.useMemo(
3480
3971
  () => ({
3481
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3482
- onScroll: (event) => onScroll(ctx, state, event),
3483
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3972
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
3973
+ onMomentumScrollEnd: (event) => {
3974
+ checkFinishedScrollFallback(ctx);
3975
+ if (onMomentumScrollEnd) {
3976
+ onMomentumScrollEnd(event);
3977
+ }
3978
+ },
3979
+ onScroll: (event) => onScroll(ctx, event),
3980
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3484
3981
  }),
3485
3982
  []
3486
3983
  );
@@ -3492,28 +3989,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3492
3989
  alignItemsAtEnd,
3493
3990
  canRender,
3494
3991
  contentContainerStyle,
3992
+ contentInset,
3495
3993
  getRenderedItem: fns.getRenderedItem,
3496
3994
  horizontal,
3497
3995
  initialContentOffset,
3498
3996
  ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
3499
3997
  ListHeaderComponent,
3500
- maintainVisibleContentPosition,
3501
3998
  onLayout,
3502
3999
  onLayoutHeader,
3503
- onMomentumScrollEnd: (event) => {
3504
- if (IsNewArchitecture) {
3505
- requestAnimationFrame(() => {
3506
- finishScrollTo(ctx, refState.current);
3507
- });
3508
- } else {
3509
- setTimeout(() => {
3510
- finishScrollTo(ctx, refState.current);
3511
- }, 1e3);
3512
- }
3513
- if (onMomentumScrollEnd) {
3514
- onMomentumScrollEnd(event);
3515
- }
3516
- },
4000
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3517
4001
  onScroll: onScrollHandler,
3518
4002
  recycleItems,
3519
4003
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2__namespace.cloneElement(refreshControl, {
@@ -3527,9 +4011,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3527
4011
  }
3528
4012
  ),
3529
4013
  refScrollView: combinedRef,
3530
- scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3531
- scrollEventThrottle: Platform2.OS === "web" ? 16 : void 0,
4014
+ scrollAdjustHandler: (_d = refState.current) == null ? void 0 : _d.scrollAdjustHandler,
4015
+ scrollEventThrottle: 0,
3532
4016
  snapToIndices,
4017
+ stickyHeaderConfig,
3533
4018
  stickyHeaderIndices,
3534
4019
  style,
3535
4020
  updateItemSize: fns.updateItemSize,
@@ -3539,6 +4024,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3539
4024
  });
3540
4025
 
3541
4026
  exports.LegendList = LegendList;
4027
+ exports.typedForwardRef = typedForwardRef;
4028
+ exports.typedMemo = typedMemo;
3542
4029
  exports.useIsLastItem = useIsLastItem;
3543
4030
  exports.useListScrollSize = useListScrollSize;
3544
4031
  exports.useRecyclingEffect = useRecyclingEffect;