@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.mjs CHANGED
@@ -7,30 +7,64 @@ import { useSyncExternalStore } from 'use-sync-external-store/shim';
7
7
  Animated.View;
8
8
  var View = View$1;
9
9
  var Text = Text$1;
10
+
11
+ // src/state/getContentInsetEnd.ts
12
+ function getContentInsetEnd(state) {
13
+ var _a3;
14
+ const { props } = state;
15
+ const horizontal = props.horizontal;
16
+ let contentInset = props.contentInset;
17
+ if (!contentInset) {
18
+ const animatedInset = (_a3 = props.animatedProps) == null ? void 0 : _a3.contentInset;
19
+ if (animatedInset) {
20
+ if ("get" in animatedInset) {
21
+ contentInset = animatedInset.get();
22
+ } else {
23
+ contentInset = animatedInset;
24
+ }
25
+ }
26
+ }
27
+ return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
28
+ }
29
+
30
+ // src/state/getContentSize.ts
31
+ function getContentSize(ctx) {
32
+ var _a3;
33
+ const { values, state } = ctx;
34
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
35
+ const stylePaddingBottom = state.props.stylePaddingBottom || 0;
36
+ const headerSize = values.get("headerSize") || 0;
37
+ const footerSize = values.get("footerSize") || 0;
38
+ const contentInsetBottom = getContentInsetEnd(state);
39
+ const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
40
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
41
+ }
10
42
  var createAnimatedValue = (value) => new Animated.Value(value);
11
43
 
12
44
  // src/state/state.tsx
13
45
  var ContextState = React2.createContext(null);
46
+ var contextNum = 0;
14
47
  function StateProvider({ children }) {
15
48
  const [value] = React2.useState(() => ({
16
49
  animatedScrollY: createAnimatedValue(0),
17
50
  columnWrapperStyle: void 0,
18
- internalState: void 0,
51
+ contextNum: contextNum++,
19
52
  listeners: /* @__PURE__ */ new Map(),
20
53
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
21
54
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
22
55
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
23
56
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
24
57
  mapViewabilityValues: /* @__PURE__ */ new Map(),
58
+ positionListeners: /* @__PURE__ */ new Map(),
59
+ state: void 0,
25
60
  values: /* @__PURE__ */ new Map([
26
61
  ["alignItemsPaddingTop", 0],
27
62
  ["stylePaddingTop", 0],
28
63
  ["headerSize", 0],
29
64
  ["numContainers", 0],
30
- ["activeStickyIndex", void 0],
65
+ ["activeStickyIndex", -1],
31
66
  ["totalSize", 0],
32
- ["scrollAdjustPending", 0],
33
- ["scrollingTo", void 0]
67
+ ["scrollAdjustPending", 0]
34
68
  ]),
35
69
  viewRefs: /* @__PURE__ */ new Map()
36
70
  }));
@@ -98,15 +132,24 @@ function set$(ctx, signalName, value) {
98
132
  }
99
133
  }
100
134
  }
101
- function getContentSize(ctx) {
102
- var _a3, _b;
103
- const { values, internalState } = ctx;
104
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
105
- const stylePaddingBottom = (internalState == null ? void 0 : internalState.props.stylePaddingBottom) || 0;
106
- const headerSize = values.get("headerSize") || 0;
107
- const footerSize = values.get("footerSize") || 0;
108
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
109
- return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom;
135
+ function listenPosition$(ctx, key, cb) {
136
+ const { positionListeners } = ctx;
137
+ let setListeners = positionListeners.get(key);
138
+ if (!setListeners) {
139
+ setListeners = /* @__PURE__ */ new Set();
140
+ positionListeners.set(key, setListeners);
141
+ }
142
+ setListeners.add(cb);
143
+ return () => setListeners.delete(cb);
144
+ }
145
+ function notifyPosition$(ctx, key, value) {
146
+ const { positionListeners } = ctx;
147
+ const setListeners = positionListeners.get(key);
148
+ if (setListeners) {
149
+ for (const listener of setListeners) {
150
+ listener(value);
151
+ }
152
+ }
110
153
  }
111
154
  function useArr$(signalNames) {
112
155
  const ctx = React2.useContext(ContextState);
@@ -187,7 +230,8 @@ var ENABLE_DEBUG_VIEW = IS_DEV && false;
187
230
  // src/constants-platform.native.ts
188
231
  var IsNewArchitecture = global.nativeFabricUIManager != null;
189
232
  var useAnimatedValue = (initialValue) => {
190
- return useRef(new Animated.Value(initialValue)).current;
233
+ const [animAnimatedValue] = useState(() => new Animated.Value(initialValue));
234
+ return animAnimatedValue;
191
235
  };
192
236
 
193
237
  // src/utils/helpers.ts
@@ -276,7 +320,7 @@ var typedForwardRef = forwardRef;
276
320
  var typedMemo = memo;
277
321
 
278
322
  // src/components/PositionView.native.tsx
279
- var PositionViewState = typedMemo(function PositionView({
323
+ var PositionViewState = typedMemo(function PositionViewState2({
280
324
  id,
281
325
  horizontal,
282
326
  style,
@@ -296,7 +340,7 @@ var PositionViewState = typedMemo(function PositionView({
296
340
  }
297
341
  );
298
342
  });
299
- var PositionViewAnimated = typedMemo(function PositionView2({
343
+ var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
300
344
  id,
301
345
  horizontal,
302
346
  style,
@@ -339,60 +383,77 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
339
383
  const viewStyle = React2.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
340
384
  return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: viewStyle, ...rest });
341
385
  });
342
- var PositionView3 = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
343
- var symbolFirst = Symbol();
386
+ var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
344
387
  function useInit(cb) {
345
- const refValue = useRef(symbolFirst);
346
- if (refValue.current === symbolFirst) {
347
- refValue.current = cb();
348
- }
349
- return refValue.current;
388
+ useState(() => cb());
350
389
  }
351
390
 
352
391
  // src/state/ContextContainer.ts
353
392
  var ContextContainer = createContext(null);
393
+ function useContextContainer() {
394
+ return useContext(ContextContainer);
395
+ }
354
396
  function useViewability(callback, configId) {
355
397
  const ctx = useStateContext();
356
- const { containerId } = useContext(ContextContainer);
357
- const key = containerId + (configId != null ? configId : "");
398
+ const containerContext = useContextContainer();
358
399
  useInit(() => {
400
+ if (!containerContext) {
401
+ return;
402
+ }
403
+ const { containerId } = containerContext;
404
+ const key = containerId + (configId != null ? configId : "");
359
405
  const value = ctx.mapViewabilityValues.get(key);
360
406
  if (value) {
361
407
  callback(value);
362
408
  }
363
409
  });
364
- ctx.mapViewabilityCallbacks.set(key, callback);
365
- useEffect(
366
- () => () => {
410
+ useEffect(() => {
411
+ if (!containerContext) {
412
+ return;
413
+ }
414
+ const { containerId } = containerContext;
415
+ const key = containerId + (configId != null ? configId : "");
416
+ ctx.mapViewabilityCallbacks.set(key, callback);
417
+ return () => {
367
418
  ctx.mapViewabilityCallbacks.delete(key);
368
- },
369
- []
370
- );
419
+ };
420
+ }, [ctx, callback, configId, containerContext]);
371
421
  }
372
422
  function useViewabilityAmount(callback) {
373
423
  const ctx = useStateContext();
374
- const { containerId } = useContext(ContextContainer);
424
+ const containerContext = useContextContainer();
375
425
  useInit(() => {
426
+ if (!containerContext) {
427
+ return;
428
+ }
429
+ const { containerId } = containerContext;
376
430
  const value = ctx.mapViewabilityAmountValues.get(containerId);
377
431
  if (value) {
378
432
  callback(value);
379
433
  }
380
434
  });
381
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
382
- useEffect(
383
- () => () => {
435
+ useEffect(() => {
436
+ if (!containerContext) {
437
+ return;
438
+ }
439
+ const { containerId } = containerContext;
440
+ ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
441
+ return () => {
384
442
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
385
- },
386
- []
387
- );
443
+ };
444
+ }, [ctx, callback, containerContext]);
388
445
  }
389
446
  function useRecyclingEffect(effect) {
390
- const { index, value } = useContext(ContextContainer);
447
+ const containerContext = useContextContainer();
391
448
  const prevValues = useRef({
392
449
  prevIndex: void 0,
393
450
  prevItem: void 0
394
451
  });
395
452
  useEffect(() => {
453
+ if (!containerContext) {
454
+ return;
455
+ }
456
+ const { index, value } = containerContext;
396
457
  let ret;
397
458
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
398
459
  ret = effect({
@@ -407,38 +468,58 @@ function useRecyclingEffect(effect) {
407
468
  prevItem: value
408
469
  };
409
470
  return ret;
410
- }, [index, value, effect]);
471
+ }, [effect, containerContext]);
411
472
  }
412
473
  function useRecyclingState(valueOrFun) {
413
- const { index, value, itemKey, triggerLayout } = useContext(ContextContainer);
414
- const refState = useRef({
415
- itemKey: null,
416
- value: null
474
+ var _a3, _b;
475
+ const containerContext = useContextContainer();
476
+ const computeValue = (ctx) => {
477
+ if (isFunction(valueOrFun)) {
478
+ const initializer = valueOrFun;
479
+ return ctx ? initializer({
480
+ index: ctx.index,
481
+ item: ctx.value,
482
+ prevIndex: void 0,
483
+ prevItem: void 0
484
+ }) : initializer();
485
+ }
486
+ return valueOrFun;
487
+ };
488
+ const [stateValue, setStateValue] = useState(() => {
489
+ return computeValue(containerContext);
417
490
  });
418
- const [_, setRenderNum] = useState(0);
419
- const state = refState.current;
420
- if (state.itemKey !== itemKey) {
421
- state.itemKey = itemKey;
422
- state.value = isFunction(valueOrFun) ? valueOrFun({
423
- index,
424
- item: value,
425
- prevIndex: void 0,
426
- prevItem: void 0
427
- }) : valueOrFun;
491
+ const prevItemKeyRef = useRef((_a3 = containerContext == null ? void 0 : containerContext.itemKey) != null ? _a3 : null);
492
+ const currentItemKey = (_b = containerContext == null ? void 0 : containerContext.itemKey) != null ? _b : null;
493
+ if (currentItemKey !== null && prevItemKeyRef.current !== currentItemKey) {
494
+ prevItemKeyRef.current = currentItemKey;
495
+ setStateValue(computeValue(containerContext));
428
496
  }
497
+ const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
429
498
  const setState = useCallback(
430
499
  (newState) => {
431
- state.value = isFunction(newState) ? newState(state.value) : newState;
432
- setRenderNum((v) => v + 1);
500
+ if (!triggerLayout) {
501
+ return;
502
+ }
503
+ setStateValue((prevValue) => {
504
+ return isFunction(newState) ? newState(prevValue) : newState;
505
+ });
433
506
  triggerLayout();
434
507
  },
435
- [triggerLayout, state]
508
+ [triggerLayout]
436
509
  );
437
- return [state.value, setState];
510
+ return [stateValue, setState];
438
511
  }
439
512
  function useIsLastItem() {
440
- const { itemKey } = useContext(ContextContainer);
441
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
513
+ const containerContext = useContextContainer();
514
+ const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
515
+ if (containerContext) {
516
+ const { itemKey } = containerContext;
517
+ if (!isNullOrUndefined(itemKey)) {
518
+ return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
519
+ }
520
+ }
521
+ return false;
522
+ });
442
523
  return isLast;
443
524
  }
444
525
  function useListScrollSize() {
@@ -448,8 +529,9 @@ function useListScrollSize() {
448
529
  var noop = () => {
449
530
  };
450
531
  function useSyncLayout() {
451
- if (IsNewArchitecture) {
452
- const { triggerLayout: syncLayout } = useContext(ContextContainer);
532
+ const containerContext = useContextContainer();
533
+ if (IsNewArchitecture && containerContext) {
534
+ const { triggerLayout: syncLayout } = containerContext;
453
535
  return syncLayout;
454
536
  } else {
455
537
  return noop;
@@ -612,6 +694,7 @@ var Container = typedMemo(function Container2({
612
694
  if (!IsNewArchitecture) {
613
695
  useEffect(() => {
614
696
  if (!isNullOrUndefined(itemKey)) {
697
+ didLayoutRef.current = false;
615
698
  const timeout = setTimeout(() => {
616
699
  if (!didLayoutRef.current) {
617
700
  const {
@@ -631,7 +714,7 @@ var Container = typedMemo(function Container2({
631
714
  }
632
715
  }, [itemKey]);
633
716
  }
634
- const PositionComponent = isSticky ? PositionViewSticky : PositionView3;
717
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
635
718
  return /* @__PURE__ */ React2.createElement(
636
719
  PositionComponent,
637
720
  {
@@ -666,10 +749,10 @@ var Containers = typedMemo(function Containers2({
666
749
  // If this is the initial scroll, we don't want to delay because we want to update the size immediately
667
750
  delay: (value, prevValue) => {
668
751
  var _a3;
669
- return !((_a3 = ctx.internalState) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
752
+ return !((_a3 = ctx.state) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
670
753
  }
671
754
  });
672
- const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("containersDidLayout", { getValue: (value) => value ? 1 : 0 }) : void 0;
755
+ const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("readyToRender", { getValue: (value) => value ? 1 : 0 }) : void 0;
673
756
  const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
674
757
  const containers = [];
675
758
  for (let i = 0; i < numContainers; i++) {
@@ -712,7 +795,8 @@ var Containers = typedMemo(function Containers2({
712
795
  return /* @__PURE__ */ React2.createElement(Animated.View, { style }, containers);
713
796
  });
714
797
  function DevNumbers() {
715
- return IS_DEV && React2.memo(function DevNumbers2() {
798
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
799
+ React2.memo(function DevNumbers2() {
716
800
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React2.createElement(
717
801
  View$1,
718
802
  {
@@ -820,13 +904,6 @@ var ListComponent = typedMemo(function ListComponent2({
820
904
  () => React2.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
821
905
  [renderScrollComponent]
822
906
  ) : ListComponentScrollView;
823
- React2.useEffect(() => {
824
- if (canRender) {
825
- setTimeout(() => {
826
- scrollAdjustHandler.setMounted();
827
- }, 0);
828
- }
829
- }, [canRender]);
830
907
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
831
908
  return /* @__PURE__ */ React2.createElement(
832
909
  SnapOrScroll,
@@ -890,10 +967,11 @@ function getId(state, index) {
890
967
  }
891
968
 
892
969
  // src/core/calculateOffsetForIndex.ts
893
- function calculateOffsetForIndex(ctx, state, index) {
970
+ function calculateOffsetForIndex(ctx, index) {
971
+ const state = ctx.state;
894
972
  let position = 0;
895
973
  if (index !== void 0) {
896
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
974
+ position = state.positions.get(getId(state, index)) || 0;
897
975
  const paddingTop = peek$(ctx, "stylePaddingTop");
898
976
  if (paddingTop) {
899
977
  position += paddingTop;
@@ -907,7 +985,8 @@ function calculateOffsetForIndex(ctx, state, index) {
907
985
  }
908
986
 
909
987
  // src/utils/setPaddingTop.ts
910
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
988
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
989
+ const state = ctx.state;
911
990
  if (stylePaddingTop !== void 0) {
912
991
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
913
992
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -926,7 +1005,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
926
1005
  }
927
1006
 
928
1007
  // src/utils/updateAlignItemsPaddingTop.ts
929
- function updateAlignItemsPaddingTop(ctx, state) {
1008
+ function updateAlignItemsPaddingTop(ctx) {
1009
+ const state = ctx.state;
930
1010
  const {
931
1011
  scrollLength,
932
1012
  props: { alignItemsAtEnd, data }
@@ -937,12 +1017,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
937
1017
  const contentSize = getContentSize(ctx);
938
1018
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
939
1019
  }
940
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1020
+ setPaddingTop(ctx, { alignItemsPaddingTop });
941
1021
  }
942
1022
  }
943
1023
 
944
1024
  // src/core/addTotalSize.ts
945
- function addTotalSize(ctx, state, key, add) {
1025
+ function addTotalSize(ctx, key, add) {
1026
+ const state = ctx.state;
946
1027
  const { alignItemsAtEnd } = state.props;
947
1028
  const prevTotalSize = state.totalSize;
948
1029
  let totalSize = state.totalSize;
@@ -963,31 +1044,34 @@ function addTotalSize(ctx, state, key, add) {
963
1044
  state.totalSize = totalSize;
964
1045
  set$(ctx, "totalSize", totalSize);
965
1046
  if (alignItemsAtEnd) {
966
- updateAlignItemsPaddingTop(ctx, state);
1047
+ updateAlignItemsPaddingTop(ctx);
967
1048
  }
968
1049
  }
969
1050
  }
970
1051
  }
971
1052
 
972
1053
  // src/core/setSize.ts
973
- function setSize(ctx, state, itemKey, size) {
1054
+ function setSize(ctx, itemKey, size) {
1055
+ const state = ctx.state;
974
1056
  const { sizes } = state;
975
1057
  const previousSize = sizes.get(itemKey);
976
1058
  const diff = previousSize !== void 0 ? size - previousSize : size;
977
1059
  if (diff !== 0) {
978
- addTotalSize(ctx, state, itemKey, diff);
1060
+ addTotalSize(ctx, itemKey, diff);
979
1061
  }
980
1062
  sizes.set(itemKey, size);
981
1063
  }
982
1064
 
983
1065
  // src/utils/getItemSize.ts
984
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1066
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
985
1067
  var _a3, _b;
1068
+ const state = ctx.state;
986
1069
  const {
987
1070
  sizesKnown,
988
1071
  sizes,
989
1072
  averageSizes,
990
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1073
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1074
+ scrollingTo
991
1075
  } = state;
992
1076
  const sizeKnown = sizesKnown.get(key);
993
1077
  if (sizeKnown !== void 0) {
@@ -995,7 +1079,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
995
1079
  }
996
1080
  let size;
997
1081
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
998
- const scrollingTo = peek$(ctx, "scrollingTo");
999
1082
  if (preferCachedSize) {
1000
1083
  const cachedSize = sizes.get(key);
1001
1084
  if (cachedSize !== void 0) {
@@ -1023,84 +1106,167 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1023
1106
  if (size === void 0) {
1024
1107
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1025
1108
  }
1026
- setSize(ctx, state, key, size);
1109
+ setSize(ctx, key, size);
1027
1110
  return size;
1028
1111
  }
1029
1112
 
1030
1113
  // src/core/calculateOffsetWithOffsetPosition.ts
1031
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1114
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1115
+ const state = ctx.state;
1032
1116
  const { index, viewOffset, viewPosition } = params;
1033
1117
  let offset = offsetParam;
1034
1118
  if (viewOffset) {
1035
1119
  offset -= viewOffset;
1036
1120
  }
1037
1121
  if (viewPosition !== void 0 && index !== void 0) {
1038
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1122
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1123
+ const trailingInset = getContentInsetEnd(state);
1124
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1039
1125
  }
1040
1126
  return offset;
1041
1127
  }
1042
1128
 
1129
+ // src/core/clampScrollOffset.ts
1130
+ function clampScrollOffset(ctx, offset) {
1131
+ const state = ctx.state;
1132
+ const contentSize = getContentSize(ctx);
1133
+ let clampedOffset = offset;
1134
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1135
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1136
+ clampedOffset = Math.min(offset, maxOffset);
1137
+ }
1138
+ clampedOffset = Math.max(0, clampedOffset);
1139
+ return clampedOffset;
1140
+ }
1141
+ var Platform2 = Platform;
1142
+
1143
+ // src/utils/setInitialRenderState.ts
1144
+ function setInitialRenderState(ctx, {
1145
+ didLayout,
1146
+ didInitialScroll
1147
+ }) {
1148
+ const { state } = ctx;
1149
+ if (didLayout) {
1150
+ state.didContainersLayout = true;
1151
+ }
1152
+ if (didInitialScroll) {
1153
+ state.didFinishInitialScroll = true;
1154
+ }
1155
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1156
+ set$(ctx, "readyToRender", true);
1157
+ }
1158
+ }
1159
+
1043
1160
  // src/core/finishScrollTo.ts
1044
- function finishScrollTo(ctx, state) {
1161
+ function finishScrollTo(ctx) {
1045
1162
  var _a3, _b;
1046
- if (state) {
1163
+ const state = ctx.state;
1164
+ if (state == null ? void 0 : state.scrollingTo) {
1047
1165
  state.scrollHistory.length = 0;
1048
1166
  state.initialScroll = void 0;
1049
1167
  state.initialAnchor = void 0;
1050
- set$(ctx, "scrollingTo", void 0);
1168
+ state.scrollingTo = void 0;
1051
1169
  if (state.pendingTotalSize !== void 0) {
1052
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1170
+ addTotalSize(ctx, null, state.pendingTotalSize);
1053
1171
  }
1054
1172
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1055
1173
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1056
1174
  }
1175
+ if (Platform2.OS === "web") {
1176
+ state.scrollAdjustHandler.commitPendingAdjust();
1177
+ }
1178
+ setInitialRenderState(ctx, { didInitialScroll: true });
1057
1179
  }
1058
1180
  }
1059
- var Platform2 = Platform;
1060
1181
 
1061
- // src/core/scrollTo.ts
1062
- function scrollTo(ctx, state, params) {
1182
+ // src/core/checkFinishedScroll.ts
1183
+ function checkFinishedScroll(ctx) {
1184
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1185
+ }
1186
+ function checkFinishedScrollFrame(ctx) {
1187
+ const scrollingTo = ctx.state.scrollingTo;
1188
+ if (scrollingTo) {
1189
+ const { state } = ctx;
1190
+ state.animFrameCheckFinishedScroll = void 0;
1191
+ const scroll = state.scroll;
1192
+ const adjust = state.scrollAdjustHandler.getAdjust();
1193
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
1194
+ const maxOffset = clampScrollOffset(ctx, scroll);
1195
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
1196
+ const diff2 = Math.abs(diff1 - adjust);
1197
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
1198
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
1199
+ finishScrollTo(ctx);
1200
+ }
1201
+ }
1202
+ }
1203
+ function checkFinishedScrollFallback(ctx) {
1204
+ const state = ctx.state;
1205
+ const scrollingTo = state.scrollingTo;
1206
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
1207
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
1208
+ () => {
1209
+ let numChecks = 0;
1210
+ const checkHasScrolled = () => {
1211
+ state.timeoutCheckFinishedScrollFallback = void 0;
1212
+ const isStillScrollingTo = state.scrollingTo;
1213
+ if (isStillScrollingTo) {
1214
+ numChecks++;
1215
+ if (state.hasScrolled || numChecks > 5) {
1216
+ finishScrollTo(ctx);
1217
+ } else {
1218
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
1219
+ }
1220
+ }
1221
+ };
1222
+ checkHasScrolled();
1223
+ },
1224
+ slowTimeout ? 500 : 100
1225
+ );
1226
+ }
1227
+
1228
+ // src/core/doScrollTo.native.ts
1229
+ function doScrollTo(ctx, params) {
1063
1230
  var _a3;
1064
- const { noScrollingTo, ...scrollTarget } = params;
1231
+ const state = ctx.state;
1232
+ const { animated, horizontal, offset } = params;
1233
+ const { refScroller } = state;
1234
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1235
+ animated: !!animated,
1236
+ x: horizontal ? offset : 0,
1237
+ y: horizontal ? 0 : offset
1238
+ });
1239
+ if (!animated) {
1240
+ state.scroll = offset;
1241
+ checkFinishedScrollFallback(ctx);
1242
+ }
1243
+ }
1244
+
1245
+ // src/core/scrollTo.ts
1246
+ function scrollTo(ctx, params) {
1247
+ const state = ctx.state;
1248
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1065
1249
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1066
1250
  const {
1067
- refScroller,
1068
1251
  props: { horizontal }
1069
1252
  } = state;
1070
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1071
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1072
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1073
- offset = Math.min(offset, maxOffset);
1253
+ if (state.animFrameCheckFinishedScroll) {
1254
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1074
1255
  }
1256
+ if (state.timeoutCheckFinishedScrollFallback) {
1257
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1258
+ }
1259
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1260
+ offset = clampScrollOffset(ctx, offset);
1075
1261
  state.scrollHistory.length = 0;
1076
1262
  if (!noScrollingTo) {
1077
- set$(ctx, "scrollingTo", scrollTarget);
1263
+ state.scrollingTo = scrollTarget;
1078
1264
  }
1079
1265
  state.scrollPending = offset;
1080
- if (!isInitialScroll || Platform2.OS === "android") {
1081
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1082
- animated: !!animated,
1083
- x: horizontal ? offset : 0,
1084
- y: horizontal ? 0 : offset
1085
- });
1086
- }
1087
- if (!animated) {
1266
+ if (forceScroll || !isInitialScroll || Platform2.OS === "android") {
1267
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1268
+ } else {
1088
1269
  state.scroll = offset;
1089
- if (Platform2.OS === "web") {
1090
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1091
- if (value && peek$(ctx, "scrollingTo")) {
1092
- finishScrollTo(ctx, state);
1093
- unlisten();
1094
- }
1095
- });
1096
- } else {
1097
- setTimeout(() => finishScrollTo(ctx, state), 100);
1098
- }
1099
- if (isInitialScroll) {
1100
- setTimeout(() => {
1101
- state.initialScroll = void 0;
1102
- }, 500);
1103
- }
1104
1270
  }
1105
1271
  }
1106
1272
 
@@ -1109,6 +1275,12 @@ var HYSTERESIS_MULTIPLIER = 1.3;
1109
1275
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1110
1276
  const absDistance = Math.abs(distance);
1111
1277
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1278
+ if (wasReached === null) {
1279
+ if (!within && distance >= 0) {
1280
+ return false;
1281
+ }
1282
+ return null;
1283
+ }
1112
1284
  const updateSnapshot = () => {
1113
1285
  setSnapshot == null ? void 0 : setSnapshot({
1114
1286
  atThreshold,
@@ -1141,8 +1313,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1141
1313
  };
1142
1314
 
1143
1315
  // src/utils/checkAtBottom.ts
1144
- function checkAtBottom(ctx, state) {
1316
+ function checkAtBottom(ctx) {
1145
1317
  var _a3;
1318
+ const state = ctx.state;
1146
1319
  if (!state) {
1147
1320
  return;
1148
1321
  }
@@ -1215,15 +1388,15 @@ function checkAtTop(state) {
1215
1388
  }
1216
1389
 
1217
1390
  // src/core/updateScroll.ts
1218
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1391
+ function updateScroll(ctx, newScroll, forceUpdate) {
1219
1392
  var _a3;
1220
- const scrollingTo = peek$(ctx, "scrollingTo");
1393
+ const state = ctx.state;
1394
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1221
1395
  state.hasScrolled = true;
1222
1396
  state.lastBatchingAction = Date.now();
1223
1397
  const currentTime = Date.now();
1224
- const adjust = state.scrollAdjustHandler.getAdjust();
1225
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1226
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1398
+ const adjust = scrollAdjustHandler.getAdjust();
1399
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1227
1400
  if (adjustChanged) {
1228
1401
  state.scrollHistory.length = 0;
1229
1402
  }
@@ -1248,22 +1421,26 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1248
1421
  return;
1249
1422
  }
1250
1423
  }
1251
- if (forceUpdate || state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1424
+ const lastCalculated = state.scrollLastCalculate;
1425
+ const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1426
+ if (shouldUpdate) {
1427
+ state.scrollLastCalculate = state.scroll;
1252
1428
  state.ignoreScrollFromMVCPIgnored = false;
1253
1429
  (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1254
- checkAtBottom(ctx, state);
1430
+ checkAtBottom(ctx);
1255
1431
  checkAtTop(state);
1256
1432
  state.dataChangeNeedsScrollUpdate = false;
1257
1433
  }
1258
1434
  }
1259
1435
 
1260
1436
  // src/utils/requestAdjust.ts
1261
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1437
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1438
+ const state = ctx.state;
1262
1439
  if (Math.abs(positionDiff) > 0.1) {
1263
1440
  const needsScrollWorkaround = Platform2.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
1264
1441
  const doit = () => {
1265
1442
  if (needsScrollWorkaround) {
1266
- scrollTo(ctx, state, {
1443
+ scrollTo(ctx, {
1267
1444
  noScrollingTo: true,
1268
1445
  offset: state.scroll
1269
1446
  });
@@ -1276,8 +1453,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1276
1453
  };
1277
1454
  state.scroll += positionDiff;
1278
1455
  state.scrollForNextCalculateItemsInView = void 0;
1279
- const didLayout = peek$(ctx, "containersDidLayout");
1280
- if (didLayout) {
1456
+ const readyToRender = peek$(ctx, "readyToRender");
1457
+ if (readyToRender) {
1281
1458
  doit();
1282
1459
  if (Platform2.OS !== "web") {
1283
1460
  const threshold = state.scroll - positionDiff / 2;
@@ -1299,7 +1476,7 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1299
1476
  if (shouldForceUpdate) {
1300
1477
  state.ignoreScrollFromMVCPIgnored = false;
1301
1478
  state.scrollPending = state.scroll;
1302
- updateScroll(ctx, state, state.scroll, true);
1479
+ updateScroll(ctx, state.scroll, true);
1303
1480
  }
1304
1481
  }, delay);
1305
1482
  }
@@ -1314,28 +1491,27 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1314
1491
  var INITIAL_ANCHOR_TOLERANCE = 0.5;
1315
1492
  var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1316
1493
  var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1317
- function ensureInitialAnchor(ctx, state) {
1494
+ function ensureInitialAnchor(ctx) {
1318
1495
  var _a3, _b, _c, _d, _e;
1319
- const anchor = state.initialAnchor;
1496
+ const state = ctx.state;
1497
+ const { initialAnchor, didContainersLayout, positions, scroll, scrollLength } = state;
1498
+ const anchor = initialAnchor;
1320
1499
  const item = state.props.data[anchor.index];
1321
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1322
- if (!containersDidLayout) {
1500
+ if (!didContainersLayout) {
1323
1501
  return;
1324
1502
  }
1325
1503
  const id = getId(state, anchor.index);
1326
- if (state.positions.get(id) === void 0) {
1504
+ if (positions.get(id) === void 0) {
1327
1505
  return;
1328
1506
  }
1329
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1507
+ const size = getItemSize(ctx, id, anchor.index, item, true, true);
1330
1508
  if (size === void 0) {
1331
1509
  return;
1332
1510
  }
1333
- const availableSpace = Math.max(0, state.scrollLength - size);
1334
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1335
- const contentSize = getContentSize(ctx);
1336
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1337
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1338
- const delta = clampedDesiredOffset - state.scroll;
1511
+ const availableSpace = Math.max(0, scrollLength - size);
1512
+ const desiredOffset = calculateOffsetForIndex(ctx, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1513
+ const clampedDesiredOffset = clampScrollOffset(ctx, desiredOffset);
1514
+ const delta = clampedDesiredOffset - scroll;
1339
1515
  if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1340
1516
  const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1341
1517
  if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
@@ -1359,18 +1535,21 @@ function ensureInitialAnchor(ctx, state) {
1359
1535
  lastDelta: delta,
1360
1536
  settledTicks: 0
1361
1537
  });
1362
- requestAdjust(ctx, state, delta);
1538
+ requestAdjust(ctx, delta);
1539
+ requestAnimationFrame(() => finishScrollTo(ctx));
1363
1540
  }
1364
1541
 
1365
1542
  // src/core/mvcp.ts
1366
- function prepareMVCP(ctx, state, dataChanged) {
1543
+ function prepareMVCP(ctx, dataChanged) {
1544
+ const state = ctx.state;
1367
1545
  const { idsInView, positions, props } = state;
1368
1546
  const { maintainVisibleContentPosition } = props;
1369
- const scrollingTo = peek$(ctx, "scrollingTo");
1547
+ const scrollingTo = state.scrollingTo;
1370
1548
  let prevPosition;
1371
1549
  let targetId;
1372
1550
  const idsInViewWithPositions = [];
1373
1551
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1552
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1374
1553
  const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1375
1554
  const indexByKey = state.indexByKey;
1376
1555
  if (shouldMVCP) {
@@ -1379,7 +1558,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1379
1558
  return void 0;
1380
1559
  }
1381
1560
  targetId = getId(state, scrollTarget);
1382
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1561
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1383
1562
  if (dataChanged) {
1384
1563
  for (let i = 0; i < idsInView.length; i++) {
1385
1564
  const id = idsInView[i];
@@ -1396,7 +1575,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1396
1575
  prevPosition = positions.get(targetId);
1397
1576
  }
1398
1577
  return () => {
1399
- let positionDiff;
1578
+ let positionDiff = 0;
1400
1579
  if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1401
1580
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1402
1581
  const { id, position } = idsInViewWithPositions[i];
@@ -1422,16 +1601,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1422
1601
  positionDiff = diff;
1423
1602
  }
1424
1603
  }
1425
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1426
- requestAdjust(ctx, state, positionDiff, dataChanged && maintainVisibleContentPosition);
1604
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1605
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1606
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1607
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1608
+ const diff = newSize - prevSize;
1609
+ if (diff !== 0) {
1610
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1611
+ scrollingTo.itemSize = newSize;
1612
+ }
1613
+ }
1614
+ }
1615
+ if (Math.abs(positionDiff) > 0.1) {
1616
+ requestAdjust(ctx, positionDiff, dataChanged && maintainVisibleContentPosition);
1427
1617
  }
1428
1618
  };
1429
1619
  }
1430
1620
  }
1431
1621
 
1432
1622
  // src/core/prepareColumnStartState.ts
1433
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1623
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1434
1624
  var _a3;
1625
+ const state = ctx.state;
1435
1626
  const numColumns = peek$(ctx, "numColumns");
1436
1627
  let rowStartIndex = startIndex;
1437
1628
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1446,7 +1637,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1446
1637
  const prevId = state.idCache[prevIndex];
1447
1638
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1448
1639
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1449
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1640
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1450
1641
  currentRowTop = prevPosition + prevRowHeight;
1451
1642
  }
1452
1643
  return {
@@ -1469,7 +1660,8 @@ function findRowStartIndex(state, numColumns, index) {
1469
1660
  }
1470
1661
  return rowStart;
1471
1662
  }
1472
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1663
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1664
+ const state = ctx.state;
1473
1665
  if (endIndex < startIndex) {
1474
1666
  return 0;
1475
1667
  }
@@ -1483,7 +1675,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1483
1675
  continue;
1484
1676
  }
1485
1677
  const id = state.idCache[i];
1486
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1678
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1487
1679
  if (size > maxSize) {
1488
1680
  maxSize = size;
1489
1681
  }
@@ -1492,22 +1684,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1492
1684
  }
1493
1685
 
1494
1686
  // src/core/updateTotalSize.ts
1495
- function updateTotalSize(ctx, state) {
1687
+ function updateTotalSize(ctx) {
1688
+ const state = ctx.state;
1496
1689
  const {
1497
1690
  positions,
1498
1691
  props: { data }
1499
1692
  } = state;
1500
1693
  if (data.length === 0) {
1501
- addTotalSize(ctx, state, null, 0);
1694
+ addTotalSize(ctx, null, 0);
1502
1695
  } else {
1503
1696
  const lastId = getId(state, data.length - 1);
1504
1697
  if (lastId !== void 0) {
1505
1698
  const lastPosition = positions.get(lastId);
1506
1699
  if (lastPosition !== void 0) {
1507
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1700
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1508
1701
  if (lastSize !== void 0) {
1509
1702
  const totalSize = lastPosition + lastSize;
1510
- addTotalSize(ctx, state, null, totalSize);
1703
+ addTotalSize(ctx, null, totalSize);
1511
1704
  }
1512
1705
  }
1513
1706
  }
@@ -1553,7 +1746,8 @@ var getScrollVelocity = (state) => {
1553
1746
  };
1554
1747
 
1555
1748
  // src/utils/updateSnapToOffsets.ts
1556
- function updateSnapToOffsets(ctx, state) {
1749
+ function updateSnapToOffsets(ctx) {
1750
+ const state = ctx.state;
1557
1751
  const {
1558
1752
  positions,
1559
1753
  props: { snapToIndices }
@@ -1568,30 +1762,30 @@ function updateSnapToOffsets(ctx, state) {
1568
1762
  }
1569
1763
 
1570
1764
  // src/core/updateItemPositions.ts
1571
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1765
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1572
1766
  doMVCP: false,
1573
1767
  forceFullUpdate: false,
1574
1768
  scrollBottomBuffered: -1,
1575
1769
  startIndex: 0
1576
1770
  }) {
1577
1771
  var _a3, _b, _c, _d, _e;
1772
+ const state = ctx.state;
1578
1773
  const {
1579
1774
  columns,
1580
1775
  indexByKey,
1581
1776
  positions,
1582
1777
  idCache,
1583
1778
  sizesKnown,
1584
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1779
+ props: { data, getEstimatedItemSize, snapToIndices },
1780
+ scrollingTo
1585
1781
  } = state;
1586
- const data = state.props.data;
1587
1782
  const dataLength = data.length;
1588
1783
  const numColumns = peek$(ctx, "numColumns");
1589
- const scrollingTo = peek$(ctx, "scrollingTo");
1590
1784
  const hasColumns = numColumns > 1;
1591
1785
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1592
1786
  const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1593
1787
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1594
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1788
+ const useAverageSize = !getEstimatedItemSize;
1595
1789
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1596
1790
  let currentRowTop = 0;
1597
1791
  let column = 1;
@@ -1600,7 +1794,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1600
1794
  if (hasColumns) {
1601
1795
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1602
1796
  ctx,
1603
- state,
1604
1797
  startIndex,
1605
1798
  useAverageSize
1606
1799
  );
@@ -1610,7 +1803,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1610
1803
  const prevIndex = startIndex - 1;
1611
1804
  const prevId = getId(state, prevIndex);
1612
1805
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1613
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1806
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1614
1807
  currentRowTop = prevPosition + prevSize;
1615
1808
  }
1616
1809
  }
@@ -1627,7 +1820,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1627
1820
  breakAt = i + itemsPerRow + 10;
1628
1821
  }
1629
1822
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1630
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1823
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1631
1824
  if (IS_DEV && needsIndexByKey) {
1632
1825
  if (indexByKeyForChecking.has(id)) {
1633
1826
  console.error(
@@ -1636,7 +1829,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1636
1829
  }
1637
1830
  indexByKeyForChecking.set(id, i);
1638
1831
  }
1639
- positions.set(id, currentRowTop);
1832
+ if (currentRowTop !== positions.get(id)) {
1833
+ positions.set(id, currentRowTop);
1834
+ notifyPosition$(ctx, id, currentRowTop);
1835
+ }
1640
1836
  if (needsIndexByKey) {
1641
1837
  indexByKey.set(id, i);
1642
1838
  }
@@ -1656,10 +1852,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1656
1852
  }
1657
1853
  }
1658
1854
  if (!didBreakEarly) {
1659
- updateTotalSize(ctx, state);
1855
+ updateTotalSize(ctx);
1660
1856
  }
1661
1857
  if (snapToIndices) {
1662
- updateSnapToOffsets(ctx, state);
1858
+ updateSnapToOffsets(ctx);
1663
1859
  }
1664
1860
  }
1665
1861
 
@@ -1737,7 +1933,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1737
1933
  if (previousViewableItems) {
1738
1934
  for (const viewToken of previousViewableItems) {
1739
1935
  const containerId = findContainerId(ctx, viewToken.key);
1740
- if (!isViewable(
1936
+ if (!checkIsViewable(
1741
1937
  state,
1742
1938
  ctx,
1743
1939
  viewabilityConfig,
@@ -1758,7 +1954,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1758
1954
  if (item) {
1759
1955
  const key = getId(state, i);
1760
1956
  const containerId = findContainerId(ctx, key);
1761
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1957
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1762
1958
  const viewToken = {
1763
1959
  containerId,
1764
1960
  index: i,
@@ -1818,11 +2014,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1818
2014
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
1819
2015
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
1820
2016
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
1821
- const isViewable2 = percent >= viewablePercentThreshold;
2017
+ const isViewable = percent >= viewablePercentThreshold;
1822
2018
  const value = {
1823
2019
  containerId,
1824
2020
  index,
1825
- isViewable: isViewable2,
2021
+ isViewable,
1826
2022
  item,
1827
2023
  key,
1828
2024
  percentOfScroller,
@@ -1841,8 +2037,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1841
2037
  }
1842
2038
  return value;
1843
2039
  }
1844
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
1845
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2040
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2041
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2042
+ if (!value || value.key !== key) {
2043
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2044
+ }
1846
2045
  return value.isViewable;
1847
2046
  }
1848
2047
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -1870,8 +2069,9 @@ function checkAllSizesKnown(state) {
1870
2069
  }
1871
2070
 
1872
2071
  // src/utils/findAvailableContainers.ts
1873
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2072
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
1874
2073
  const numContainers = peek$(ctx, "numContainers");
2074
+ const state = ctx.state;
1875
2075
  const { stickyContainerPool, containerItemTypes } = state;
1876
2076
  const result = [];
1877
2077
  const availableContainers = [];
@@ -1915,14 +2115,14 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1915
2115
  continue;
1916
2116
  }
1917
2117
  const key = peek$(ctx, `containerItemKey${u}`);
1918
- let isOk = key === void 0;
1919
- if (!isOk && pendingRemovalSet.has(u)) {
1920
- pendingRemovalSet.delete(u);
1921
- pendingRemovalChanged = true;
1922
- const requiredType = neededTypes[typeIndex];
1923
- isOk = canReuseContainer(u, requiredType);
1924
- }
1925
- if (isOk) {
2118
+ const requiredType = neededTypes[typeIndex];
2119
+ const isPending = key !== void 0 && pendingRemovalSet.has(u);
2120
+ const canUse = key === void 0 || isPending && canReuseContainer(u, requiredType);
2121
+ if (canUse) {
2122
+ if (isPending) {
2123
+ pendingRemovalSet.delete(u);
2124
+ pendingRemovalChanged = true;
2125
+ }
1926
2126
  result.push(u);
1927
2127
  if (requiredItemTypes) {
1928
2128
  typeIndex++;
@@ -1991,21 +2191,26 @@ function comparatorByDistance(a, b) {
1991
2191
  }
1992
2192
 
1993
2193
  // src/core/scrollToIndex.ts
1994
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1995
- if (index >= state.props.data.length) {
1996
- index = state.props.data.length - 1;
2194
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2195
+ const state = ctx.state;
2196
+ const { data } = state.props;
2197
+ if (index >= data.length) {
2198
+ index = data.length - 1;
1997
2199
  } else if (index < 0) {
1998
2200
  index = 0;
1999
2201
  }
2000
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2001
- const isLast = index === state.props.data.length - 1;
2202
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2203
+ const isLast = index === data.length - 1;
2002
2204
  if (isLast && viewPosition === void 0) {
2003
2205
  viewPosition = 1;
2004
2206
  }
2005
2207
  state.scrollForNextCalculateItemsInView = void 0;
2006
- scrollTo(ctx, state, {
2208
+ const targetId = getId(state, index);
2209
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2210
+ scrollTo(ctx, {
2007
2211
  animated,
2008
2212
  index,
2213
+ itemSize,
2009
2214
  offset: firstIndexOffset,
2010
2215
  viewOffset,
2011
2216
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2013,29 +2218,30 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2013
2218
  }
2014
2219
 
2015
2220
  // src/utils/setDidLayout.ts
2016
- function setDidLayout(ctx, state) {
2221
+ function setDidLayout(ctx) {
2222
+ const state = ctx.state;
2017
2223
  const {
2018
2224
  loadStartTime,
2019
2225
  initialScroll,
2020
2226
  props: { onLoad }
2021
2227
  } = state;
2022
2228
  state.queuedInitialLayout = true;
2023
- checkAtBottom(ctx, state);
2229
+ checkAtBottom(ctx);
2024
2230
  const setIt = () => {
2025
- set$(ctx, "containersDidLayout", true);
2231
+ setInitialRenderState(ctx, { didLayout: true });
2026
2232
  if (onLoad) {
2027
2233
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2028
2234
  }
2029
2235
  };
2030
2236
  if (Platform2.OS === "android" && initialScroll) {
2031
2237
  if (IsNewArchitecture) {
2032
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2238
+ scrollToIndex(ctx, { ...initialScroll, animated: false });
2033
2239
  requestAnimationFrame(() => {
2034
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2240
+ scrollToIndex(ctx, { ...initialScroll, animated: false });
2035
2241
  setIt();
2036
2242
  });
2037
2243
  } else {
2038
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2244
+ scrollToIndex(ctx, { ...initialScroll, animated: false });
2039
2245
  setIt();
2040
2246
  }
2041
2247
  } else {
@@ -2058,15 +2264,17 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2058
2264
  }
2059
2265
  return -1;
2060
2266
  }
2061
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2267
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2268
+ const state = ctx.state;
2062
2269
  return new Set(
2063
2270
  Array.from(state.stickyContainerPool).map((i) => peek$(ctx, `containerItemKey${i}`)).map((key) => key ? state.indexByKey.get(key) : void 0).filter((idx) => idx !== void 0 && stickyHeaderIndices.has(idx))
2064
2271
  );
2065
2272
  }
2066
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2273
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2067
2274
  var _a3;
2068
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2069
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2275
+ const state = ctx.state;
2276
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2277
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2070
2278
  for (let offset = 0; offset <= 1; offset++) {
2071
2279
  const idx = currentStickyIdx - offset;
2072
2280
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -2077,8 +2285,9 @@ function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, cu
2077
2285
  }
2078
2286
  }
2079
2287
  }
2080
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2288
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2081
2289
  var _a3, _b, _c;
2290
+ const state = ctx.state;
2082
2291
  for (const containerIndex of state.stickyContainerPool) {
2083
2292
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2084
2293
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
@@ -2102,7 +2311,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2102
2311
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2103
2312
  if (currentId) {
2104
2313
  const currentPos = state.positions.get(currentId);
2105
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2314
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2106
2315
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2107
2316
  }
2108
2317
  }
@@ -2111,7 +2320,8 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2111
2320
  }
2112
2321
  }
2113
2322
  }
2114
- function calculateItemsInView(ctx, state, params = {}) {
2323
+ function calculateItemsInView(ctx, params = {}) {
2324
+ const state = ctx.state;
2115
2325
  unstable_batchedUpdates(() => {
2116
2326
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2117
2327
  const {
@@ -2135,8 +2345,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2135
2345
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2136
2346
  const prevNumContainers = peek$(ctx, "numContainers");
2137
2347
  if (!data || scrollLength === 0 || !prevNumContainers) {
2138
- if (state.initialAnchor) {
2139
- ensureInitialAnchor(ctx, state);
2348
+ if (!IsNewArchitecture && state.initialAnchor) {
2349
+ ensureInitialAnchor(ctx);
2140
2350
  }
2141
2351
  return;
2142
2352
  }
@@ -2151,15 +2361,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2151
2361
  if (!queuedInitialLayout && initialScroll) {
2152
2362
  const updatedOffset = calculateOffsetWithOffsetPosition(
2153
2363
  ctx,
2154
- state,
2155
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2364
+ calculateOffsetForIndex(ctx, initialScroll.index),
2156
2365
  initialScroll
2157
2366
  );
2158
2367
  scrollState = updatedOffset;
2159
2368
  }
2160
2369
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2161
2370
  const scrollAdjustPad = scrollAdjustPending - topPad;
2162
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2371
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2163
2372
  if (scroll + scrollLength > totalSize) {
2164
2373
  scroll = Math.max(0, totalSize - scrollLength);
2165
2374
  }
@@ -2167,11 +2376,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2167
2376
  set$(ctx, "debugRawScroll", scrollState);
2168
2377
  set$(ctx, "debugComputedScroll", scroll);
2169
2378
  }
2170
- const previousStickyIndex = state.activeStickyIndex;
2379
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2171
2380
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2172
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2173
- state.activeStickyIndex = nextActiveStickyIndex;
2174
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2381
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2382
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2383
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2384
+ }
2175
2385
  let scrollBufferTop = scrollBuffer;
2176
2386
  let scrollBufferBottom = scrollBuffer;
2177
2387
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2184,23 +2394,23 @@ function calculateItemsInView(ctx, state, params = {}) {
2184
2394
  const scrollTopBuffered = scroll - scrollBufferTop;
2185
2395
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2186
2396
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2187
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2397
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2188
2398
  const { top, bottom } = scrollForNextCalculateItemsInView;
2189
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2190
- if (state.initialAnchor) {
2191
- ensureInitialAnchor(ctx, state);
2399
+ if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2400
+ if (!IsNewArchitecture && state.initialAnchor) {
2401
+ ensureInitialAnchor(ctx);
2192
2402
  }
2193
2403
  return;
2194
2404
  }
2195
2405
  }
2196
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2406
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2197
2407
  if (dataChanged) {
2198
2408
  indexByKey.clear();
2199
2409
  idCache.length = 0;
2200
2410
  positions.clear();
2201
2411
  }
2202
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2203
- updateItemPositions(ctx, state, dataChanged, {
2412
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2413
+ updateItemPositions(ctx, dataChanged, {
2204
2414
  doMVCP,
2205
2415
  forceFullUpdate: !!forceFullItemPositions,
2206
2416
  scrollBottomBuffered,
@@ -2219,9 +2429,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2219
2429
  for (let i = loopStart; i >= 0; i--) {
2220
2430
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2221
2431
  const top = positions.get(id);
2222
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2432
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2223
2433
  const bottom = top + size;
2224
- if (bottom > scroll - scrollBuffer) {
2434
+ if (bottom > scroll - scrollBufferTop) {
2225
2435
  loopStart = i;
2226
2436
  } else {
2227
2437
  break;
@@ -2246,7 +2456,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2246
2456
  const dataLength = data.length;
2247
2457
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2248
2458
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2249
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2459
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2250
2460
  const top = positions.get(id);
2251
2461
  if (!foundEnd) {
2252
2462
  if (startNoBuffer === null && top + size > scroll) {
@@ -2258,7 +2468,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2258
2468
  if (startBuffered === null && top + size > scrollTopBuffered) {
2259
2469
  startBuffered = i;
2260
2470
  startBufferedId = id;
2261
- nextTop = top;
2471
+ if (scrollTopBuffered < 0) {
2472
+ nextTop = null;
2473
+ } else {
2474
+ nextTop = top;
2475
+ }
2262
2476
  }
2263
2477
  if (startNoBuffer !== null) {
2264
2478
  if (top <= scrollBottom) {
@@ -2266,7 +2480,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2266
2480
  }
2267
2481
  if (top <= scrollBottomBuffered) {
2268
2482
  endBuffered = i;
2269
- nextBottom = top + size;
2483
+ if (scrollBottomBuffered > totalSize) {
2484
+ nextBottom = null;
2485
+ } else {
2486
+ nextBottom = top + size;
2487
+ }
2270
2488
  } else {
2271
2489
  foundEnd = true;
2272
2490
  }
@@ -2293,7 +2511,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2293
2511
  top: nextTop
2294
2512
  } : void 0;
2295
2513
  }
2296
- const numContainers = peek$(ctx, "numContainers");
2514
+ let numContainers = prevNumContainers;
2297
2515
  const pendingRemoval = [];
2298
2516
  if (dataChanged) {
2299
2517
  for (let i = 0; i < numContainers; i++) {
@@ -2304,7 +2522,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2304
2522
  }
2305
2523
  }
2306
2524
  if (startBuffered !== null && endBuffered !== null) {
2307
- let numContainers2 = prevNumContainers;
2308
2525
  const needNewContainers = [];
2309
2526
  for (let i = startBuffered; i <= endBuffered; i++) {
2310
2527
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
@@ -2315,7 +2532,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2315
2532
  if (stickyIndicesArr.length > 0) {
2316
2533
  handleStickyActivation(
2317
2534
  ctx,
2318
- state,
2319
2535
  stickyIndicesSet,
2320
2536
  stickyIndicesArr,
2321
2537
  currentStickyIdx,
@@ -2323,9 +2539,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2323
2539
  startBuffered,
2324
2540
  endBuffered
2325
2541
  );
2326
- } else {
2327
- state.activeStickyIndex = void 0;
2328
- set$(ctx, "activeStickyIndex", void 0);
2542
+ } else if (previousStickyIndex !== -1) {
2543
+ set$(ctx, "activeStickyIndex", -1);
2329
2544
  }
2330
2545
  if (needNewContainers.length > 0) {
2331
2546
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2334,7 +2549,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2334
2549
  }) : void 0;
2335
2550
  const availableContainers = findAvailableContainers(
2336
2551
  ctx,
2337
- state,
2338
2552
  needNewContainers.length,
2339
2553
  startBuffered,
2340
2554
  endBuffered,
@@ -2356,29 +2570,30 @@ function calculateItemsInView(ctx, state, params = {}) {
2356
2570
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2357
2571
  }
2358
2572
  containerItemKeys.add(id);
2573
+ const containerSticky = `containerSticky${containerIndex}`;
2359
2574
  if (stickyIndicesSet.has(i)) {
2360
- set$(ctx, `containerSticky${containerIndex}`, true);
2575
+ set$(ctx, containerSticky, true);
2361
2576
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2362
2577
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2363
2578
  state.stickyContainerPool.add(containerIndex);
2364
- } else {
2365
- set$(ctx, `containerSticky${containerIndex}`, false);
2579
+ } else if (peek$(ctx, containerSticky)) {
2580
+ set$(ctx, containerSticky, false);
2366
2581
  state.stickyContainerPool.delete(containerIndex);
2367
2582
  }
2368
- if (containerIndex >= numContainers2) {
2369
- numContainers2 = containerIndex + 1;
2583
+ if (containerIndex >= numContainers) {
2584
+ numContainers = containerIndex + 1;
2370
2585
  }
2371
2586
  }
2372
- if (numContainers2 !== prevNumContainers) {
2373
- set$(ctx, "numContainers", numContainers2);
2374
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2375
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2587
+ if (numContainers !== prevNumContainers) {
2588
+ set$(ctx, "numContainers", numContainers);
2589
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2590
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2376
2591
  }
2377
2592
  }
2378
2593
  }
2379
2594
  }
2380
2595
  if (stickyIndicesArr.length > 0) {
2381
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2596
+ handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2382
2597
  }
2383
2598
  let didChangePositions = false;
2384
2599
  for (let i = 0; i < numContainers; i++) {
@@ -2430,7 +2645,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2430
2645
  }
2431
2646
  if (!queuedInitialLayout && endBuffered !== null) {
2432
2647
  if (checkAllSizesKnown(state)) {
2433
- setDidLayout(ctx, state);
2648
+ setDidLayout(ctx);
2434
2649
  }
2435
2650
  }
2436
2651
  if (viewabilityConfigCallbackPairs) {
@@ -2443,8 +2658,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2443
2658
  }
2444
2659
  }
2445
2660
  });
2446
- if (state.initialAnchor) {
2447
- ensureInitialAnchor(ctx, state);
2661
+ if (!IsNewArchitecture && state.initialAnchor) {
2662
+ ensureInitialAnchor(ctx);
2448
2663
  }
2449
2664
  }
2450
2665
 
@@ -2469,19 +2684,22 @@ function checkActualChange(state, dataProp, previousData) {
2469
2684
  }
2470
2685
 
2471
2686
  // src/core/doMaintainScrollAtEnd.ts
2472
- function doMaintainScrollAtEnd(ctx, state, animated) {
2687
+ function doMaintainScrollAtEnd(ctx, animated) {
2688
+ const state = ctx.state;
2473
2689
  const {
2690
+ didContainersLayout,
2691
+ isAtEnd,
2474
2692
  refScroller,
2475
2693
  props: { maintainScrollAtEnd }
2476
2694
  } = state;
2477
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2695
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2478
2696
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2479
2697
  if (paddingTop > 0) {
2480
2698
  state.scroll = 0;
2481
2699
  }
2482
2700
  requestAnimationFrame(() => {
2483
2701
  var _a3;
2484
- if (state == null ? void 0 : state.isAtEnd) {
2702
+ if (state.isAtEnd) {
2485
2703
  state.maintainingScrollAtEnd = true;
2486
2704
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2487
2705
  animated
@@ -2552,28 +2770,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2552
2770
  }
2553
2771
 
2554
2772
  // src/core/checkResetContainers.ts
2555
- function checkResetContainers(ctx, state, dataProp) {
2773
+ function checkResetContainers(ctx, dataProp) {
2774
+ const state = ctx.state;
2556
2775
  const { previousData } = state;
2557
2776
  if (previousData) {
2558
2777
  updateAveragesOnDataChange(state, previousData, dataProp);
2559
2778
  }
2560
2779
  const { maintainScrollAtEnd } = state.props;
2561
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2780
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2562
2781
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2563
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2782
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2564
2783
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2565
2784
  state.isEndReached = false;
2566
2785
  }
2567
2786
  if (!didMaintainScrollAtEnd) {
2568
2787
  checkAtTop(state);
2569
- checkAtBottom(ctx, state);
2788
+ checkAtBottom(ctx);
2570
2789
  }
2571
2790
  delete state.previousData;
2572
2791
  }
2573
2792
 
2574
2793
  // src/core/doInitialAllocateContainers.ts
2575
- function doInitialAllocateContainers(ctx, state) {
2794
+ function doInitialAllocateContainers(ctx) {
2576
2795
  var _a3, _b, _c;
2796
+ const state = ctx.state;
2577
2797
  const {
2578
2798
  scrollLength,
2579
2799
  props: {
@@ -2611,10 +2831,10 @@ function doInitialAllocateContainers(ctx, state) {
2611
2831
  if (!IsNewArchitecture || state.lastLayout) {
2612
2832
  if (state.initialScroll) {
2613
2833
  requestAnimationFrame(() => {
2614
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2834
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2615
2835
  });
2616
2836
  } else {
2617
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2837
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2618
2838
  }
2619
2839
  }
2620
2840
  return true;
@@ -2622,7 +2842,8 @@ function doInitialAllocateContainers(ctx, state) {
2622
2842
  }
2623
2843
 
2624
2844
  // src/core/handleLayout.ts
2625
- function handleLayout(ctx, state, layout, setCanRender) {
2845
+ function handleLayout(ctx, layout, setCanRender) {
2846
+ const state = ctx.state;
2626
2847
  const { maintainScrollAtEnd } = state.props;
2627
2848
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2628
2849
  const previousLength = state.scrollLength;
@@ -2638,19 +2859,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2638
2859
  state.lastBatchingAction = Date.now();
2639
2860
  state.scrollForNextCalculateItemsInView = void 0;
2640
2861
  if (scrollLength > 0) {
2641
- doInitialAllocateContainers(ctx, state);
2862
+ doInitialAllocateContainers(ctx);
2642
2863
  }
2643
2864
  if (needsCalculate) {
2644
- calculateItemsInView(ctx, state, { doMVCP: true });
2865
+ calculateItemsInView(ctx, { doMVCP: true });
2645
2866
  }
2646
2867
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2647
2868
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2648
2869
  }
2649
2870
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2650
- doMaintainScrollAtEnd(ctx, state, false);
2871
+ doMaintainScrollAtEnd(ctx, false);
2651
2872
  }
2652
- updateAlignItemsPaddingTop(ctx, state);
2653
- checkAtBottom(ctx, state);
2873
+ updateAlignItemsPaddingTop(ctx);
2874
+ checkAtBottom(ctx);
2654
2875
  checkAtTop(state);
2655
2876
  if (state) {
2656
2877
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2666,8 +2887,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2666
2887
  }
2667
2888
 
2668
2889
  // src/core/onScroll.ts
2669
- function onScroll(ctx, state, event) {
2890
+ function onScroll(ctx, event) {
2670
2891
  var _a3, _b, _c;
2892
+ const state = ctx.state;
2671
2893
  const {
2672
2894
  scrollProcessingEnabled,
2673
2895
  props: { onScroll: onScrollProp }
@@ -2678,9 +2900,23 @@ function onScroll(ctx, state, event) {
2678
2900
  if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2679
2901
  return;
2680
2902
  }
2681
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2903
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2682
2904
  state.scrollPending = newScroll;
2683
- updateScroll(ctx, state, newScroll);
2905
+ if (state.scrollingTo) {
2906
+ const maxOffset = clampScrollOffset(ctx, newScroll);
2907
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
2908
+ newScroll = maxOffset;
2909
+ scrollTo(ctx, {
2910
+ forceScroll: true,
2911
+ isInitialScroll: true,
2912
+ noScrollingTo: true,
2913
+ offset: newScroll
2914
+ });
2915
+ return;
2916
+ }
2917
+ }
2918
+ updateScroll(ctx, newScroll);
2919
+ checkFinishedScroll(ctx);
2684
2920
  onScrollProp == null ? void 0 : onScrollProp(event);
2685
2921
  }
2686
2922
 
@@ -2689,51 +2925,47 @@ var ScrollAdjustHandler = class {
2689
2925
  constructor(ctx) {
2690
2926
  this.appliedAdjust = 0;
2691
2927
  this.pendingAdjust = 0;
2692
- this.mounted = false;
2693
- this.context = ctx;
2694
- if (Platform2.OS === "web") {
2695
- const commitPendingAdjust = () => {
2696
- const state = this.context.internalState;
2697
- const pending = this.pendingAdjust;
2698
- if (pending !== 0) {
2699
- this.pendingAdjust = 0;
2700
- this.appliedAdjust += pending;
2701
- state.scroll += pending;
2702
- state.scrollForNextCalculateItemsInView = void 0;
2703
- set$(this.context, "scrollAdjustPending", 0);
2704
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2705
- calculateItemsInView(this.context, this.context.internalState);
2706
- }
2707
- };
2708
- listen$(this.context, "scrollingTo", (value) => {
2709
- if (value === void 0) {
2710
- commitPendingAdjust();
2711
- }
2712
- });
2713
- }
2928
+ this.ctx = ctx;
2714
2929
  }
2715
2930
  requestAdjust(add) {
2716
- const scrollingTo = peek$(this.context, "scrollingTo");
2931
+ const scrollingTo = this.ctx.state.scrollingTo;
2717
2932
  if (Platform2.OS === "web" && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2718
2933
  this.pendingAdjust += add;
2719
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
2934
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2720
2935
  } else {
2721
2936
  this.appliedAdjust += add;
2722
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2937
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
2938
+ }
2939
+ if (this.ctx.state.scrollingTo) {
2940
+ checkFinishedScroll(this.ctx);
2723
2941
  }
2724
- }
2725
- setMounted() {
2726
- this.mounted = true;
2727
2942
  }
2728
2943
  getAdjust() {
2729
2944
  return this.appliedAdjust;
2730
2945
  }
2946
+ commitPendingAdjust() {
2947
+ if (Platform2.OS === "web") {
2948
+ const state = this.ctx.state;
2949
+ const pending = this.pendingAdjust;
2950
+ if (pending !== 0) {
2951
+ this.pendingAdjust = 0;
2952
+ this.appliedAdjust += pending;
2953
+ state.scroll += pending;
2954
+ state.scrollForNextCalculateItemsInView = void 0;
2955
+ set$(this.ctx, "scrollAdjustPending", 0);
2956
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
2957
+ calculateItemsInView(this.ctx);
2958
+ }
2959
+ }
2960
+ }
2731
2961
  };
2732
2962
 
2733
2963
  // src/core/updateItemSize.ts
2734
- function updateItemSize(ctx, state, itemKey, sizeObj) {
2964
+ function updateItemSize(ctx, itemKey, sizeObj) {
2735
2965
  var _a3;
2966
+ const state = ctx.state;
2736
2967
  const {
2968
+ didContainersLayout,
2737
2969
  sizesKnown,
2738
2970
  props: {
2739
2971
  getFixedItemSize,
@@ -2761,13 +2993,12 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2761
2993
  return;
2762
2994
  }
2763
2995
  }
2764
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2765
- let needsRecalculate = !containersDidLayout;
2996
+ let needsRecalculate = !didContainersLayout;
2766
2997
  let shouldMaintainScrollAtEnd = false;
2767
2998
  let minIndexSizeChanged;
2768
2999
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2769
3000
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2770
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3001
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
2771
3002
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2772
3003
  if (diff !== 0) {
2773
3004
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
@@ -2816,22 +3047,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2816
3047
  if (!cur || maxOtherAxisSize > cur) {
2817
3048
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
2818
3049
  }
2819
- if (containersDidLayout || checkAllSizesKnown(state)) {
3050
+ if (didContainersLayout || checkAllSizesKnown(state)) {
2820
3051
  if (needsRecalculate) {
2821
3052
  state.scrollForNextCalculateItemsInView = void 0;
2822
- calculateItemsInView(ctx, state, { doMVCP: true });
3053
+ calculateItemsInView(ctx, { doMVCP: true });
2823
3054
  }
2824
3055
  if (shouldMaintainScrollAtEnd) {
2825
3056
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2826
- doMaintainScrollAtEnd(ctx, state, false);
3057
+ doMaintainScrollAtEnd(ctx, false);
2827
3058
  }
2828
3059
  }
2829
3060
  }
2830
3061
  }
2831
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3062
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
2832
3063
  var _a3;
3064
+ const state = ctx.state;
2833
3065
  const {
2834
- sizes,
2835
3066
  indexByKey,
2836
3067
  sizesKnown,
2837
3068
  averageSizes,
@@ -2839,9 +3070,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2839
3070
  } = state;
2840
3071
  if (!data) return 0;
2841
3072
  const index = indexByKey.get(itemKey);
2842
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3073
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
2843
3074
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2844
3075
  const size = Platform2.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
3076
+ const prevSizeKnown = sizesKnown.get(itemKey);
2845
3077
  sizesKnown.set(itemKey, size);
2846
3078
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2847
3079
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -2849,11 +3081,15 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2849
3081
  if (!averages) {
2850
3082
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
2851
3083
  }
2852
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2853
- averages.num++;
3084
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3085
+ averages.avg += (size - prevSizeKnown) / averages.num;
3086
+ } else {
3087
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3088
+ averages.num++;
3089
+ }
2854
3090
  }
2855
3091
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2856
- setSize(ctx, state, itemKey, size);
3092
+ setSize(ctx, itemKey, size);
2857
3093
  return size - prevSize;
2858
3094
  }
2859
3095
  return 0;
@@ -2919,14 +3155,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
2919
3155
  }
2920
3156
 
2921
3157
  // src/utils/createImperativeHandle.ts
2922
- function createImperativeHandle(ctx, state) {
3158
+ function createImperativeHandle(ctx) {
3159
+ const state = ctx.state;
2923
3160
  const scrollIndexIntoView = (options) => {
2924
3161
  if (state) {
2925
3162
  const { index, ...rest } = options;
2926
3163
  const { startNoBuffer, endNoBuffer } = state;
2927
3164
  if (index < startNoBuffer || index > endNoBuffer) {
2928
3165
  const viewPosition = index < startNoBuffer ? 0 : 1;
2929
- scrollToIndex(ctx, state, {
3166
+ scrollToIndex(ctx, {
2930
3167
  ...rest,
2931
3168
  index,
2932
3169
  viewPosition
@@ -2941,7 +3178,7 @@ function createImperativeHandle(ctx, state) {
2941
3178
  getScrollableNode: () => refScroller.current.getScrollableNode(),
2942
3179
  getScrollResponder: () => refScroller.current.getScrollResponder(),
2943
3180
  getState: () => ({
2944
- activeStickyIndex: state.activeStickyIndex,
3181
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
2945
3182
  contentLength: state.totalSize,
2946
3183
  data: state.props.data,
2947
3184
  elementAtIndex: (index) => {
@@ -2952,6 +3189,8 @@ function createImperativeHandle(ctx, state) {
2952
3189
  endBuffered: state.endBuffered,
2953
3190
  isAtEnd: state.isAtEnd,
2954
3191
  isAtStart: state.isAtStart,
3192
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3193
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
2955
3194
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
2956
3195
  positions: state.positions,
2957
3196
  scroll: state.scroll,
@@ -2976,23 +3215,23 @@ function createImperativeHandle(ctx, state) {
2976
3215
  if (index !== -1) {
2977
3216
  const paddingBottom = stylePaddingBottom || 0;
2978
3217
  const footerSize = peek$(ctx, "footerSize") || 0;
2979
- scrollToIndex(ctx, state, {
3218
+ scrollToIndex(ctx, {
3219
+ ...options,
2980
3220
  index,
2981
3221
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
2982
- viewPosition: 1,
2983
- ...options
3222
+ viewPosition: 1
2984
3223
  });
2985
3224
  }
2986
3225
  },
2987
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3226
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
2988
3227
  scrollToItem: ({ item, ...props }) => {
2989
3228
  const data = state.props.data;
2990
3229
  const index = data.indexOf(item);
2991
3230
  if (index !== -1) {
2992
- scrollToIndex(ctx, state, { index, ...props });
3231
+ scrollToIndex(ctx, { index, ...props });
2993
3232
  }
2994
3233
  },
2995
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3234
+ scrollToOffset: (params) => scrollTo(ctx, params),
2996
3235
  setScrollProcessingEnabled: (enabled) => {
2997
3236
  state.scrollProcessingEnabled = enabled;
2998
3237
  },
@@ -3002,8 +3241,9 @@ function createImperativeHandle(ctx, state) {
3002
3241
  }
3003
3242
  };
3004
3243
  }
3005
- function getRenderedItem(ctx, state, key) {
3244
+ function getRenderedItem(ctx, key) {
3006
3245
  var _a3;
3246
+ const state = ctx.state;
3007
3247
  if (!state) {
3008
3248
  return null;
3009
3249
  }
@@ -3080,11 +3320,13 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3080
3320
  var DEFAULT_DRAW_DISTANCE = 250;
3081
3321
  var DEFAULT_ITEM_SIZE = 100;
3082
3322
  var LegendList = typedMemo(
3323
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3083
3324
  typedForwardRef(function LegendList2(props, forwardedRef) {
3084
3325
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3085
3326
  const isChildrenMode = children !== void 0 && dataProp === void 0;
3086
3327
  const processedProps = isChildrenMode ? {
3087
3328
  ...restProps,
3329
+ childrenMode: true,
3088
3330
  data: (isArray(children) ? children : React2.Children.toArray(children)).flat(1),
3089
3331
  renderItem: ({ item }) => item
3090
3332
  } : {
@@ -3101,10 +3343,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3101
3343
  alignItemsAtEnd = false,
3102
3344
  columnWrapperStyle,
3103
3345
  contentContainerStyle: contentContainerStyleProp,
3346
+ contentInset,
3104
3347
  data: dataProp = [],
3105
3348
  dataVersion,
3106
3349
  drawDistance = 250,
3107
- enableAverages = true,
3108
3350
  estimatedItemSize: estimatedItemSizeProp,
3109
3351
  estimatedListSize,
3110
3352
  extraData,
@@ -3146,6 +3388,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3146
3388
  snapToIndices,
3147
3389
  stickyHeaderIndices: stickyHeaderIndicesProp,
3148
3390
  stickyIndices: stickyIndicesDeprecated,
3391
+ // TODOV3: Remove from v3 release
3149
3392
  style: styleProp,
3150
3393
  suggestEstimatedItemSize,
3151
3394
  viewabilityConfig,
@@ -3153,6 +3396,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3153
3396
  waitForInitialLayout = true,
3154
3397
  ...rest
3155
3398
  } = props;
3399
+ const animatedPropsInternal = props.animatedPropsInternal;
3400
+ const { childrenMode } = rest;
3156
3401
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3157
3402
  const style = { ...StyleSheet.flatten(styleProp) };
3158
3403
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
@@ -3176,10 +3421,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3176
3421
  }
3177
3422
  const refState = useRef();
3178
3423
  if (!refState.current) {
3179
- if (!ctx.internalState) {
3424
+ if (!ctx.state) {
3180
3425
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : getWindowSize())[horizontal ? "width" : "height"];
3181
- ctx.internalState = {
3182
- activeStickyIndex: void 0,
3426
+ ctx.state = {
3427
+ activeStickyIndex: -1,
3183
3428
  averageSizes: {},
3184
3429
  columns: /* @__PURE__ */ new Map(),
3185
3430
  containerItemKeys: /* @__PURE__ */ new Set(),
@@ -3205,9 +3450,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3205
3450
  initialScroll: initialScrollProp,
3206
3451
  isAtEnd: false,
3207
3452
  isAtStart: false,
3208
- isEndReached: false,
3453
+ isEndReached: null,
3209
3454
  isFirst: true,
3210
- isStartReached: false,
3455
+ isStartReached: null,
3211
3456
  lastBatchingAction: Date.now(),
3212
3457
  lastLayout: void 0,
3213
3458
  loadStartTime: Date.now(),
@@ -3239,12 +3484,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3239
3484
  totalSize: 0,
3240
3485
  viewabilityConfigCallbackPairs: void 0
3241
3486
  };
3242
- const internalState = ctx.internalState;
3243
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3487
+ const internalState = ctx.state;
3488
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3244
3489
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3245
3490
  set$(ctx, "extraData", extraData);
3246
3491
  }
3247
- refState.current = ctx.internalState;
3492
+ refState.current = ctx.state;
3248
3493
  }
3249
3494
  const state = refState.current;
3250
3495
  const isFirstLocal = state.isFirst;
@@ -3258,9 +3503,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3258
3503
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3259
3504
  state.props = {
3260
3505
  alignItemsAtEnd,
3506
+ animatedProps: animatedPropsInternal,
3507
+ contentInset,
3261
3508
  data: dataProp,
3262
3509
  dataVersion,
3263
- enableAverages,
3264
3510
  estimatedItemSize,
3265
3511
  getEstimatedItemSize,
3266
3512
  getFixedItemSize,
@@ -3303,62 +3549,62 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3303
3549
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3304
3550
  set$(ctx, "numColumns", numColumnsProp);
3305
3551
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3306
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3552
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3307
3553
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3308
3554
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3309
3555
  if (paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3310
3556
  if (state.scroll < 0) {
3311
3557
  paddingDiff += state.scroll;
3312
3558
  }
3313
- requestAdjust(ctx, state, paddingDiff);
3559
+ requestAdjust(ctx, paddingDiff);
3314
3560
  }
3315
3561
  };
3316
3562
  if (isFirstLocal) {
3317
3563
  initializeStateVars();
3318
3564
  updateItemPositions(
3319
3565
  ctx,
3320
- state,
3321
3566
  /*dataChanged*/
3322
3567
  true
3323
3568
  );
3324
3569
  }
3325
3570
  const initialContentOffset = useMemo(() => {
3326
- var _a4, _b2;
3327
- const { initialScroll } = refState.current;
3328
- if (!initialScroll) {
3571
+ var _a4;
3572
+ let value;
3573
+ const { initialScroll, initialAnchor } = refState.current;
3574
+ if (initialScroll) {
3575
+ if (!IsNewArchitecture && initialScroll.index !== void 0 && (!initialAnchor || (initialAnchor == null ? void 0 : initialAnchor.index) !== initialScroll.index)) {
3576
+ refState.current.initialAnchor = {
3577
+ attempts: 0,
3578
+ index: initialScroll.index,
3579
+ settledTicks: 0,
3580
+ viewOffset: (_a4 = initialScroll.viewOffset) != null ? _a4 : 0,
3581
+ viewPosition: initialScroll.viewPosition
3582
+ };
3583
+ }
3584
+ if (initialScroll.contentOffset !== void 0) {
3585
+ value = initialScroll.contentOffset;
3586
+ } else {
3587
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3588
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3589
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3590
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3591
+ refState.current.initialScroll = updatedInitialScroll;
3592
+ state.initialScroll = updatedInitialScroll;
3593
+ value = clampedOffset;
3594
+ }
3595
+ } else {
3329
3596
  refState.current.initialAnchor = void 0;
3330
- return 0;
3331
- }
3332
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3333
- refState.current.initialAnchor = {
3334
- attempts: 0,
3335
- index: initialScroll.index,
3336
- settledTicks: 0,
3337
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3338
- viewPosition: initialScroll.viewPosition
3339
- };
3597
+ value = 0;
3598
+ }
3599
+ if (!value) {
3600
+ state.didFinishInitialScroll = true;
3340
3601
  }
3341
- if (initialScroll.contentOffset !== void 0) {
3342
- return initialScroll.contentOffset;
3343
- }
3344
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3345
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3346
- let clampedOffset = resolvedOffset;
3347
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3348
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3349
- clampedOffset = Math.min(clampedOffset, maxOffset);
3350
- }
3351
- clampedOffset = Math.max(0, clampedOffset);
3352
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3353
- refState.current.initialScroll = updatedInitialScroll;
3354
- state.initialScroll = updatedInitialScroll;
3355
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3356
- return clampedOffset;
3602
+ return value;
3357
3603
  }, [renderNum]);
3358
3604
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3359
3605
  refState.current.lastBatchingAction = Date.now();
3360
3606
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3361
- IS_DEV && warnDevOnce(
3607
+ IS_DEV && !childrenMode && warnDevOnce(
3362
3608
  "keyExtractor",
3363
3609
  "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."
3364
3610
  );
@@ -3383,12 +3629,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3383
3629
  }
3384
3630
  }, []);
3385
3631
  const doInitialScroll = useCallback(() => {
3386
- var _a4;
3387
3632
  const initialScroll = state.initialScroll;
3388
3633
  if (initialScroll) {
3389
- scrollTo(ctx, state, {
3634
+ scrollTo(ctx, {
3390
3635
  animated: false,
3391
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3636
+ index: initialScroll == null ? void 0 : initialScroll.index,
3392
3637
  isInitialScroll: true,
3393
3638
  offset: initialContentOffset,
3394
3639
  precomputedWithViewOffset: true
@@ -3397,7 +3642,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3397
3642
  }, [initialContentOffset]);
3398
3643
  const onLayoutChange = useCallback((layout) => {
3399
3644
  doInitialScroll();
3400
- handleLayout(ctx, state, layout, setCanRender);
3645
+ handleLayout(ctx, layout, setCanRender);
3401
3646
  }, []);
3402
3647
  const { onLayout } = useOnLayoutSync({
3403
3648
  onLayoutChange,
@@ -3407,7 +3652,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3407
3652
  });
3408
3653
  useLayoutEffect(() => {
3409
3654
  if (snapToIndices) {
3410
- updateSnapToOffsets(ctx, state);
3655
+ updateSnapToOffsets(ctx);
3411
3656
  }
3412
3657
  }, [snapToIndices]);
3413
3658
  useLayoutEffect(() => {
@@ -3417,9 +3662,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3417
3662
  isFirst,
3418
3663
  props: { data }
3419
3664
  } = state;
3420
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3665
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3421
3666
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3422
- checkResetContainers(ctx, state, data);
3667
+ checkResetContainers(ctx, data);
3423
3668
  }
3424
3669
  state.didColumnsChange = false;
3425
3670
  state.didDataChange = false;
@@ -3446,18 +3691,24 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3446
3691
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3447
3692
  if (!IsNewArchitecture) {
3448
3693
  useInit(() => {
3449
- doInitialAllocateContainers(ctx, state);
3694
+ doInitialAllocateContainers(ctx);
3450
3695
  });
3451
3696
  }
3452
- useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3697
+ useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3453
3698
  if (Platform2.OS === "web") {
3454
3699
  useEffect(doInitialScroll, []);
3455
3700
  }
3456
3701
  const fns = useMemo(
3457
3702
  () => ({
3458
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3459
- onScroll: (event) => onScroll(ctx, state, event),
3460
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3703
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
3704
+ onMomentumScrollEnd: (event) => {
3705
+ checkFinishedScrollFallback(ctx);
3706
+ if (onMomentumScrollEnd) {
3707
+ onMomentumScrollEnd(event);
3708
+ }
3709
+ },
3710
+ onScroll: (event) => onScroll(ctx, event),
3711
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3461
3712
  }),
3462
3713
  []
3463
3714
  );
@@ -3469,6 +3720,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3469
3720
  alignItemsAtEnd,
3470
3721
  canRender,
3471
3722
  contentContainerStyle,
3723
+ contentInset,
3472
3724
  getRenderedItem: fns.getRenderedItem,
3473
3725
  horizontal,
3474
3726
  initialContentOffset,
@@ -3477,20 +3729,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3477
3729
  maintainVisibleContentPosition,
3478
3730
  onLayout,
3479
3731
  onLayoutHeader,
3480
- onMomentumScrollEnd: (event) => {
3481
- if (IsNewArchitecture) {
3482
- requestAnimationFrame(() => {
3483
- finishScrollTo(ctx, refState.current);
3484
- });
3485
- } else {
3486
- setTimeout(() => {
3487
- finishScrollTo(ctx, refState.current);
3488
- }, 1e3);
3489
- }
3490
- if (onMomentumScrollEnd) {
3491
- onMomentumScrollEnd(event);
3492
- }
3493
- },
3732
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3494
3733
  onScroll: onScrollHandler,
3495
3734
  recycleItems,
3496
3735
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControl, {
@@ -3505,7 +3744,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3505
3744
  ),
3506
3745
  refScrollView: combinedRef,
3507
3746
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3508
- scrollEventThrottle: Platform2.OS === "web" ? 16 : void 0,
3747
+ scrollEventThrottle: 0,
3509
3748
  snapToIndices,
3510
3749
  stickyHeaderIndices,
3511
3750
  style,