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

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