@legendapp/list 3.0.0-beta.1 → 3.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.native.js CHANGED
@@ -28,30 +28,64 @@ var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
28
28
  reactNative.Animated.View;
29
29
  var View = reactNative.View;
30
30
  var Text = reactNative.Text;
31
+
32
+ // src/state/getContentInsetEnd.ts
33
+ function getContentInsetEnd(state) {
34
+ var _a3;
35
+ const { props } = state;
36
+ const horizontal = props.horizontal;
37
+ let contentInset = props.contentInset;
38
+ if (!contentInset) {
39
+ const animatedInset = (_a3 = props.animatedProps) == null ? void 0 : _a3.contentInset;
40
+ if (animatedInset) {
41
+ if ("get" in animatedInset) {
42
+ contentInset = animatedInset.get();
43
+ } else {
44
+ contentInset = animatedInset;
45
+ }
46
+ }
47
+ }
48
+ return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
49
+ }
50
+
51
+ // src/state/getContentSize.ts
52
+ function getContentSize(ctx) {
53
+ var _a3;
54
+ const { values, state } = ctx;
55
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
56
+ const stylePaddingBottom = state.props.stylePaddingBottom || 0;
57
+ const headerSize = values.get("headerSize") || 0;
58
+ const footerSize = values.get("footerSize") || 0;
59
+ const contentInsetBottom = getContentInsetEnd(state);
60
+ const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
61
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
62
+ }
31
63
  var createAnimatedValue = (value) => new reactNative.Animated.Value(value);
32
64
 
33
65
  // src/state/state.tsx
34
66
  var ContextState = React2__namespace.createContext(null);
67
+ var contextNum = 0;
35
68
  function StateProvider({ children }) {
36
69
  const [value] = React2__namespace.useState(() => ({
37
70
  animatedScrollY: createAnimatedValue(0),
38
71
  columnWrapperStyle: void 0,
39
- internalState: void 0,
72
+ contextNum: contextNum++,
40
73
  listeners: /* @__PURE__ */ new Map(),
41
74
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
42
75
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
43
76
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
44
77
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
45
78
  mapViewabilityValues: /* @__PURE__ */ new Map(),
79
+ positionListeners: /* @__PURE__ */ new Map(),
80
+ state: void 0,
46
81
  values: /* @__PURE__ */ new Map([
47
82
  ["alignItemsPaddingTop", 0],
48
83
  ["stylePaddingTop", 0],
49
84
  ["headerSize", 0],
50
85
  ["numContainers", 0],
51
- ["activeStickyIndex", void 0],
86
+ ["activeStickyIndex", -1],
52
87
  ["totalSize", 0],
53
- ["scrollAdjustPending", 0],
54
- ["scrollingTo", void 0]
88
+ ["scrollAdjustPending", 0]
55
89
  ]),
56
90
  viewRefs: /* @__PURE__ */ new Map()
57
91
  }));
@@ -119,15 +153,24 @@ function set$(ctx, signalName, value) {
119
153
  }
120
154
  }
121
155
  }
122
- function getContentSize(ctx) {
123
- var _a3, _b;
124
- const { values, internalState } = ctx;
125
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
126
- const stylePaddingBottom = (internalState == null ? void 0 : internalState.props.stylePaddingBottom) || 0;
127
- const headerSize = values.get("headerSize") || 0;
128
- const footerSize = values.get("footerSize") || 0;
129
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
130
- return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom;
156
+ function listenPosition$(ctx, key, cb) {
157
+ const { positionListeners } = ctx;
158
+ let setListeners = positionListeners.get(key);
159
+ if (!setListeners) {
160
+ setListeners = /* @__PURE__ */ new Set();
161
+ positionListeners.set(key, setListeners);
162
+ }
163
+ setListeners.add(cb);
164
+ return () => setListeners.delete(cb);
165
+ }
166
+ function notifyPosition$(ctx, key, value) {
167
+ const { positionListeners } = ctx;
168
+ const setListeners = positionListeners.get(key);
169
+ if (setListeners) {
170
+ for (const listener of setListeners) {
171
+ listener(value);
172
+ }
173
+ }
131
174
  }
132
175
  function useArr$(signalNames) {
133
176
  const ctx = React2__namespace.useContext(ContextState);
@@ -208,7 +251,8 @@ var ENABLE_DEBUG_VIEW = IS_DEV && false;
208
251
  // src/constants-platform.native.ts
209
252
  var IsNewArchitecture = global.nativeFabricUIManager != null;
210
253
  var useAnimatedValue = (initialValue) => {
211
- return React2.useRef(new reactNative.Animated.Value(initialValue)).current;
254
+ const [animAnimatedValue] = React2.useState(() => new reactNative.Animated.Value(initialValue));
255
+ return animAnimatedValue;
212
256
  };
213
257
 
214
258
  // src/utils/helpers.ts
@@ -297,7 +341,7 @@ var typedForwardRef = React2.forwardRef;
297
341
  var typedMemo = React2.memo;
298
342
 
299
343
  // src/components/PositionView.native.tsx
300
- var PositionViewState = typedMemo(function PositionView({
344
+ var PositionViewState = typedMemo(function PositionViewState2({
301
345
  id,
302
346
  horizontal,
303
347
  style,
@@ -317,7 +361,7 @@ var PositionViewState = typedMemo(function PositionView({
317
361
  }
318
362
  );
319
363
  });
320
- var PositionViewAnimated = typedMemo(function PositionView2({
364
+ var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
321
365
  id,
322
366
  horizontal,
323
367
  style,
@@ -360,60 +404,77 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
360
404
  const viewStyle = React2__namespace.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
361
405
  return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { ref: refView, style: viewStyle, ...rest });
362
406
  });
363
- var PositionView3 = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
364
- var symbolFirst = Symbol();
407
+ var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
365
408
  function useInit(cb) {
366
- const refValue = React2.useRef(symbolFirst);
367
- if (refValue.current === symbolFirst) {
368
- refValue.current = cb();
369
- }
370
- return refValue.current;
409
+ React2.useState(() => cb());
371
410
  }
372
411
 
373
412
  // src/state/ContextContainer.ts
374
413
  var ContextContainer = React2.createContext(null);
414
+ function useContextContainer() {
415
+ return React2.useContext(ContextContainer);
416
+ }
375
417
  function useViewability(callback, configId) {
376
418
  const ctx = useStateContext();
377
- const { containerId } = React2.useContext(ContextContainer);
378
- const key = containerId + (configId != null ? configId : "");
419
+ const containerContext = useContextContainer();
379
420
  useInit(() => {
421
+ if (!containerContext) {
422
+ return;
423
+ }
424
+ const { containerId } = containerContext;
425
+ const key = containerId + (configId != null ? configId : "");
380
426
  const value = ctx.mapViewabilityValues.get(key);
381
427
  if (value) {
382
428
  callback(value);
383
429
  }
384
430
  });
385
- ctx.mapViewabilityCallbacks.set(key, callback);
386
- React2.useEffect(
387
- () => () => {
431
+ React2.useEffect(() => {
432
+ if (!containerContext) {
433
+ return;
434
+ }
435
+ const { containerId } = containerContext;
436
+ const key = containerId + (configId != null ? configId : "");
437
+ ctx.mapViewabilityCallbacks.set(key, callback);
438
+ return () => {
388
439
  ctx.mapViewabilityCallbacks.delete(key);
389
- },
390
- []
391
- );
440
+ };
441
+ }, [ctx, callback, configId, containerContext]);
392
442
  }
393
443
  function useViewabilityAmount(callback) {
394
444
  const ctx = useStateContext();
395
- const { containerId } = React2.useContext(ContextContainer);
445
+ const containerContext = useContextContainer();
396
446
  useInit(() => {
447
+ if (!containerContext) {
448
+ return;
449
+ }
450
+ const { containerId } = containerContext;
397
451
  const value = ctx.mapViewabilityAmountValues.get(containerId);
398
452
  if (value) {
399
453
  callback(value);
400
454
  }
401
455
  });
402
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
403
- React2.useEffect(
404
- () => () => {
456
+ React2.useEffect(() => {
457
+ if (!containerContext) {
458
+ return;
459
+ }
460
+ const { containerId } = containerContext;
461
+ ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
462
+ return () => {
405
463
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
406
- },
407
- []
408
- );
464
+ };
465
+ }, [ctx, callback, containerContext]);
409
466
  }
410
467
  function useRecyclingEffect(effect) {
411
- const { index, value } = React2.useContext(ContextContainer);
468
+ const containerContext = useContextContainer();
412
469
  const prevValues = React2.useRef({
413
470
  prevIndex: void 0,
414
471
  prevItem: void 0
415
472
  });
416
473
  React2.useEffect(() => {
474
+ if (!containerContext) {
475
+ return;
476
+ }
477
+ const { index, value } = containerContext;
417
478
  let ret;
418
479
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
419
480
  ret = effect({
@@ -428,38 +489,58 @@ function useRecyclingEffect(effect) {
428
489
  prevItem: value
429
490
  };
430
491
  return ret;
431
- }, [index, value, effect]);
492
+ }, [effect, containerContext]);
432
493
  }
433
494
  function useRecyclingState(valueOrFun) {
434
- const { index, value, itemKey, triggerLayout } = React2.useContext(ContextContainer);
435
- const refState = React2.useRef({
436
- itemKey: null,
437
- value: null
495
+ var _a3, _b;
496
+ const containerContext = useContextContainer();
497
+ const computeValue = (ctx) => {
498
+ if (isFunction(valueOrFun)) {
499
+ const initializer = valueOrFun;
500
+ return ctx ? initializer({
501
+ index: ctx.index,
502
+ item: ctx.value,
503
+ prevIndex: void 0,
504
+ prevItem: void 0
505
+ }) : initializer();
506
+ }
507
+ return valueOrFun;
508
+ };
509
+ const [stateValue, setStateValue] = React2.useState(() => {
510
+ return computeValue(containerContext);
438
511
  });
439
- const [_, setRenderNum] = React2.useState(0);
440
- const state = refState.current;
441
- if (state.itemKey !== itemKey) {
442
- state.itemKey = itemKey;
443
- state.value = isFunction(valueOrFun) ? valueOrFun({
444
- index,
445
- item: value,
446
- prevIndex: void 0,
447
- prevItem: void 0
448
- }) : valueOrFun;
512
+ const prevItemKeyRef = React2.useRef((_a3 = containerContext == null ? void 0 : containerContext.itemKey) != null ? _a3 : null);
513
+ const currentItemKey = (_b = containerContext == null ? void 0 : containerContext.itemKey) != null ? _b : null;
514
+ if (currentItemKey !== null && prevItemKeyRef.current !== currentItemKey) {
515
+ prevItemKeyRef.current = currentItemKey;
516
+ setStateValue(computeValue(containerContext));
449
517
  }
518
+ const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
450
519
  const setState = React2.useCallback(
451
520
  (newState) => {
452
- state.value = isFunction(newState) ? newState(state.value) : newState;
453
- setRenderNum((v) => v + 1);
521
+ if (!triggerLayout) {
522
+ return;
523
+ }
524
+ setStateValue((prevValue) => {
525
+ return isFunction(newState) ? newState(prevValue) : newState;
526
+ });
454
527
  triggerLayout();
455
528
  },
456
- [triggerLayout, state]
529
+ [triggerLayout]
457
530
  );
458
- return [state.value, setState];
531
+ return [stateValue, setState];
459
532
  }
460
533
  function useIsLastItem() {
461
- const { itemKey } = React2.useContext(ContextContainer);
462
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
534
+ const containerContext = useContextContainer();
535
+ const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
536
+ if (containerContext) {
537
+ const { itemKey } = containerContext;
538
+ if (!isNullOrUndefined(itemKey)) {
539
+ return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
540
+ }
541
+ }
542
+ return false;
543
+ });
463
544
  return isLast;
464
545
  }
465
546
  function useListScrollSize() {
@@ -469,8 +550,9 @@ function useListScrollSize() {
469
550
  var noop = () => {
470
551
  };
471
552
  function useSyncLayout() {
472
- if (IsNewArchitecture) {
473
- const { triggerLayout: syncLayout } = React2.useContext(ContextContainer);
553
+ const containerContext = useContextContainer();
554
+ if (IsNewArchitecture && containerContext) {
555
+ const { triggerLayout: syncLayout } = containerContext;
474
556
  return syncLayout;
475
557
  } else {
476
558
  return noop;
@@ -633,6 +715,7 @@ var Container = typedMemo(function Container2({
633
715
  if (!IsNewArchitecture) {
634
716
  React2.useEffect(() => {
635
717
  if (!isNullOrUndefined(itemKey)) {
718
+ didLayoutRef.current = false;
636
719
  const timeout = setTimeout(() => {
637
720
  if (!didLayoutRef.current) {
638
721
  const {
@@ -652,7 +735,7 @@ var Container = typedMemo(function Container2({
652
735
  }
653
736
  }, [itemKey]);
654
737
  }
655
- const PositionComponent = isSticky ? PositionViewSticky : PositionView3;
738
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
656
739
  return /* @__PURE__ */ React2__namespace.createElement(
657
740
  PositionComponent,
658
741
  {
@@ -687,10 +770,10 @@ var Containers = typedMemo(function Containers2({
687
770
  // If this is the initial scroll, we don't want to delay because we want to update the size immediately
688
771
  delay: (value, prevValue) => {
689
772
  var _a3;
690
- return !((_a3 = ctx.internalState) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
773
+ return !((_a3 = ctx.state) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
691
774
  }
692
775
  });
693
- const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("containersDidLayout", { getValue: (value) => value ? 1 : 0 }) : void 0;
776
+ const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("readyToRender", { getValue: (value) => value ? 1 : 0 }) : void 0;
694
777
  const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
695
778
  const containers = [];
696
779
  for (let i = 0; i < numContainers; i++) {
@@ -733,7 +816,8 @@ var Containers = typedMemo(function Containers2({
733
816
  return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { style }, containers);
734
817
  });
735
818
  function DevNumbers() {
736
- return IS_DEV && React2__namespace.memo(function DevNumbers2() {
819
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
820
+ React2__namespace.memo(function DevNumbers2() {
737
821
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React2__namespace.createElement(
738
822
  reactNative.View,
739
823
  {
@@ -841,13 +925,6 @@ var ListComponent = typedMemo(function ListComponent2({
841
925
  () => React2__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
842
926
  [renderScrollComponent]
843
927
  ) : ListComponentScrollView;
844
- React2__namespace.useEffect(() => {
845
- if (canRender) {
846
- setTimeout(() => {
847
- scrollAdjustHandler.setMounted();
848
- }, 0);
849
- }
850
- }, [canRender]);
851
928
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
852
929
  return /* @__PURE__ */ React2__namespace.createElement(
853
930
  SnapOrScroll,
@@ -911,10 +988,11 @@ function getId(state, index) {
911
988
  }
912
989
 
913
990
  // src/core/calculateOffsetForIndex.ts
914
- function calculateOffsetForIndex(ctx, state, index) {
991
+ function calculateOffsetForIndex(ctx, index) {
992
+ const state = ctx.state;
915
993
  let position = 0;
916
994
  if (index !== void 0) {
917
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
995
+ position = state.positions.get(getId(state, index)) || 0;
918
996
  const paddingTop = peek$(ctx, "stylePaddingTop");
919
997
  if (paddingTop) {
920
998
  position += paddingTop;
@@ -928,7 +1006,8 @@ function calculateOffsetForIndex(ctx, state, index) {
928
1006
  }
929
1007
 
930
1008
  // src/utils/setPaddingTop.ts
931
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1009
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1010
+ const state = ctx.state;
932
1011
  if (stylePaddingTop !== void 0) {
933
1012
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
934
1013
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -947,7 +1026,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
947
1026
  }
948
1027
 
949
1028
  // src/utils/updateAlignItemsPaddingTop.ts
950
- function updateAlignItemsPaddingTop(ctx, state) {
1029
+ function updateAlignItemsPaddingTop(ctx) {
1030
+ const state = ctx.state;
951
1031
  const {
952
1032
  scrollLength,
953
1033
  props: { alignItemsAtEnd, data }
@@ -958,12 +1038,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
958
1038
  const contentSize = getContentSize(ctx);
959
1039
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
960
1040
  }
961
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1041
+ setPaddingTop(ctx, { alignItemsPaddingTop });
962
1042
  }
963
1043
  }
964
1044
 
965
1045
  // src/core/addTotalSize.ts
966
- function addTotalSize(ctx, state, key, add) {
1046
+ function addTotalSize(ctx, key, add) {
1047
+ const state = ctx.state;
967
1048
  const { alignItemsAtEnd } = state.props;
968
1049
  const prevTotalSize = state.totalSize;
969
1050
  let totalSize = state.totalSize;
@@ -984,31 +1065,34 @@ function addTotalSize(ctx, state, key, add) {
984
1065
  state.totalSize = totalSize;
985
1066
  set$(ctx, "totalSize", totalSize);
986
1067
  if (alignItemsAtEnd) {
987
- updateAlignItemsPaddingTop(ctx, state);
1068
+ updateAlignItemsPaddingTop(ctx);
988
1069
  }
989
1070
  }
990
1071
  }
991
1072
  }
992
1073
 
993
1074
  // src/core/setSize.ts
994
- function setSize(ctx, state, itemKey, size) {
1075
+ function setSize(ctx, itemKey, size) {
1076
+ const state = ctx.state;
995
1077
  const { sizes } = state;
996
1078
  const previousSize = sizes.get(itemKey);
997
1079
  const diff = previousSize !== void 0 ? size - previousSize : size;
998
1080
  if (diff !== 0) {
999
- addTotalSize(ctx, state, itemKey, diff);
1081
+ addTotalSize(ctx, itemKey, diff);
1000
1082
  }
1001
1083
  sizes.set(itemKey, size);
1002
1084
  }
1003
1085
 
1004
1086
  // src/utils/getItemSize.ts
1005
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1087
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1006
1088
  var _a3, _b;
1089
+ const state = ctx.state;
1007
1090
  const {
1008
1091
  sizesKnown,
1009
1092
  sizes,
1010
1093
  averageSizes,
1011
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1094
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1095
+ scrollingTo
1012
1096
  } = state;
1013
1097
  const sizeKnown = sizesKnown.get(key);
1014
1098
  if (sizeKnown !== void 0) {
@@ -1016,7 +1100,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1016
1100
  }
1017
1101
  let size;
1018
1102
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1019
- const scrollingTo = peek$(ctx, "scrollingTo");
1020
1103
  if (preferCachedSize) {
1021
1104
  const cachedSize = sizes.get(key);
1022
1105
  if (cachedSize !== void 0) {
@@ -1044,84 +1127,167 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1044
1127
  if (size === void 0) {
1045
1128
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1046
1129
  }
1047
- setSize(ctx, state, key, size);
1130
+ setSize(ctx, key, size);
1048
1131
  return size;
1049
1132
  }
1050
1133
 
1051
1134
  // src/core/calculateOffsetWithOffsetPosition.ts
1052
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1135
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1136
+ const state = ctx.state;
1053
1137
  const { index, viewOffset, viewPosition } = params;
1054
1138
  let offset = offsetParam;
1055
1139
  if (viewOffset) {
1056
1140
  offset -= viewOffset;
1057
1141
  }
1058
1142
  if (viewPosition !== void 0 && index !== void 0) {
1059
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1143
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1144
+ const trailingInset = getContentInsetEnd(state);
1145
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1060
1146
  }
1061
1147
  return offset;
1062
1148
  }
1063
1149
 
1150
+ // src/core/clampScrollOffset.ts
1151
+ function clampScrollOffset(ctx, offset) {
1152
+ const state = ctx.state;
1153
+ const contentSize = getContentSize(ctx);
1154
+ let clampedOffset = offset;
1155
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1156
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1157
+ clampedOffset = Math.min(offset, maxOffset);
1158
+ }
1159
+ clampedOffset = Math.max(0, clampedOffset);
1160
+ return clampedOffset;
1161
+ }
1162
+ var Platform2 = reactNative.Platform;
1163
+
1164
+ // src/utils/setInitialRenderState.ts
1165
+ function setInitialRenderState(ctx, {
1166
+ didLayout,
1167
+ didInitialScroll
1168
+ }) {
1169
+ const { state } = ctx;
1170
+ if (didLayout) {
1171
+ state.didContainersLayout = true;
1172
+ }
1173
+ if (didInitialScroll) {
1174
+ state.didFinishInitialScroll = true;
1175
+ }
1176
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1177
+ set$(ctx, "readyToRender", true);
1178
+ }
1179
+ }
1180
+
1064
1181
  // src/core/finishScrollTo.ts
1065
- function finishScrollTo(ctx, state) {
1182
+ function finishScrollTo(ctx) {
1066
1183
  var _a3, _b;
1067
- if (state) {
1184
+ const state = ctx.state;
1185
+ if (state == null ? void 0 : state.scrollingTo) {
1068
1186
  state.scrollHistory.length = 0;
1069
1187
  state.initialScroll = void 0;
1070
1188
  state.initialAnchor = void 0;
1071
- set$(ctx, "scrollingTo", void 0);
1189
+ state.scrollingTo = void 0;
1072
1190
  if (state.pendingTotalSize !== void 0) {
1073
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1191
+ addTotalSize(ctx, null, state.pendingTotalSize);
1074
1192
  }
1075
1193
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1076
1194
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1077
1195
  }
1196
+ if (Platform2.OS === "web") {
1197
+ state.scrollAdjustHandler.commitPendingAdjust();
1198
+ }
1199
+ setInitialRenderState(ctx, { didInitialScroll: true });
1078
1200
  }
1079
1201
  }
1080
- var Platform2 = reactNative.Platform;
1081
1202
 
1082
- // src/core/scrollTo.ts
1083
- function scrollTo(ctx, state, params) {
1203
+ // src/core/checkFinishedScroll.ts
1204
+ function checkFinishedScroll(ctx) {
1205
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1206
+ }
1207
+ function checkFinishedScrollFrame(ctx) {
1208
+ const scrollingTo = ctx.state.scrollingTo;
1209
+ if (scrollingTo) {
1210
+ const { state } = ctx;
1211
+ state.animFrameCheckFinishedScroll = void 0;
1212
+ const scroll = state.scroll;
1213
+ const adjust = state.scrollAdjustHandler.getAdjust();
1214
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
1215
+ const maxOffset = clampScrollOffset(ctx, scroll);
1216
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
1217
+ const diff2 = Math.abs(diff1 - adjust);
1218
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
1219
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
1220
+ finishScrollTo(ctx);
1221
+ }
1222
+ }
1223
+ }
1224
+ function checkFinishedScrollFallback(ctx) {
1225
+ const state = ctx.state;
1226
+ const scrollingTo = state.scrollingTo;
1227
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
1228
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
1229
+ () => {
1230
+ let numChecks = 0;
1231
+ const checkHasScrolled = () => {
1232
+ state.timeoutCheckFinishedScrollFallback = void 0;
1233
+ const isStillScrollingTo = state.scrollingTo;
1234
+ if (isStillScrollingTo) {
1235
+ numChecks++;
1236
+ if (state.hasScrolled || numChecks > 5) {
1237
+ finishScrollTo(ctx);
1238
+ } else {
1239
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
1240
+ }
1241
+ }
1242
+ };
1243
+ checkHasScrolled();
1244
+ },
1245
+ slowTimeout ? 500 : 100
1246
+ );
1247
+ }
1248
+
1249
+ // src/core/doScrollTo.native.ts
1250
+ function doScrollTo(ctx, params) {
1084
1251
  var _a3;
1085
- const { noScrollingTo, ...scrollTarget } = params;
1252
+ const state = ctx.state;
1253
+ const { animated, horizontal, offset } = params;
1254
+ const { refScroller } = state;
1255
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1256
+ animated: !!animated,
1257
+ x: horizontal ? offset : 0,
1258
+ y: horizontal ? 0 : offset
1259
+ });
1260
+ if (!animated) {
1261
+ state.scroll = offset;
1262
+ checkFinishedScrollFallback(ctx);
1263
+ }
1264
+ }
1265
+
1266
+ // src/core/scrollTo.ts
1267
+ function scrollTo(ctx, params) {
1268
+ const state = ctx.state;
1269
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1086
1270
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1087
1271
  const {
1088
- refScroller,
1089
1272
  props: { horizontal }
1090
1273
  } = state;
1091
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1092
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1093
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1094
- offset = Math.min(offset, maxOffset);
1274
+ if (state.animFrameCheckFinishedScroll) {
1275
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1095
1276
  }
1277
+ if (state.timeoutCheckFinishedScrollFallback) {
1278
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1279
+ }
1280
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1281
+ offset = clampScrollOffset(ctx, offset);
1096
1282
  state.scrollHistory.length = 0;
1097
1283
  if (!noScrollingTo) {
1098
- set$(ctx, "scrollingTo", scrollTarget);
1284
+ state.scrollingTo = scrollTarget;
1099
1285
  }
1100
1286
  state.scrollPending = offset;
1101
- if (!isInitialScroll || Platform2.OS === "android") {
1102
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1103
- animated: !!animated,
1104
- x: horizontal ? offset : 0,
1105
- y: horizontal ? 0 : offset
1106
- });
1107
- }
1108
- if (!animated) {
1287
+ if (forceScroll || !isInitialScroll || Platform2.OS === "android") {
1288
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1289
+ } else {
1109
1290
  state.scroll = offset;
1110
- if (Platform2.OS === "web") {
1111
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1112
- if (value && peek$(ctx, "scrollingTo")) {
1113
- finishScrollTo(ctx, state);
1114
- unlisten();
1115
- }
1116
- });
1117
- } else {
1118
- setTimeout(() => finishScrollTo(ctx, state), 100);
1119
- }
1120
- if (isInitialScroll) {
1121
- setTimeout(() => {
1122
- state.initialScroll = void 0;
1123
- }, 500);
1124
- }
1125
1291
  }
1126
1292
  }
1127
1293
 
@@ -1130,6 +1296,12 @@ var HYSTERESIS_MULTIPLIER = 1.3;
1130
1296
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1131
1297
  const absDistance = Math.abs(distance);
1132
1298
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1299
+ if (wasReached === null) {
1300
+ if (!within && distance >= 0) {
1301
+ return false;
1302
+ }
1303
+ return null;
1304
+ }
1133
1305
  const updateSnapshot = () => {
1134
1306
  setSnapshot == null ? void 0 : setSnapshot({
1135
1307
  atThreshold,
@@ -1162,8 +1334,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1162
1334
  };
1163
1335
 
1164
1336
  // src/utils/checkAtBottom.ts
1165
- function checkAtBottom(ctx, state) {
1337
+ function checkAtBottom(ctx) {
1166
1338
  var _a3;
1339
+ const state = ctx.state;
1167
1340
  if (!state) {
1168
1341
  return;
1169
1342
  }
@@ -1236,15 +1409,15 @@ function checkAtTop(state) {
1236
1409
  }
1237
1410
 
1238
1411
  // src/core/updateScroll.ts
1239
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1412
+ function updateScroll(ctx, newScroll, forceUpdate) {
1240
1413
  var _a3;
1241
- const scrollingTo = peek$(ctx, "scrollingTo");
1414
+ const state = ctx.state;
1415
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1242
1416
  state.hasScrolled = true;
1243
1417
  state.lastBatchingAction = Date.now();
1244
1418
  const currentTime = Date.now();
1245
- const adjust = state.scrollAdjustHandler.getAdjust();
1246
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1247
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1419
+ const adjust = scrollAdjustHandler.getAdjust();
1420
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1248
1421
  if (adjustChanged) {
1249
1422
  state.scrollHistory.length = 0;
1250
1423
  }
@@ -1269,22 +1442,26 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1269
1442
  return;
1270
1443
  }
1271
1444
  }
1272
- if (forceUpdate || state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1445
+ const lastCalculated = state.scrollLastCalculate;
1446
+ const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1447
+ if (shouldUpdate) {
1448
+ state.scrollLastCalculate = state.scroll;
1273
1449
  state.ignoreScrollFromMVCPIgnored = false;
1274
1450
  (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1275
- checkAtBottom(ctx, state);
1451
+ checkAtBottom(ctx);
1276
1452
  checkAtTop(state);
1277
1453
  state.dataChangeNeedsScrollUpdate = false;
1278
1454
  }
1279
1455
  }
1280
1456
 
1281
1457
  // src/utils/requestAdjust.ts
1282
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1458
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1459
+ const state = ctx.state;
1283
1460
  if (Math.abs(positionDiff) > 0.1) {
1284
1461
  const needsScrollWorkaround = Platform2.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
1285
1462
  const doit = () => {
1286
1463
  if (needsScrollWorkaround) {
1287
- scrollTo(ctx, state, {
1464
+ scrollTo(ctx, {
1288
1465
  noScrollingTo: true,
1289
1466
  offset: state.scroll
1290
1467
  });
@@ -1297,8 +1474,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1297
1474
  };
1298
1475
  state.scroll += positionDiff;
1299
1476
  state.scrollForNextCalculateItemsInView = void 0;
1300
- const didLayout = peek$(ctx, "containersDidLayout");
1301
- if (didLayout) {
1477
+ const readyToRender = peek$(ctx, "readyToRender");
1478
+ if (readyToRender) {
1302
1479
  doit();
1303
1480
  if (Platform2.OS !== "web") {
1304
1481
  const threshold = state.scroll - positionDiff / 2;
@@ -1320,7 +1497,7 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1320
1497
  if (shouldForceUpdate) {
1321
1498
  state.ignoreScrollFromMVCPIgnored = false;
1322
1499
  state.scrollPending = state.scroll;
1323
- updateScroll(ctx, state, state.scroll, true);
1500
+ updateScroll(ctx, state.scroll, true);
1324
1501
  }
1325
1502
  }, delay);
1326
1503
  }
@@ -1335,28 +1512,27 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1335
1512
  var INITIAL_ANCHOR_TOLERANCE = 0.5;
1336
1513
  var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1337
1514
  var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1338
- function ensureInitialAnchor(ctx, state) {
1515
+ function ensureInitialAnchor(ctx) {
1339
1516
  var _a3, _b, _c, _d, _e;
1340
- const anchor = state.initialAnchor;
1517
+ const state = ctx.state;
1518
+ const { initialAnchor, didContainersLayout, positions, scroll, scrollLength } = state;
1519
+ const anchor = initialAnchor;
1341
1520
  const item = state.props.data[anchor.index];
1342
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1343
- if (!containersDidLayout) {
1521
+ if (!didContainersLayout) {
1344
1522
  return;
1345
1523
  }
1346
1524
  const id = getId(state, anchor.index);
1347
- if (state.positions.get(id) === void 0) {
1525
+ if (positions.get(id) === void 0) {
1348
1526
  return;
1349
1527
  }
1350
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1528
+ const size = getItemSize(ctx, id, anchor.index, item, true, true);
1351
1529
  if (size === void 0) {
1352
1530
  return;
1353
1531
  }
1354
- const availableSpace = Math.max(0, state.scrollLength - size);
1355
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1356
- const contentSize = getContentSize(ctx);
1357
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1358
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1359
- const delta = clampedDesiredOffset - state.scroll;
1532
+ const availableSpace = Math.max(0, scrollLength - size);
1533
+ const desiredOffset = calculateOffsetForIndex(ctx, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1534
+ const clampedDesiredOffset = clampScrollOffset(ctx, desiredOffset);
1535
+ const delta = clampedDesiredOffset - scroll;
1360
1536
  if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1361
1537
  const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1362
1538
  if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
@@ -1380,18 +1556,21 @@ function ensureInitialAnchor(ctx, state) {
1380
1556
  lastDelta: delta,
1381
1557
  settledTicks: 0
1382
1558
  });
1383
- requestAdjust(ctx, state, delta);
1559
+ requestAdjust(ctx, delta);
1560
+ requestAnimationFrame(() => finishScrollTo(ctx));
1384
1561
  }
1385
1562
 
1386
1563
  // src/core/mvcp.ts
1387
- function prepareMVCP(ctx, state, dataChanged) {
1564
+ function prepareMVCP(ctx, dataChanged) {
1565
+ const state = ctx.state;
1388
1566
  const { idsInView, positions, props } = state;
1389
1567
  const { maintainVisibleContentPosition } = props;
1390
- const scrollingTo = peek$(ctx, "scrollingTo");
1568
+ const scrollingTo = state.scrollingTo;
1391
1569
  let prevPosition;
1392
1570
  let targetId;
1393
1571
  const idsInViewWithPositions = [];
1394
1572
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1573
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1395
1574
  const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1396
1575
  const indexByKey = state.indexByKey;
1397
1576
  if (shouldMVCP) {
@@ -1400,7 +1579,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1400
1579
  return void 0;
1401
1580
  }
1402
1581
  targetId = getId(state, scrollTarget);
1403
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1582
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1404
1583
  if (dataChanged) {
1405
1584
  for (let i = 0; i < idsInView.length; i++) {
1406
1585
  const id = idsInView[i];
@@ -1417,7 +1596,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1417
1596
  prevPosition = positions.get(targetId);
1418
1597
  }
1419
1598
  return () => {
1420
- let positionDiff;
1599
+ let positionDiff = 0;
1421
1600
  if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1422
1601
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1423
1602
  const { id, position } = idsInViewWithPositions[i];
@@ -1443,16 +1622,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1443
1622
  positionDiff = diff;
1444
1623
  }
1445
1624
  }
1446
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1447
- requestAdjust(ctx, state, positionDiff, dataChanged && maintainVisibleContentPosition);
1625
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1626
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1627
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1628
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1629
+ const diff = newSize - prevSize;
1630
+ if (diff !== 0) {
1631
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1632
+ scrollingTo.itemSize = newSize;
1633
+ }
1634
+ }
1635
+ }
1636
+ if (Math.abs(positionDiff) > 0.1) {
1637
+ requestAdjust(ctx, positionDiff, dataChanged && maintainVisibleContentPosition);
1448
1638
  }
1449
1639
  };
1450
1640
  }
1451
1641
  }
1452
1642
 
1453
1643
  // src/core/prepareColumnStartState.ts
1454
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1644
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1455
1645
  var _a3;
1646
+ const state = ctx.state;
1456
1647
  const numColumns = peek$(ctx, "numColumns");
1457
1648
  let rowStartIndex = startIndex;
1458
1649
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1467,7 +1658,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1467
1658
  const prevId = state.idCache[prevIndex];
1468
1659
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1469
1660
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1470
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1661
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1471
1662
  currentRowTop = prevPosition + prevRowHeight;
1472
1663
  }
1473
1664
  return {
@@ -1490,7 +1681,8 @@ function findRowStartIndex(state, numColumns, index) {
1490
1681
  }
1491
1682
  return rowStart;
1492
1683
  }
1493
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1684
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1685
+ const state = ctx.state;
1494
1686
  if (endIndex < startIndex) {
1495
1687
  return 0;
1496
1688
  }
@@ -1504,7 +1696,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1504
1696
  continue;
1505
1697
  }
1506
1698
  const id = state.idCache[i];
1507
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1699
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1508
1700
  if (size > maxSize) {
1509
1701
  maxSize = size;
1510
1702
  }
@@ -1513,22 +1705,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1513
1705
  }
1514
1706
 
1515
1707
  // src/core/updateTotalSize.ts
1516
- function updateTotalSize(ctx, state) {
1708
+ function updateTotalSize(ctx) {
1709
+ const state = ctx.state;
1517
1710
  const {
1518
1711
  positions,
1519
1712
  props: { data }
1520
1713
  } = state;
1521
1714
  if (data.length === 0) {
1522
- addTotalSize(ctx, state, null, 0);
1715
+ addTotalSize(ctx, null, 0);
1523
1716
  } else {
1524
1717
  const lastId = getId(state, data.length - 1);
1525
1718
  if (lastId !== void 0) {
1526
1719
  const lastPosition = positions.get(lastId);
1527
1720
  if (lastPosition !== void 0) {
1528
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1721
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1529
1722
  if (lastSize !== void 0) {
1530
1723
  const totalSize = lastPosition + lastSize;
1531
- addTotalSize(ctx, state, null, totalSize);
1724
+ addTotalSize(ctx, null, totalSize);
1532
1725
  }
1533
1726
  }
1534
1727
  }
@@ -1574,7 +1767,8 @@ var getScrollVelocity = (state) => {
1574
1767
  };
1575
1768
 
1576
1769
  // src/utils/updateSnapToOffsets.ts
1577
- function updateSnapToOffsets(ctx, state) {
1770
+ function updateSnapToOffsets(ctx) {
1771
+ const state = ctx.state;
1578
1772
  const {
1579
1773
  positions,
1580
1774
  props: { snapToIndices }
@@ -1589,30 +1783,30 @@ function updateSnapToOffsets(ctx, state) {
1589
1783
  }
1590
1784
 
1591
1785
  // src/core/updateItemPositions.ts
1592
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1786
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1593
1787
  doMVCP: false,
1594
1788
  forceFullUpdate: false,
1595
1789
  scrollBottomBuffered: -1,
1596
1790
  startIndex: 0
1597
1791
  }) {
1598
1792
  var _a3, _b, _c, _d, _e;
1793
+ const state = ctx.state;
1599
1794
  const {
1600
1795
  columns,
1601
1796
  indexByKey,
1602
1797
  positions,
1603
1798
  idCache,
1604
1799
  sizesKnown,
1605
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1800
+ props: { data, getEstimatedItemSize, snapToIndices },
1801
+ scrollingTo
1606
1802
  } = state;
1607
- const data = state.props.data;
1608
1803
  const dataLength = data.length;
1609
1804
  const numColumns = peek$(ctx, "numColumns");
1610
- const scrollingTo = peek$(ctx, "scrollingTo");
1611
1805
  const hasColumns = numColumns > 1;
1612
1806
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1613
1807
  const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1614
1808
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1615
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1809
+ const useAverageSize = !getEstimatedItemSize;
1616
1810
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1617
1811
  let currentRowTop = 0;
1618
1812
  let column = 1;
@@ -1621,7 +1815,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1621
1815
  if (hasColumns) {
1622
1816
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1623
1817
  ctx,
1624
- state,
1625
1818
  startIndex,
1626
1819
  useAverageSize
1627
1820
  );
@@ -1631,7 +1824,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1631
1824
  const prevIndex = startIndex - 1;
1632
1825
  const prevId = getId(state, prevIndex);
1633
1826
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1634
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1827
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1635
1828
  currentRowTop = prevPosition + prevSize;
1636
1829
  }
1637
1830
  }
@@ -1648,7 +1841,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1648
1841
  breakAt = i + itemsPerRow + 10;
1649
1842
  }
1650
1843
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1651
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1844
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1652
1845
  if (IS_DEV && needsIndexByKey) {
1653
1846
  if (indexByKeyForChecking.has(id)) {
1654
1847
  console.error(
@@ -1657,7 +1850,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1657
1850
  }
1658
1851
  indexByKeyForChecking.set(id, i);
1659
1852
  }
1660
- positions.set(id, currentRowTop);
1853
+ if (currentRowTop !== positions.get(id)) {
1854
+ positions.set(id, currentRowTop);
1855
+ notifyPosition$(ctx, id, currentRowTop);
1856
+ }
1661
1857
  if (needsIndexByKey) {
1662
1858
  indexByKey.set(id, i);
1663
1859
  }
@@ -1677,10 +1873,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1677
1873
  }
1678
1874
  }
1679
1875
  if (!didBreakEarly) {
1680
- updateTotalSize(ctx, state);
1876
+ updateTotalSize(ctx);
1681
1877
  }
1682
1878
  if (snapToIndices) {
1683
- updateSnapToOffsets(ctx, state);
1879
+ updateSnapToOffsets(ctx);
1684
1880
  }
1685
1881
  }
1686
1882
 
@@ -1758,7 +1954,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1758
1954
  if (previousViewableItems) {
1759
1955
  for (const viewToken of previousViewableItems) {
1760
1956
  const containerId = findContainerId(ctx, viewToken.key);
1761
- if (!isViewable(
1957
+ if (!checkIsViewable(
1762
1958
  state,
1763
1959
  ctx,
1764
1960
  viewabilityConfig,
@@ -1779,7 +1975,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1779
1975
  if (item) {
1780
1976
  const key = getId(state, i);
1781
1977
  const containerId = findContainerId(ctx, key);
1782
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1978
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1783
1979
  const viewToken = {
1784
1980
  containerId,
1785
1981
  index: i,
@@ -1839,11 +2035,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1839
2035
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
1840
2036
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
1841
2037
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
1842
- const isViewable2 = percent >= viewablePercentThreshold;
2038
+ const isViewable = percent >= viewablePercentThreshold;
1843
2039
  const value = {
1844
2040
  containerId,
1845
2041
  index,
1846
- isViewable: isViewable2,
2042
+ isViewable,
1847
2043
  item,
1848
2044
  key,
1849
2045
  percentOfScroller,
@@ -1862,8 +2058,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1862
2058
  }
1863
2059
  return value;
1864
2060
  }
1865
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
1866
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2061
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2062
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2063
+ if (!value || value.key !== key) {
2064
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2065
+ }
1867
2066
  return value.isViewable;
1868
2067
  }
1869
2068
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -1891,8 +2090,9 @@ function checkAllSizesKnown(state) {
1891
2090
  }
1892
2091
 
1893
2092
  // src/utils/findAvailableContainers.ts
1894
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2093
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
1895
2094
  const numContainers = peek$(ctx, "numContainers");
2095
+ const state = ctx.state;
1896
2096
  const { stickyContainerPool, containerItemTypes } = state;
1897
2097
  const result = [];
1898
2098
  const availableContainers = [];
@@ -1936,14 +2136,14 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1936
2136
  continue;
1937
2137
  }
1938
2138
  const key = peek$(ctx, `containerItemKey${u}`);
1939
- let isOk = key === void 0;
1940
- if (!isOk && pendingRemovalSet.has(u)) {
1941
- pendingRemovalSet.delete(u);
1942
- pendingRemovalChanged = true;
1943
- const requiredType = neededTypes[typeIndex];
1944
- isOk = canReuseContainer(u, requiredType);
1945
- }
1946
- if (isOk) {
2139
+ const requiredType = neededTypes[typeIndex];
2140
+ const isPending = key !== void 0 && pendingRemovalSet.has(u);
2141
+ const canUse = key === void 0 || isPending && canReuseContainer(u, requiredType);
2142
+ if (canUse) {
2143
+ if (isPending) {
2144
+ pendingRemovalSet.delete(u);
2145
+ pendingRemovalChanged = true;
2146
+ }
1947
2147
  result.push(u);
1948
2148
  if (requiredItemTypes) {
1949
2149
  typeIndex++;
@@ -2012,21 +2212,26 @@ function comparatorByDistance(a, b) {
2012
2212
  }
2013
2213
 
2014
2214
  // src/core/scrollToIndex.ts
2015
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2016
- if (index >= state.props.data.length) {
2017
- index = state.props.data.length - 1;
2215
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2216
+ const state = ctx.state;
2217
+ const { data } = state.props;
2218
+ if (index >= data.length) {
2219
+ index = data.length - 1;
2018
2220
  } else if (index < 0) {
2019
2221
  index = 0;
2020
2222
  }
2021
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2022
- const isLast = index === state.props.data.length - 1;
2223
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2224
+ const isLast = index === data.length - 1;
2023
2225
  if (isLast && viewPosition === void 0) {
2024
2226
  viewPosition = 1;
2025
2227
  }
2026
2228
  state.scrollForNextCalculateItemsInView = void 0;
2027
- scrollTo(ctx, state, {
2229
+ const targetId = getId(state, index);
2230
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2231
+ scrollTo(ctx, {
2028
2232
  animated,
2029
2233
  index,
2234
+ itemSize,
2030
2235
  offset: firstIndexOffset,
2031
2236
  viewOffset,
2032
2237
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2034,29 +2239,30 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2034
2239
  }
2035
2240
 
2036
2241
  // src/utils/setDidLayout.ts
2037
- function setDidLayout(ctx, state) {
2242
+ function setDidLayout(ctx) {
2243
+ const state = ctx.state;
2038
2244
  const {
2039
2245
  loadStartTime,
2040
2246
  initialScroll,
2041
2247
  props: { onLoad }
2042
2248
  } = state;
2043
2249
  state.queuedInitialLayout = true;
2044
- checkAtBottom(ctx, state);
2250
+ checkAtBottom(ctx);
2045
2251
  const setIt = () => {
2046
- set$(ctx, "containersDidLayout", true);
2252
+ setInitialRenderState(ctx, { didLayout: true });
2047
2253
  if (onLoad) {
2048
2254
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2049
2255
  }
2050
2256
  };
2051
2257
  if (Platform2.OS === "android" && initialScroll) {
2052
2258
  if (IsNewArchitecture) {
2053
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2259
+ scrollToIndex(ctx, { ...initialScroll, animated: false });
2054
2260
  requestAnimationFrame(() => {
2055
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2261
+ scrollToIndex(ctx, { ...initialScroll, animated: false });
2056
2262
  setIt();
2057
2263
  });
2058
2264
  } else {
2059
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2265
+ scrollToIndex(ctx, { ...initialScroll, animated: false });
2060
2266
  setIt();
2061
2267
  }
2062
2268
  } else {
@@ -2079,15 +2285,17 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2079
2285
  }
2080
2286
  return -1;
2081
2287
  }
2082
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2288
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2289
+ const state = ctx.state;
2083
2290
  return new Set(
2084
2291
  Array.from(state.stickyContainerPool).map((i) => peek$(ctx, `containerItemKey${i}`)).map((key) => key ? state.indexByKey.get(key) : void 0).filter((idx) => idx !== void 0 && stickyHeaderIndices.has(idx))
2085
2292
  );
2086
2293
  }
2087
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2294
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2088
2295
  var _a3;
2089
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2090
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2296
+ const state = ctx.state;
2297
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2298
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2091
2299
  for (let offset = 0; offset <= 1; offset++) {
2092
2300
  const idx = currentStickyIdx - offset;
2093
2301
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -2098,8 +2306,9 @@ function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, cu
2098
2306
  }
2099
2307
  }
2100
2308
  }
2101
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2309
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2102
2310
  var _a3, _b, _c;
2311
+ const state = ctx.state;
2103
2312
  for (const containerIndex of state.stickyContainerPool) {
2104
2313
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2105
2314
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
@@ -2123,7 +2332,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2123
2332
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2124
2333
  if (currentId) {
2125
2334
  const currentPos = state.positions.get(currentId);
2126
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2335
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2127
2336
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2128
2337
  }
2129
2338
  }
@@ -2132,7 +2341,8 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2132
2341
  }
2133
2342
  }
2134
2343
  }
2135
- function calculateItemsInView(ctx, state, params = {}) {
2344
+ function calculateItemsInView(ctx, params = {}) {
2345
+ const state = ctx.state;
2136
2346
  reactNative.unstable_batchedUpdates(() => {
2137
2347
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2138
2348
  const {
@@ -2156,8 +2366,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2156
2366
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2157
2367
  const prevNumContainers = peek$(ctx, "numContainers");
2158
2368
  if (!data || scrollLength === 0 || !prevNumContainers) {
2159
- if (state.initialAnchor) {
2160
- ensureInitialAnchor(ctx, state);
2369
+ if (!IsNewArchitecture && state.initialAnchor) {
2370
+ ensureInitialAnchor(ctx);
2161
2371
  }
2162
2372
  return;
2163
2373
  }
@@ -2172,15 +2382,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2172
2382
  if (!queuedInitialLayout && initialScroll) {
2173
2383
  const updatedOffset = calculateOffsetWithOffsetPosition(
2174
2384
  ctx,
2175
- state,
2176
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2385
+ calculateOffsetForIndex(ctx, initialScroll.index),
2177
2386
  initialScroll
2178
2387
  );
2179
2388
  scrollState = updatedOffset;
2180
2389
  }
2181
2390
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2182
2391
  const scrollAdjustPad = scrollAdjustPending - topPad;
2183
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2392
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2184
2393
  if (scroll + scrollLength > totalSize) {
2185
2394
  scroll = Math.max(0, totalSize - scrollLength);
2186
2395
  }
@@ -2188,11 +2397,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2188
2397
  set$(ctx, "debugRawScroll", scrollState);
2189
2398
  set$(ctx, "debugComputedScroll", scroll);
2190
2399
  }
2191
- const previousStickyIndex = state.activeStickyIndex;
2400
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2192
2401
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2193
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2194
- state.activeStickyIndex = nextActiveStickyIndex;
2195
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2402
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2403
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2404
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2405
+ }
2196
2406
  let scrollBufferTop = scrollBuffer;
2197
2407
  let scrollBufferBottom = scrollBuffer;
2198
2408
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2205,23 +2415,23 @@ function calculateItemsInView(ctx, state, params = {}) {
2205
2415
  const scrollTopBuffered = scroll - scrollBufferTop;
2206
2416
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2207
2417
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2208
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2418
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2209
2419
  const { top, bottom } = scrollForNextCalculateItemsInView;
2210
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2211
- if (state.initialAnchor) {
2212
- ensureInitialAnchor(ctx, state);
2420
+ if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2421
+ if (!IsNewArchitecture && state.initialAnchor) {
2422
+ ensureInitialAnchor(ctx);
2213
2423
  }
2214
2424
  return;
2215
2425
  }
2216
2426
  }
2217
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2427
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2218
2428
  if (dataChanged) {
2219
2429
  indexByKey.clear();
2220
2430
  idCache.length = 0;
2221
2431
  positions.clear();
2222
2432
  }
2223
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2224
- updateItemPositions(ctx, state, dataChanged, {
2433
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2434
+ updateItemPositions(ctx, dataChanged, {
2225
2435
  doMVCP,
2226
2436
  forceFullUpdate: !!forceFullItemPositions,
2227
2437
  scrollBottomBuffered,
@@ -2240,9 +2450,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2240
2450
  for (let i = loopStart; i >= 0; i--) {
2241
2451
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2242
2452
  const top = positions.get(id);
2243
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2453
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2244
2454
  const bottom = top + size;
2245
- if (bottom > scroll - scrollBuffer) {
2455
+ if (bottom > scroll - scrollBufferTop) {
2246
2456
  loopStart = i;
2247
2457
  } else {
2248
2458
  break;
@@ -2267,7 +2477,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2267
2477
  const dataLength = data.length;
2268
2478
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2269
2479
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2270
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2480
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2271
2481
  const top = positions.get(id);
2272
2482
  if (!foundEnd) {
2273
2483
  if (startNoBuffer === null && top + size > scroll) {
@@ -2279,7 +2489,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2279
2489
  if (startBuffered === null && top + size > scrollTopBuffered) {
2280
2490
  startBuffered = i;
2281
2491
  startBufferedId = id;
2282
- nextTop = top;
2492
+ if (scrollTopBuffered < 0) {
2493
+ nextTop = null;
2494
+ } else {
2495
+ nextTop = top;
2496
+ }
2283
2497
  }
2284
2498
  if (startNoBuffer !== null) {
2285
2499
  if (top <= scrollBottom) {
@@ -2287,7 +2501,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2287
2501
  }
2288
2502
  if (top <= scrollBottomBuffered) {
2289
2503
  endBuffered = i;
2290
- nextBottom = top + size;
2504
+ if (scrollBottomBuffered > totalSize) {
2505
+ nextBottom = null;
2506
+ } else {
2507
+ nextBottom = top + size;
2508
+ }
2291
2509
  } else {
2292
2510
  foundEnd = true;
2293
2511
  }
@@ -2314,7 +2532,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2314
2532
  top: nextTop
2315
2533
  } : void 0;
2316
2534
  }
2317
- const numContainers = peek$(ctx, "numContainers");
2535
+ let numContainers = prevNumContainers;
2318
2536
  const pendingRemoval = [];
2319
2537
  if (dataChanged) {
2320
2538
  for (let i = 0; i < numContainers; i++) {
@@ -2325,7 +2543,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2325
2543
  }
2326
2544
  }
2327
2545
  if (startBuffered !== null && endBuffered !== null) {
2328
- let numContainers2 = prevNumContainers;
2329
2546
  const needNewContainers = [];
2330
2547
  for (let i = startBuffered; i <= endBuffered; i++) {
2331
2548
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
@@ -2336,7 +2553,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2336
2553
  if (stickyIndicesArr.length > 0) {
2337
2554
  handleStickyActivation(
2338
2555
  ctx,
2339
- state,
2340
2556
  stickyIndicesSet,
2341
2557
  stickyIndicesArr,
2342
2558
  currentStickyIdx,
@@ -2344,9 +2560,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2344
2560
  startBuffered,
2345
2561
  endBuffered
2346
2562
  );
2347
- } else {
2348
- state.activeStickyIndex = void 0;
2349
- set$(ctx, "activeStickyIndex", void 0);
2563
+ } else if (previousStickyIndex !== -1) {
2564
+ set$(ctx, "activeStickyIndex", -1);
2350
2565
  }
2351
2566
  if (needNewContainers.length > 0) {
2352
2567
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2355,7 +2570,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2355
2570
  }) : void 0;
2356
2571
  const availableContainers = findAvailableContainers(
2357
2572
  ctx,
2358
- state,
2359
2573
  needNewContainers.length,
2360
2574
  startBuffered,
2361
2575
  endBuffered,
@@ -2377,29 +2591,30 @@ function calculateItemsInView(ctx, state, params = {}) {
2377
2591
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2378
2592
  }
2379
2593
  containerItemKeys.add(id);
2594
+ const containerSticky = `containerSticky${containerIndex}`;
2380
2595
  if (stickyIndicesSet.has(i)) {
2381
- set$(ctx, `containerSticky${containerIndex}`, true);
2596
+ set$(ctx, containerSticky, true);
2382
2597
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2383
2598
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2384
2599
  state.stickyContainerPool.add(containerIndex);
2385
- } else {
2386
- set$(ctx, `containerSticky${containerIndex}`, false);
2600
+ } else if (peek$(ctx, containerSticky)) {
2601
+ set$(ctx, containerSticky, false);
2387
2602
  state.stickyContainerPool.delete(containerIndex);
2388
2603
  }
2389
- if (containerIndex >= numContainers2) {
2390
- numContainers2 = containerIndex + 1;
2604
+ if (containerIndex >= numContainers) {
2605
+ numContainers = containerIndex + 1;
2391
2606
  }
2392
2607
  }
2393
- if (numContainers2 !== prevNumContainers) {
2394
- set$(ctx, "numContainers", numContainers2);
2395
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2396
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2608
+ if (numContainers !== prevNumContainers) {
2609
+ set$(ctx, "numContainers", numContainers);
2610
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2611
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2397
2612
  }
2398
2613
  }
2399
2614
  }
2400
2615
  }
2401
2616
  if (stickyIndicesArr.length > 0) {
2402
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2617
+ handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2403
2618
  }
2404
2619
  let didChangePositions = false;
2405
2620
  for (let i = 0; i < numContainers; i++) {
@@ -2451,7 +2666,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2451
2666
  }
2452
2667
  if (!queuedInitialLayout && endBuffered !== null) {
2453
2668
  if (checkAllSizesKnown(state)) {
2454
- setDidLayout(ctx, state);
2669
+ setDidLayout(ctx);
2455
2670
  }
2456
2671
  }
2457
2672
  if (viewabilityConfigCallbackPairs) {
@@ -2464,8 +2679,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2464
2679
  }
2465
2680
  }
2466
2681
  });
2467
- if (state.initialAnchor) {
2468
- ensureInitialAnchor(ctx, state);
2682
+ if (!IsNewArchitecture && state.initialAnchor) {
2683
+ ensureInitialAnchor(ctx);
2469
2684
  }
2470
2685
  }
2471
2686
 
@@ -2490,19 +2705,22 @@ function checkActualChange(state, dataProp, previousData) {
2490
2705
  }
2491
2706
 
2492
2707
  // src/core/doMaintainScrollAtEnd.ts
2493
- function doMaintainScrollAtEnd(ctx, state, animated) {
2708
+ function doMaintainScrollAtEnd(ctx, animated) {
2709
+ const state = ctx.state;
2494
2710
  const {
2711
+ didContainersLayout,
2712
+ isAtEnd,
2495
2713
  refScroller,
2496
2714
  props: { maintainScrollAtEnd }
2497
2715
  } = state;
2498
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2716
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2499
2717
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2500
2718
  if (paddingTop > 0) {
2501
2719
  state.scroll = 0;
2502
2720
  }
2503
2721
  requestAnimationFrame(() => {
2504
2722
  var _a3;
2505
- if (state == null ? void 0 : state.isAtEnd) {
2723
+ if (state.isAtEnd) {
2506
2724
  state.maintainingScrollAtEnd = true;
2507
2725
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2508
2726
  animated
@@ -2573,28 +2791,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2573
2791
  }
2574
2792
 
2575
2793
  // src/core/checkResetContainers.ts
2576
- function checkResetContainers(ctx, state, dataProp) {
2794
+ function checkResetContainers(ctx, dataProp) {
2795
+ const state = ctx.state;
2577
2796
  const { previousData } = state;
2578
2797
  if (previousData) {
2579
2798
  updateAveragesOnDataChange(state, previousData, dataProp);
2580
2799
  }
2581
2800
  const { maintainScrollAtEnd } = state.props;
2582
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2801
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2583
2802
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2584
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2803
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2585
2804
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2586
2805
  state.isEndReached = false;
2587
2806
  }
2588
2807
  if (!didMaintainScrollAtEnd) {
2589
2808
  checkAtTop(state);
2590
- checkAtBottom(ctx, state);
2809
+ checkAtBottom(ctx);
2591
2810
  }
2592
2811
  delete state.previousData;
2593
2812
  }
2594
2813
 
2595
2814
  // src/core/doInitialAllocateContainers.ts
2596
- function doInitialAllocateContainers(ctx, state) {
2815
+ function doInitialAllocateContainers(ctx) {
2597
2816
  var _a3, _b, _c;
2817
+ const state = ctx.state;
2598
2818
  const {
2599
2819
  scrollLength,
2600
2820
  props: {
@@ -2632,10 +2852,10 @@ function doInitialAllocateContainers(ctx, state) {
2632
2852
  if (!IsNewArchitecture || state.lastLayout) {
2633
2853
  if (state.initialScroll) {
2634
2854
  requestAnimationFrame(() => {
2635
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2855
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2636
2856
  });
2637
2857
  } else {
2638
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2858
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2639
2859
  }
2640
2860
  }
2641
2861
  return true;
@@ -2643,7 +2863,8 @@ function doInitialAllocateContainers(ctx, state) {
2643
2863
  }
2644
2864
 
2645
2865
  // src/core/handleLayout.ts
2646
- function handleLayout(ctx, state, layout, setCanRender) {
2866
+ function handleLayout(ctx, layout, setCanRender) {
2867
+ const state = ctx.state;
2647
2868
  const { maintainScrollAtEnd } = state.props;
2648
2869
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2649
2870
  const previousLength = state.scrollLength;
@@ -2659,19 +2880,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2659
2880
  state.lastBatchingAction = Date.now();
2660
2881
  state.scrollForNextCalculateItemsInView = void 0;
2661
2882
  if (scrollLength > 0) {
2662
- doInitialAllocateContainers(ctx, state);
2883
+ doInitialAllocateContainers(ctx);
2663
2884
  }
2664
2885
  if (needsCalculate) {
2665
- calculateItemsInView(ctx, state, { doMVCP: true });
2886
+ calculateItemsInView(ctx, { doMVCP: true });
2666
2887
  }
2667
2888
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2668
2889
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2669
2890
  }
2670
2891
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2671
- doMaintainScrollAtEnd(ctx, state, false);
2892
+ doMaintainScrollAtEnd(ctx, false);
2672
2893
  }
2673
- updateAlignItemsPaddingTop(ctx, state);
2674
- checkAtBottom(ctx, state);
2894
+ updateAlignItemsPaddingTop(ctx);
2895
+ checkAtBottom(ctx);
2675
2896
  checkAtTop(state);
2676
2897
  if (state) {
2677
2898
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2687,8 +2908,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2687
2908
  }
2688
2909
 
2689
2910
  // src/core/onScroll.ts
2690
- function onScroll(ctx, state, event) {
2911
+ function onScroll(ctx, event) {
2691
2912
  var _a3, _b, _c;
2913
+ const state = ctx.state;
2692
2914
  const {
2693
2915
  scrollProcessingEnabled,
2694
2916
  props: { onScroll: onScrollProp }
@@ -2699,9 +2921,23 @@ function onScroll(ctx, state, event) {
2699
2921
  if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2700
2922
  return;
2701
2923
  }
2702
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2924
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2703
2925
  state.scrollPending = newScroll;
2704
- updateScroll(ctx, state, newScroll);
2926
+ if (state.scrollingTo) {
2927
+ const maxOffset = clampScrollOffset(ctx, newScroll);
2928
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
2929
+ newScroll = maxOffset;
2930
+ scrollTo(ctx, {
2931
+ forceScroll: true,
2932
+ isInitialScroll: true,
2933
+ noScrollingTo: true,
2934
+ offset: newScroll
2935
+ });
2936
+ return;
2937
+ }
2938
+ }
2939
+ updateScroll(ctx, newScroll);
2940
+ checkFinishedScroll(ctx);
2705
2941
  onScrollProp == null ? void 0 : onScrollProp(event);
2706
2942
  }
2707
2943
 
@@ -2710,51 +2946,47 @@ var ScrollAdjustHandler = class {
2710
2946
  constructor(ctx) {
2711
2947
  this.appliedAdjust = 0;
2712
2948
  this.pendingAdjust = 0;
2713
- this.mounted = false;
2714
- this.context = ctx;
2715
- if (Platform2.OS === "web") {
2716
- const commitPendingAdjust = () => {
2717
- const state = this.context.internalState;
2718
- const pending = this.pendingAdjust;
2719
- if (pending !== 0) {
2720
- this.pendingAdjust = 0;
2721
- this.appliedAdjust += pending;
2722
- state.scroll += pending;
2723
- state.scrollForNextCalculateItemsInView = void 0;
2724
- set$(this.context, "scrollAdjustPending", 0);
2725
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2726
- calculateItemsInView(this.context, this.context.internalState);
2727
- }
2728
- };
2729
- listen$(this.context, "scrollingTo", (value) => {
2730
- if (value === void 0) {
2731
- commitPendingAdjust();
2732
- }
2733
- });
2734
- }
2949
+ this.ctx = ctx;
2735
2950
  }
2736
2951
  requestAdjust(add) {
2737
- const scrollingTo = peek$(this.context, "scrollingTo");
2952
+ const scrollingTo = this.ctx.state.scrollingTo;
2738
2953
  if (Platform2.OS === "web" && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2739
2954
  this.pendingAdjust += add;
2740
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
2955
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2741
2956
  } else {
2742
2957
  this.appliedAdjust += add;
2743
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2958
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
2959
+ }
2960
+ if (this.ctx.state.scrollingTo) {
2961
+ checkFinishedScroll(this.ctx);
2744
2962
  }
2745
- }
2746
- setMounted() {
2747
- this.mounted = true;
2748
2963
  }
2749
2964
  getAdjust() {
2750
2965
  return this.appliedAdjust;
2751
2966
  }
2967
+ commitPendingAdjust() {
2968
+ if (Platform2.OS === "web") {
2969
+ const state = this.ctx.state;
2970
+ const pending = this.pendingAdjust;
2971
+ if (pending !== 0) {
2972
+ this.pendingAdjust = 0;
2973
+ this.appliedAdjust += pending;
2974
+ state.scroll += pending;
2975
+ state.scrollForNextCalculateItemsInView = void 0;
2976
+ set$(this.ctx, "scrollAdjustPending", 0);
2977
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
2978
+ calculateItemsInView(this.ctx);
2979
+ }
2980
+ }
2981
+ }
2752
2982
  };
2753
2983
 
2754
2984
  // src/core/updateItemSize.ts
2755
- function updateItemSize(ctx, state, itemKey, sizeObj) {
2985
+ function updateItemSize(ctx, itemKey, sizeObj) {
2756
2986
  var _a3;
2987
+ const state = ctx.state;
2757
2988
  const {
2989
+ didContainersLayout,
2758
2990
  sizesKnown,
2759
2991
  props: {
2760
2992
  getFixedItemSize,
@@ -2782,13 +3014,12 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2782
3014
  return;
2783
3015
  }
2784
3016
  }
2785
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2786
- let needsRecalculate = !containersDidLayout;
3017
+ let needsRecalculate = !didContainersLayout;
2787
3018
  let shouldMaintainScrollAtEnd = false;
2788
3019
  let minIndexSizeChanged;
2789
3020
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2790
3021
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2791
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3022
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
2792
3023
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2793
3024
  if (diff !== 0) {
2794
3025
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
@@ -2837,22 +3068,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2837
3068
  if (!cur || maxOtherAxisSize > cur) {
2838
3069
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
2839
3070
  }
2840
- if (containersDidLayout || checkAllSizesKnown(state)) {
3071
+ if (didContainersLayout || checkAllSizesKnown(state)) {
2841
3072
  if (needsRecalculate) {
2842
3073
  state.scrollForNextCalculateItemsInView = void 0;
2843
- calculateItemsInView(ctx, state, { doMVCP: true });
3074
+ calculateItemsInView(ctx, { doMVCP: true });
2844
3075
  }
2845
3076
  if (shouldMaintainScrollAtEnd) {
2846
3077
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2847
- doMaintainScrollAtEnd(ctx, state, false);
3078
+ doMaintainScrollAtEnd(ctx, false);
2848
3079
  }
2849
3080
  }
2850
3081
  }
2851
3082
  }
2852
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3083
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
2853
3084
  var _a3;
3085
+ const state = ctx.state;
2854
3086
  const {
2855
- sizes,
2856
3087
  indexByKey,
2857
3088
  sizesKnown,
2858
3089
  averageSizes,
@@ -2860,9 +3091,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2860
3091
  } = state;
2861
3092
  if (!data) return 0;
2862
3093
  const index = indexByKey.get(itemKey);
2863
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3094
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
2864
3095
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2865
3096
  const size = Platform2.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
3097
+ const prevSizeKnown = sizesKnown.get(itemKey);
2866
3098
  sizesKnown.set(itemKey, size);
2867
3099
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2868
3100
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -2870,11 +3102,15 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2870
3102
  if (!averages) {
2871
3103
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
2872
3104
  }
2873
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2874
- averages.num++;
3105
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3106
+ averages.avg += (size - prevSizeKnown) / averages.num;
3107
+ } else {
3108
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3109
+ averages.num++;
3110
+ }
2875
3111
  }
2876
3112
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2877
- setSize(ctx, state, itemKey, size);
3113
+ setSize(ctx, itemKey, size);
2878
3114
  return size - prevSize;
2879
3115
  }
2880
3116
  return 0;
@@ -2940,14 +3176,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
2940
3176
  }
2941
3177
 
2942
3178
  // src/utils/createImperativeHandle.ts
2943
- function createImperativeHandle(ctx, state) {
3179
+ function createImperativeHandle(ctx) {
3180
+ const state = ctx.state;
2944
3181
  const scrollIndexIntoView = (options) => {
2945
3182
  if (state) {
2946
3183
  const { index, ...rest } = options;
2947
3184
  const { startNoBuffer, endNoBuffer } = state;
2948
3185
  if (index < startNoBuffer || index > endNoBuffer) {
2949
3186
  const viewPosition = index < startNoBuffer ? 0 : 1;
2950
- scrollToIndex(ctx, state, {
3187
+ scrollToIndex(ctx, {
2951
3188
  ...rest,
2952
3189
  index,
2953
3190
  viewPosition
@@ -2962,7 +3199,7 @@ function createImperativeHandle(ctx, state) {
2962
3199
  getScrollableNode: () => refScroller.current.getScrollableNode(),
2963
3200
  getScrollResponder: () => refScroller.current.getScrollResponder(),
2964
3201
  getState: () => ({
2965
- activeStickyIndex: state.activeStickyIndex,
3202
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
2966
3203
  contentLength: state.totalSize,
2967
3204
  data: state.props.data,
2968
3205
  elementAtIndex: (index) => {
@@ -2973,6 +3210,8 @@ function createImperativeHandle(ctx, state) {
2973
3210
  endBuffered: state.endBuffered,
2974
3211
  isAtEnd: state.isAtEnd,
2975
3212
  isAtStart: state.isAtStart,
3213
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3214
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
2976
3215
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
2977
3216
  positions: state.positions,
2978
3217
  scroll: state.scroll,
@@ -2997,23 +3236,23 @@ function createImperativeHandle(ctx, state) {
2997
3236
  if (index !== -1) {
2998
3237
  const paddingBottom = stylePaddingBottom || 0;
2999
3238
  const footerSize = peek$(ctx, "footerSize") || 0;
3000
- scrollToIndex(ctx, state, {
3239
+ scrollToIndex(ctx, {
3240
+ ...options,
3001
3241
  index,
3002
3242
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3003
- viewPosition: 1,
3004
- ...options
3243
+ viewPosition: 1
3005
3244
  });
3006
3245
  }
3007
3246
  },
3008
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3247
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
3009
3248
  scrollToItem: ({ item, ...props }) => {
3010
3249
  const data = state.props.data;
3011
3250
  const index = data.indexOf(item);
3012
3251
  if (index !== -1) {
3013
- scrollToIndex(ctx, state, { index, ...props });
3252
+ scrollToIndex(ctx, { index, ...props });
3014
3253
  }
3015
3254
  },
3016
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3255
+ scrollToOffset: (params) => scrollTo(ctx, params),
3017
3256
  setScrollProcessingEnabled: (enabled) => {
3018
3257
  state.scrollProcessingEnabled = enabled;
3019
3258
  },
@@ -3023,8 +3262,9 @@ function createImperativeHandle(ctx, state) {
3023
3262
  }
3024
3263
  };
3025
3264
  }
3026
- function getRenderedItem(ctx, state, key) {
3265
+ function getRenderedItem(ctx, key) {
3027
3266
  var _a3;
3267
+ const state = ctx.state;
3028
3268
  if (!state) {
3029
3269
  return null;
3030
3270
  }
@@ -3101,11 +3341,13 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3101
3341
  var DEFAULT_DRAW_DISTANCE = 250;
3102
3342
  var DEFAULT_ITEM_SIZE = 100;
3103
3343
  var LegendList = typedMemo(
3344
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3104
3345
  typedForwardRef(function LegendList2(props, forwardedRef) {
3105
3346
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3106
3347
  const isChildrenMode = children !== void 0 && dataProp === void 0;
3107
3348
  const processedProps = isChildrenMode ? {
3108
3349
  ...restProps,
3350
+ childrenMode: true,
3109
3351
  data: (isArray(children) ? children : React2__namespace.Children.toArray(children)).flat(1),
3110
3352
  renderItem: ({ item }) => item
3111
3353
  } : {
@@ -3122,10 +3364,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3122
3364
  alignItemsAtEnd = false,
3123
3365
  columnWrapperStyle,
3124
3366
  contentContainerStyle: contentContainerStyleProp,
3367
+ contentInset,
3125
3368
  data: dataProp = [],
3126
3369
  dataVersion,
3127
3370
  drawDistance = 250,
3128
- enableAverages = true,
3129
3371
  estimatedItemSize: estimatedItemSizeProp,
3130
3372
  estimatedListSize,
3131
3373
  extraData,
@@ -3167,6 +3409,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3167
3409
  snapToIndices,
3168
3410
  stickyHeaderIndices: stickyHeaderIndicesProp,
3169
3411
  stickyIndices: stickyIndicesDeprecated,
3412
+ // TODOV3: Remove from v3 release
3170
3413
  style: styleProp,
3171
3414
  suggestEstimatedItemSize,
3172
3415
  viewabilityConfig,
@@ -3174,6 +3417,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3174
3417
  waitForInitialLayout = true,
3175
3418
  ...rest
3176
3419
  } = props;
3420
+ const animatedPropsInternal = props.animatedPropsInternal;
3421
+ const { childrenMode } = rest;
3177
3422
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3178
3423
  const style = { ...StyleSheet.flatten(styleProp) };
3179
3424
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
@@ -3197,10 +3442,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3197
3442
  }
3198
3443
  const refState = React2.useRef();
3199
3444
  if (!refState.current) {
3200
- if (!ctx.internalState) {
3445
+ if (!ctx.state) {
3201
3446
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : getWindowSize())[horizontal ? "width" : "height"];
3202
- ctx.internalState = {
3203
- activeStickyIndex: void 0,
3447
+ ctx.state = {
3448
+ activeStickyIndex: -1,
3204
3449
  averageSizes: {},
3205
3450
  columns: /* @__PURE__ */ new Map(),
3206
3451
  containerItemKeys: /* @__PURE__ */ new Set(),
@@ -3226,9 +3471,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3226
3471
  initialScroll: initialScrollProp,
3227
3472
  isAtEnd: false,
3228
3473
  isAtStart: false,
3229
- isEndReached: false,
3474
+ isEndReached: null,
3230
3475
  isFirst: true,
3231
- isStartReached: false,
3476
+ isStartReached: null,
3232
3477
  lastBatchingAction: Date.now(),
3233
3478
  lastLayout: void 0,
3234
3479
  loadStartTime: Date.now(),
@@ -3260,12 +3505,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3260
3505
  totalSize: 0,
3261
3506
  viewabilityConfigCallbackPairs: void 0
3262
3507
  };
3263
- const internalState = ctx.internalState;
3264
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3508
+ const internalState = ctx.state;
3509
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3265
3510
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3266
3511
  set$(ctx, "extraData", extraData);
3267
3512
  }
3268
- refState.current = ctx.internalState;
3513
+ refState.current = ctx.state;
3269
3514
  }
3270
3515
  const state = refState.current;
3271
3516
  const isFirstLocal = state.isFirst;
@@ -3279,9 +3524,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3279
3524
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3280
3525
  state.props = {
3281
3526
  alignItemsAtEnd,
3527
+ animatedProps: animatedPropsInternal,
3528
+ contentInset,
3282
3529
  data: dataProp,
3283
3530
  dataVersion,
3284
- enableAverages,
3285
3531
  estimatedItemSize,
3286
3532
  getEstimatedItemSize,
3287
3533
  getFixedItemSize,
@@ -3324,62 +3570,62 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3324
3570
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3325
3571
  set$(ctx, "numColumns", numColumnsProp);
3326
3572
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3327
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3573
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3328
3574
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3329
3575
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3330
3576
  if (paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3331
3577
  if (state.scroll < 0) {
3332
3578
  paddingDiff += state.scroll;
3333
3579
  }
3334
- requestAdjust(ctx, state, paddingDiff);
3580
+ requestAdjust(ctx, paddingDiff);
3335
3581
  }
3336
3582
  };
3337
3583
  if (isFirstLocal) {
3338
3584
  initializeStateVars();
3339
3585
  updateItemPositions(
3340
3586
  ctx,
3341
- state,
3342
3587
  /*dataChanged*/
3343
3588
  true
3344
3589
  );
3345
3590
  }
3346
3591
  const initialContentOffset = React2.useMemo(() => {
3347
- var _a4, _b2;
3348
- const { initialScroll } = refState.current;
3349
- if (!initialScroll) {
3592
+ var _a4;
3593
+ let value;
3594
+ const { initialScroll, initialAnchor } = refState.current;
3595
+ if (initialScroll) {
3596
+ if (!IsNewArchitecture && initialScroll.index !== void 0 && (!initialAnchor || (initialAnchor == null ? void 0 : initialAnchor.index) !== initialScroll.index)) {
3597
+ refState.current.initialAnchor = {
3598
+ attempts: 0,
3599
+ index: initialScroll.index,
3600
+ settledTicks: 0,
3601
+ viewOffset: (_a4 = initialScroll.viewOffset) != null ? _a4 : 0,
3602
+ viewPosition: initialScroll.viewPosition
3603
+ };
3604
+ }
3605
+ if (initialScroll.contentOffset !== void 0) {
3606
+ value = initialScroll.contentOffset;
3607
+ } else {
3608
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3609
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3610
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3611
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3612
+ refState.current.initialScroll = updatedInitialScroll;
3613
+ state.initialScroll = updatedInitialScroll;
3614
+ value = clampedOffset;
3615
+ }
3616
+ } else {
3350
3617
  refState.current.initialAnchor = void 0;
3351
- return 0;
3352
- }
3353
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3354
- refState.current.initialAnchor = {
3355
- attempts: 0,
3356
- index: initialScroll.index,
3357
- settledTicks: 0,
3358
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3359
- viewPosition: initialScroll.viewPosition
3360
- };
3618
+ value = 0;
3619
+ }
3620
+ if (!value) {
3621
+ state.didFinishInitialScroll = true;
3361
3622
  }
3362
- if (initialScroll.contentOffset !== void 0) {
3363
- return initialScroll.contentOffset;
3364
- }
3365
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3366
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3367
- let clampedOffset = resolvedOffset;
3368
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3369
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3370
- clampedOffset = Math.min(clampedOffset, maxOffset);
3371
- }
3372
- clampedOffset = Math.max(0, clampedOffset);
3373
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3374
- refState.current.initialScroll = updatedInitialScroll;
3375
- state.initialScroll = updatedInitialScroll;
3376
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3377
- return clampedOffset;
3623
+ return value;
3378
3624
  }, [renderNum]);
3379
3625
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3380
3626
  refState.current.lastBatchingAction = Date.now();
3381
3627
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3382
- IS_DEV && warnDevOnce(
3628
+ IS_DEV && !childrenMode && warnDevOnce(
3383
3629
  "keyExtractor",
3384
3630
  "Changing data without a keyExtractor can cause slow performance and resetting scroll. If your list data can change you should use a keyExtractor with a unique id for best performance and behavior."
3385
3631
  );
@@ -3404,12 +3650,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3404
3650
  }
3405
3651
  }, []);
3406
3652
  const doInitialScroll = React2.useCallback(() => {
3407
- var _a4;
3408
3653
  const initialScroll = state.initialScroll;
3409
3654
  if (initialScroll) {
3410
- scrollTo(ctx, state, {
3655
+ scrollTo(ctx, {
3411
3656
  animated: false,
3412
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3657
+ index: initialScroll == null ? void 0 : initialScroll.index,
3413
3658
  isInitialScroll: true,
3414
3659
  offset: initialContentOffset,
3415
3660
  precomputedWithViewOffset: true
@@ -3418,7 +3663,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3418
3663
  }, [initialContentOffset]);
3419
3664
  const onLayoutChange = React2.useCallback((layout) => {
3420
3665
  doInitialScroll();
3421
- handleLayout(ctx, state, layout, setCanRender);
3666
+ handleLayout(ctx, layout, setCanRender);
3422
3667
  }, []);
3423
3668
  const { onLayout } = useOnLayoutSync({
3424
3669
  onLayoutChange,
@@ -3428,7 +3673,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3428
3673
  });
3429
3674
  React2.useLayoutEffect(() => {
3430
3675
  if (snapToIndices) {
3431
- updateSnapToOffsets(ctx, state);
3676
+ updateSnapToOffsets(ctx);
3432
3677
  }
3433
3678
  }, [snapToIndices]);
3434
3679
  React2.useLayoutEffect(() => {
@@ -3438,9 +3683,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3438
3683
  isFirst,
3439
3684
  props: { data }
3440
3685
  } = state;
3441
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3686
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3442
3687
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3443
- checkResetContainers(ctx, state, data);
3688
+ checkResetContainers(ctx, data);
3444
3689
  }
3445
3690
  state.didColumnsChange = false;
3446
3691
  state.didDataChange = false;
@@ -3467,18 +3712,24 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3467
3712
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3468
3713
  if (!IsNewArchitecture) {
3469
3714
  useInit(() => {
3470
- doInitialAllocateContainers(ctx, state);
3715
+ doInitialAllocateContainers(ctx);
3471
3716
  });
3472
3717
  }
3473
- React2.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3718
+ React2.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3474
3719
  if (Platform2.OS === "web") {
3475
3720
  React2.useEffect(doInitialScroll, []);
3476
3721
  }
3477
3722
  const fns = React2.useMemo(
3478
3723
  () => ({
3479
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3480
- onScroll: (event) => onScroll(ctx, state, event),
3481
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3724
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
3725
+ onMomentumScrollEnd: (event) => {
3726
+ checkFinishedScrollFallback(ctx);
3727
+ if (onMomentumScrollEnd) {
3728
+ onMomentumScrollEnd(event);
3729
+ }
3730
+ },
3731
+ onScroll: (event) => onScroll(ctx, event),
3732
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3482
3733
  }),
3483
3734
  []
3484
3735
  );
@@ -3490,6 +3741,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3490
3741
  alignItemsAtEnd,
3491
3742
  canRender,
3492
3743
  contentContainerStyle,
3744
+ contentInset,
3493
3745
  getRenderedItem: fns.getRenderedItem,
3494
3746
  horizontal,
3495
3747
  initialContentOffset,
@@ -3498,20 +3750,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3498
3750
  maintainVisibleContentPosition,
3499
3751
  onLayout,
3500
3752
  onLayoutHeader,
3501
- onMomentumScrollEnd: (event) => {
3502
- if (IsNewArchitecture) {
3503
- requestAnimationFrame(() => {
3504
- finishScrollTo(ctx, refState.current);
3505
- });
3506
- } else {
3507
- setTimeout(() => {
3508
- finishScrollTo(ctx, refState.current);
3509
- }, 1e3);
3510
- }
3511
- if (onMomentumScrollEnd) {
3512
- onMomentumScrollEnd(event);
3513
- }
3514
- },
3753
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3515
3754
  onScroll: onScrollHandler,
3516
3755
  recycleItems,
3517
3756
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2__namespace.cloneElement(refreshControl, {
@@ -3526,7 +3765,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3526
3765
  ),
3527
3766
  refScrollView: combinedRef,
3528
3767
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3529
- scrollEventThrottle: Platform2.OS === "web" ? 16 : void 0,
3768
+ scrollEventThrottle: 0,
3530
3769
  snapToIndices,
3531
3770
  stickyHeaderIndices,
3532
3771
  style,