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

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/section-list.mjs CHANGED
@@ -13,31 +13,65 @@ var View = forwardRef(function View2(props, ref) {
13
13
  });
14
14
  var Text = View;
15
15
 
16
+ // src/state/getContentInsetEnd.ts
17
+ function getContentInsetEnd(state) {
18
+ var _a3;
19
+ const { props } = state;
20
+ const horizontal = props.horizontal;
21
+ let contentInset = props.contentInset;
22
+ if (!contentInset) {
23
+ const animatedInset = (_a3 = props.animatedProps) == null ? void 0 : _a3.contentInset;
24
+ if (animatedInset) {
25
+ if ("get" in animatedInset) {
26
+ contentInset = animatedInset.get();
27
+ } else {
28
+ contentInset = animatedInset;
29
+ }
30
+ }
31
+ }
32
+ return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
33
+ }
34
+
35
+ // src/state/getContentSize.ts
36
+ function getContentSize(ctx) {
37
+ var _a3;
38
+ const { values, state } = ctx;
39
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
40
+ const stylePaddingBottom = state.props.stylePaddingBottom || 0;
41
+ const headerSize = values.get("headerSize") || 0;
42
+ const footerSize = values.get("footerSize") || 0;
43
+ const contentInsetBottom = getContentInsetEnd(state);
44
+ const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
45
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
46
+ }
47
+
16
48
  // src/platform/Animated.tsx
17
49
  var createAnimatedValue = (value) => value;
18
50
 
19
51
  // src/state/state.tsx
20
52
  var ContextState = React3.createContext(null);
53
+ var contextNum = 0;
21
54
  function StateProvider({ children }) {
22
55
  const [value] = React3.useState(() => ({
23
56
  animatedScrollY: createAnimatedValue(0),
24
57
  columnWrapperStyle: void 0,
25
- internalState: void 0,
58
+ contextNum: contextNum++,
26
59
  listeners: /* @__PURE__ */ new Map(),
27
60
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
28
61
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
29
62
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
30
63
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
31
64
  mapViewabilityValues: /* @__PURE__ */ new Map(),
65
+ positionListeners: /* @__PURE__ */ new Map(),
66
+ state: void 0,
32
67
  values: /* @__PURE__ */ new Map([
33
68
  ["alignItemsPaddingTop", 0],
34
69
  ["stylePaddingTop", 0],
35
70
  ["headerSize", 0],
36
71
  ["numContainers", 0],
37
- ["activeStickyIndex", void 0],
72
+ ["activeStickyIndex", -1],
38
73
  ["totalSize", 0],
39
- ["scrollAdjustPending", 0],
40
- ["scrollingTo", void 0]
74
+ ["scrollAdjustPending", 0]
41
75
  ]),
42
76
  viewRefs: /* @__PURE__ */ new Map()
43
77
  }));
@@ -105,15 +139,24 @@ function set$(ctx, signalName, value) {
105
139
  }
106
140
  }
107
141
  }
108
- function getContentSize(ctx) {
109
- var _a3, _b;
110
- const { values, internalState } = ctx;
111
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
112
- const stylePaddingBottom = (internalState == null ? void 0 : internalState.props.stylePaddingBottom) || 0;
113
- const headerSize = values.get("headerSize") || 0;
114
- const footerSize = values.get("footerSize") || 0;
115
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
116
- return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom;
142
+ function listenPosition$(ctx, key, cb) {
143
+ const { positionListeners } = ctx;
144
+ let setListeners = positionListeners.get(key);
145
+ if (!setListeners) {
146
+ setListeners = /* @__PURE__ */ new Set();
147
+ positionListeners.set(key, setListeners);
148
+ }
149
+ setListeners.add(cb);
150
+ return () => setListeners.delete(cb);
151
+ }
152
+ function notifyPosition$(ctx, key, value) {
153
+ const { positionListeners } = ctx;
154
+ const setListeners = positionListeners.get(key);
155
+ if (setListeners) {
156
+ for (const listener of setListeners) {
157
+ listener(value);
158
+ }
159
+ }
117
160
  }
118
161
  function useArr$(signalNames) {
119
162
  const ctx = React3.useContext(ContextState);
@@ -235,12 +278,12 @@ function findContainerId(ctx, key) {
235
278
  }
236
279
 
237
280
  // src/components/PositionView.tsx
238
- var PositionViewState = typedMemo(function PositionView({
281
+ var PositionViewState = typedMemo(function PositionViewState2({
239
282
  id,
240
283
  horizontal,
241
284
  style,
242
285
  refView,
243
- ...rest
286
+ ...props
244
287
  }) {
245
288
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
246
289
  const base = {
@@ -248,7 +291,8 @@ var PositionViewState = typedMemo(function PositionView({
248
291
  };
249
292
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
250
293
  const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
251
- return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: combinedStyle, ...rest });
294
+ const { animatedScrollY, stickyOffset, onLayout, ...webProps } = props;
295
+ return /* @__PURE__ */ React3.createElement("div", { ref: refView, ...webProps, style: combinedStyle });
252
296
  });
253
297
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
254
298
  id,
@@ -293,7 +337,7 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
293
337
  }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
294
338
  return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
295
339
  });
296
- var PositionView2 = PositionViewState;
340
+ var PositionView = PositionViewState;
297
341
 
298
342
  // src/constants-platform.ts
299
343
  var IsNewArchitecture = true;
@@ -348,10 +392,9 @@ function createResizeObserver(element, callback) {
348
392
  }
349
393
  callbacks.add(callback);
350
394
  return () => {
351
- const callbacks2 = callbackMap.get(element);
352
- if (callbacks2) {
353
- callbacks2.delete(callback);
354
- if (callbacks2.size === 0) {
395
+ if (callbacks) {
396
+ callbacks.delete(callback);
397
+ if (callbacks.size === 0) {
355
398
  callbackMap.delete(element);
356
399
  observer.unobserve(element);
357
400
  }
@@ -386,10 +429,10 @@ function useOnLayoutSync({
386
429
  return createResizeObserver(element, (entry) => {
387
430
  var _a4;
388
431
  const target = entry.target instanceof HTMLElement ? entry.target : void 0;
389
- const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
390
- if (rect2.width !== prevRect.width || rect2.height !== prevRect.height) {
391
- prevRect = rect2;
392
- emit(toLayout(rect2), false);
432
+ const rectObserved = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
433
+ if (rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height) {
434
+ prevRect = rectObserved;
435
+ emit(toLayout(rectObserved), false);
393
436
  }
394
437
  });
395
438
  }, deps || []);
@@ -517,7 +560,7 @@ var Container = typedMemo(function Container2({
517
560
  },
518
561
  [itemKey, layoutRenderCount]
519
562
  );
520
- const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
563
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
521
564
  return /* @__PURE__ */ React3.createElement(
522
565
  PositionComponent,
523
566
  {
@@ -710,7 +753,8 @@ var Containers = typedMemo(function Containers2({
710
753
  return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
711
754
  });
712
755
  function DevNumbers() {
713
- return IS_DEV && React3.memo(function DevNumbers2() {
756
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
757
+ React3.memo(function DevNumbers2() {
714
758
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3.createElement(
715
759
  "div",
716
760
  {
@@ -758,7 +802,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
758
802
  }, ref) {
759
803
  const scrollRef = useRef(null);
760
804
  const contentRef = useRef(null);
761
- const momentumTimeout = useRef(null);
762
805
  useImperativeHandle(ref, () => {
763
806
  const api = {
764
807
  getBoundingClientRect: () => {
@@ -824,16 +867,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
824
867
  }
825
868
  };
826
869
  onScroll2(scrollEvent);
827
- if (onMomentumScrollEnd) {
828
- if (momentumTimeout.current != null) clearTimeout(momentumTimeout.current);
829
- momentumTimeout.current = setTimeout(() => {
830
- onMomentumScrollEnd({
831
- nativeEvent: {
832
- contentOffset: scrollEvent.nativeEvent.contentOffset
833
- }
834
- });
835
- }, 100);
836
- }
837
870
  },
838
871
  [onScroll2, onMomentumScrollEnd]
839
872
  );
@@ -895,7 +928,8 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
895
928
  minWidth: horizontal ? "100%" : void 0,
896
929
  ...StyleSheet.flatten(contentContainerStyle)
897
930
  };
898
- return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
931
+ const { contentInset, scrollEventThrottle, ScrollComponent, ...webProps } = props;
932
+ return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
899
933
  });
900
934
  function Padding() {
901
935
  const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
@@ -936,7 +970,7 @@ function ScrollAdjust() {
936
970
  const scrollAdjust = peek$(ctx, "scrollAdjust");
937
971
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
938
972
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
939
- const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
973
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
940
974
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
941
975
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
942
976
  if (scrollDelta !== 0) {
@@ -944,16 +978,16 @@ function ScrollAdjust() {
944
978
  const prevScroll = el.scrollTop;
945
979
  const nextScroll = prevScroll + scrollDelta;
946
980
  const totalSize = el.scrollHeight;
947
- if (scrollDelta > 0 && !ctx.internalState.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
981
+ if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
948
982
  const child = el.firstElementChild;
949
983
  const prevPaddingBottom = child.style.paddingBottom;
950
984
  const pad = (nextScroll + el.clientHeight - totalSize) * 2;
951
985
  child.style.paddingBottom = `${pad}px`;
952
986
  void el.offsetHeight;
953
987
  scrollView.scrollBy(0, scrollDelta);
954
- setTimeout(() => {
988
+ requestAnimationFrame(() => {
955
989
  child.style.paddingBottom = prevPaddingBottom;
956
- }, 100);
990
+ });
957
991
  } else {
958
992
  scrollView.scrollBy(0, scrollDelta);
959
993
  }
@@ -963,7 +997,7 @@ function ScrollAdjust() {
963
997
  }
964
998
  lastScrollOffsetRef.current = scrollOffset;
965
999
  }
966
- }, []);
1000
+ }, [ctx]);
967
1001
  useValueListener$("scrollAdjust", callback);
968
1002
  useValueListener$("scrollAdjustUserOffset", callback);
969
1003
  return null;
@@ -1021,13 +1055,6 @@ var ListComponent = typedMemo(function ListComponent2({
1021
1055
  () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1022
1056
  [renderScrollComponent]
1023
1057
  ) : ListComponentScrollView;
1024
- React3.useEffect(() => {
1025
- if (canRender) {
1026
- setTimeout(() => {
1027
- scrollAdjustHandler.setMounted();
1028
- }, 0);
1029
- }
1030
- }, [canRender]);
1031
1058
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1032
1059
  return /* @__PURE__ */ React3.createElement(
1033
1060
  SnapOrScroll,
@@ -1091,10 +1118,11 @@ function getId(state, index) {
1091
1118
  }
1092
1119
 
1093
1120
  // src/core/calculateOffsetForIndex.ts
1094
- function calculateOffsetForIndex(ctx, state, index) {
1121
+ function calculateOffsetForIndex(ctx, index) {
1122
+ const state = ctx.state;
1095
1123
  let position = 0;
1096
1124
  if (index !== void 0) {
1097
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
1125
+ position = state.positions.get(getId(state, index)) || 0;
1098
1126
  const paddingTop = peek$(ctx, "stylePaddingTop");
1099
1127
  if (paddingTop) {
1100
1128
  position += paddingTop;
@@ -1108,7 +1136,8 @@ function calculateOffsetForIndex(ctx, state, index) {
1108
1136
  }
1109
1137
 
1110
1138
  // src/utils/setPaddingTop.ts
1111
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1139
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1140
+ const state = ctx.state;
1112
1141
  if (stylePaddingTop !== void 0) {
1113
1142
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1114
1143
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -1127,7 +1156,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1127
1156
  }
1128
1157
 
1129
1158
  // src/utils/updateAlignItemsPaddingTop.ts
1130
- function updateAlignItemsPaddingTop(ctx, state) {
1159
+ function updateAlignItemsPaddingTop(ctx) {
1160
+ const state = ctx.state;
1131
1161
  const {
1132
1162
  scrollLength,
1133
1163
  props: { alignItemsAtEnd, data }
@@ -1138,12 +1168,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
1138
1168
  const contentSize = getContentSize(ctx);
1139
1169
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1140
1170
  }
1141
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1171
+ setPaddingTop(ctx, { alignItemsPaddingTop });
1142
1172
  }
1143
1173
  }
1144
1174
 
1145
1175
  // src/core/addTotalSize.ts
1146
- function addTotalSize(ctx, state, key, add) {
1176
+ function addTotalSize(ctx, key, add) {
1177
+ const state = ctx.state;
1147
1178
  const { alignItemsAtEnd } = state.props;
1148
1179
  const prevTotalSize = state.totalSize;
1149
1180
  let totalSize = state.totalSize;
@@ -1162,31 +1193,34 @@ function addTotalSize(ctx, state, key, add) {
1162
1193
  state.totalSize = totalSize;
1163
1194
  set$(ctx, "totalSize", totalSize);
1164
1195
  if (alignItemsAtEnd) {
1165
- updateAlignItemsPaddingTop(ctx, state);
1196
+ updateAlignItemsPaddingTop(ctx);
1166
1197
  }
1167
1198
  }
1168
1199
  }
1169
1200
  }
1170
1201
 
1171
1202
  // src/core/setSize.ts
1172
- function setSize(ctx, state, itemKey, size) {
1203
+ function setSize(ctx, itemKey, size) {
1204
+ const state = ctx.state;
1173
1205
  const { sizes } = state;
1174
1206
  const previousSize = sizes.get(itemKey);
1175
1207
  const diff = previousSize !== void 0 ? size - previousSize : size;
1176
1208
  if (diff !== 0) {
1177
- addTotalSize(ctx, state, itemKey, diff);
1209
+ addTotalSize(ctx, itemKey, diff);
1178
1210
  }
1179
1211
  sizes.set(itemKey, size);
1180
1212
  }
1181
1213
 
1182
1214
  // src/utils/getItemSize.ts
1183
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1215
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1184
1216
  var _a3, _b;
1217
+ const state = ctx.state;
1185
1218
  const {
1186
1219
  sizesKnown,
1187
1220
  sizes,
1188
1221
  averageSizes,
1189
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1222
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1223
+ scrollingTo
1190
1224
  } = state;
1191
1225
  const sizeKnown = sizesKnown.get(key);
1192
1226
  if (sizeKnown !== void 0) {
@@ -1194,7 +1228,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1194
1228
  }
1195
1229
  let size;
1196
1230
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1197
- const scrollingTo = peek$(ctx, "scrollingTo");
1198
1231
  if (preferCachedSize) {
1199
1232
  const cachedSize = sizes.get(key);
1200
1233
  if (cachedSize !== void 0) {
@@ -1222,81 +1255,169 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1222
1255
  if (size === void 0) {
1223
1256
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1224
1257
  }
1225
- setSize(ctx, state, key, size);
1258
+ setSize(ctx, key, size);
1226
1259
  return size;
1227
1260
  }
1228
1261
 
1229
1262
  // src/core/calculateOffsetWithOffsetPosition.ts
1230
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1263
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1264
+ const state = ctx.state;
1231
1265
  const { index, viewOffset, viewPosition } = params;
1232
1266
  let offset = offsetParam;
1233
1267
  if (viewOffset) {
1234
1268
  offset -= viewOffset;
1235
1269
  }
1236
1270
  if (viewPosition !== void 0 && index !== void 0) {
1237
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1271
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1272
+ const trailingInset = getContentInsetEnd(state);
1273
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1238
1274
  }
1239
1275
  return offset;
1240
1276
  }
1241
1277
 
1278
+ // src/core/clampScrollOffset.ts
1279
+ function clampScrollOffset(ctx, offset) {
1280
+ const state = ctx.state;
1281
+ const contentSize = getContentSize(ctx);
1282
+ let clampedOffset = offset;
1283
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1284
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1285
+ clampedOffset = Math.min(offset, maxOffset);
1286
+ }
1287
+ clampedOffset = Math.max(0, clampedOffset);
1288
+ return clampedOffset;
1289
+ }
1290
+
1291
+ // src/utils/setInitialRenderState.ts
1292
+ function setInitialRenderState(ctx, {
1293
+ didLayout,
1294
+ didInitialScroll
1295
+ }) {
1296
+ const { state } = ctx;
1297
+ if (didLayout) {
1298
+ state.didContainersLayout = true;
1299
+ }
1300
+ if (didInitialScroll) {
1301
+ state.didFinishInitialScroll = true;
1302
+ }
1303
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1304
+ set$(ctx, "readyToRender", true);
1305
+ }
1306
+ }
1307
+
1242
1308
  // src/core/finishScrollTo.ts
1243
- function finishScrollTo(ctx, state) {
1309
+ function finishScrollTo(ctx) {
1244
1310
  var _a3, _b;
1245
- if (state) {
1311
+ const state = ctx.state;
1312
+ if (state == null ? void 0 : state.scrollingTo) {
1246
1313
  state.scrollHistory.length = 0;
1247
1314
  state.initialScroll = void 0;
1248
1315
  state.initialAnchor = void 0;
1249
- set$(ctx, "scrollingTo", void 0);
1316
+ state.scrollingTo = void 0;
1250
1317
  if (state.pendingTotalSize !== void 0) {
1251
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1318
+ addTotalSize(ctx, null, state.pendingTotalSize);
1252
1319
  }
1253
1320
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1254
1321
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1255
1322
  }
1323
+ {
1324
+ state.scrollAdjustHandler.commitPendingAdjust();
1325
+ }
1326
+ setInitialRenderState(ctx, { didInitialScroll: true });
1327
+ }
1328
+ }
1329
+
1330
+ // src/core/doScrollTo.ts
1331
+ var SCROLL_END_IDLE_MS = 80;
1332
+ var SCROLL_END_MAX_MS = 1500;
1333
+ var SMOOTH_SCROLL_DURATION_MS = 320;
1334
+ function doScrollTo(ctx, params) {
1335
+ const state = ctx.state;
1336
+ const { animated, horizontal, offset } = params;
1337
+ const scroller = state.refScroller.current;
1338
+ const node = typeof (scroller == null ? void 0 : scroller.getScrollableNode) === "function" ? scroller.getScrollableNode() : scroller;
1339
+ if (node) {
1340
+ const left = horizontal ? offset : 0;
1341
+ const top = horizontal ? 0 : offset;
1342
+ node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1343
+ if (animated) {
1344
+ listenForScrollEnd(ctx, node);
1345
+ } else {
1346
+ state.scroll = offset;
1347
+ setTimeout(() => {
1348
+ finishScrollTo(ctx);
1349
+ }, 100);
1350
+ }
1351
+ }
1352
+ }
1353
+ function listenForScrollEnd(ctx, node) {
1354
+ const supportsScrollEnd = "onscrollend" in node;
1355
+ let idleTimeout;
1356
+ let maxTimeout;
1357
+ let settled = false;
1358
+ const targetToken = ctx.state.scrollingTo;
1359
+ const finish = () => {
1360
+ if (settled) return;
1361
+ settled = true;
1362
+ cleanup();
1363
+ if (targetToken === ctx.state.scrollingTo) {
1364
+ finishScrollTo(ctx);
1365
+ }
1366
+ };
1367
+ const onScroll2 = () => {
1368
+ if (idleTimeout) {
1369
+ clearTimeout(idleTimeout);
1370
+ }
1371
+ idleTimeout = setTimeout(finish, SCROLL_END_IDLE_MS);
1372
+ };
1373
+ const cleanup = () => {
1374
+ if (supportsScrollEnd) {
1375
+ node.removeEventListener("scrollend", finish);
1376
+ } else {
1377
+ node.removeEventListener("scroll", onScroll2);
1378
+ }
1379
+ if (idleTimeout) {
1380
+ clearTimeout(idleTimeout);
1381
+ }
1382
+ if (maxTimeout) {
1383
+ clearTimeout(maxTimeout);
1384
+ }
1385
+ };
1386
+ if (supportsScrollEnd) {
1387
+ node.addEventListener("scrollend", finish, { once: true });
1388
+ } else {
1389
+ node.addEventListener("scroll", onScroll2);
1390
+ idleTimeout = setTimeout(finish, SMOOTH_SCROLL_DURATION_MS);
1391
+ maxTimeout = setTimeout(finish, SCROLL_END_MAX_MS);
1256
1392
  }
1393
+ return cleanup;
1257
1394
  }
1258
1395
 
1259
1396
  // src/core/scrollTo.ts
1260
- function scrollTo(ctx, state, params) {
1261
- var _a3;
1262
- const { noScrollingTo, ...scrollTarget } = params;
1397
+ function scrollTo(ctx, params) {
1398
+ const state = ctx.state;
1399
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1263
1400
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1264
1401
  const {
1265
- refScroller,
1266
1402
  props: { horizontal }
1267
1403
  } = state;
1268
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1269
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1270
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1271
- offset = Math.min(offset, maxOffset);
1404
+ if (state.animFrameCheckFinishedScroll) {
1405
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1272
1406
  }
1407
+ if (state.timeoutCheckFinishedScrollFallback) {
1408
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1409
+ }
1410
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1411
+ offset = clampScrollOffset(ctx, offset);
1273
1412
  state.scrollHistory.length = 0;
1274
1413
  if (!noScrollingTo) {
1275
- set$(ctx, "scrollingTo", scrollTarget);
1414
+ state.scrollingTo = scrollTarget;
1276
1415
  }
1277
1416
  state.scrollPending = offset;
1278
- if (!isInitialScroll || Platform.OS === "android") {
1279
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1280
- animated: !!animated,
1281
- x: horizontal ? offset : 0,
1282
- y: horizontal ? 0 : offset
1283
- });
1284
- }
1285
- if (!animated) {
1417
+ if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1418
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1419
+ } else {
1286
1420
  state.scroll = offset;
1287
- {
1288
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1289
- if (value && peek$(ctx, "scrollingTo")) {
1290
- finishScrollTo(ctx, state);
1291
- unlisten();
1292
- }
1293
- });
1294
- }
1295
- if (isInitialScroll) {
1296
- setTimeout(() => {
1297
- state.initialScroll = void 0;
1298
- }, 500);
1299
- }
1300
1421
  }
1301
1422
  }
1302
1423
 
@@ -1305,6 +1426,12 @@ var HYSTERESIS_MULTIPLIER = 1.3;
1305
1426
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1306
1427
  const absDistance = Math.abs(distance);
1307
1428
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1429
+ if (wasReached === null) {
1430
+ if (!within && distance >= 0) {
1431
+ return false;
1432
+ }
1433
+ return null;
1434
+ }
1308
1435
  const updateSnapshot = () => {
1309
1436
  setSnapshot == null ? void 0 : setSnapshot({
1310
1437
  atThreshold,
@@ -1337,8 +1464,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1337
1464
  };
1338
1465
 
1339
1466
  // src/utils/checkAtBottom.ts
1340
- function checkAtBottom(ctx, state) {
1467
+ function checkAtBottom(ctx) {
1341
1468
  var _a3;
1469
+ const state = ctx.state;
1342
1470
  if (!state) {
1343
1471
  return;
1344
1472
  }
@@ -1411,15 +1539,15 @@ function checkAtTop(state) {
1411
1539
  }
1412
1540
 
1413
1541
  // src/core/updateScroll.ts
1414
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1542
+ function updateScroll(ctx, newScroll, forceUpdate) {
1415
1543
  var _a3;
1416
- const scrollingTo = peek$(ctx, "scrollingTo");
1544
+ const state = ctx.state;
1545
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1417
1546
  state.hasScrolled = true;
1418
1547
  state.lastBatchingAction = Date.now();
1419
1548
  const currentTime = Date.now();
1420
- const adjust = state.scrollAdjustHandler.getAdjust();
1421
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1422
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1549
+ const adjust = scrollAdjustHandler.getAdjust();
1550
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1423
1551
  if (adjustChanged) {
1424
1552
  state.scrollHistory.length = 0;
1425
1553
  }
@@ -1444,17 +1572,21 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1444
1572
  return;
1445
1573
  }
1446
1574
  }
1447
- if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1575
+ const lastCalculated = state.scrollLastCalculate;
1576
+ const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1577
+ if (shouldUpdate) {
1578
+ state.scrollLastCalculate = state.scroll;
1448
1579
  state.ignoreScrollFromMVCPIgnored = false;
1449
1580
  (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1450
- checkAtBottom(ctx, state);
1581
+ checkAtBottom(ctx);
1451
1582
  checkAtTop(state);
1452
1583
  state.dataChangeNeedsScrollUpdate = false;
1453
1584
  }
1454
1585
  }
1455
1586
 
1456
1587
  // src/utils/requestAdjust.ts
1457
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1588
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1589
+ const state = ctx.state;
1458
1590
  if (Math.abs(positionDiff) > 0.1) {
1459
1591
  const doit = () => {
1460
1592
  {
@@ -1466,8 +1598,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1466
1598
  };
1467
1599
  state.scroll += positionDiff;
1468
1600
  state.scrollForNextCalculateItemsInView = void 0;
1469
- const didLayout = peek$(ctx, "containersDidLayout");
1470
- if (didLayout) {
1601
+ const readyToRender = peek$(ctx, "readyToRender");
1602
+ if (readyToRender) {
1471
1603
  doit();
1472
1604
  } else {
1473
1605
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -1476,73 +1608,23 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1476
1608
  }
1477
1609
  }
1478
1610
 
1479
- // src/core/ensureInitialAnchor.ts
1480
- var INITIAL_ANCHOR_TOLERANCE = 0.5;
1481
- var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1482
- var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1483
- function ensureInitialAnchor(ctx, state) {
1484
- var _a3, _b, _c, _d, _e;
1485
- const anchor = state.initialAnchor;
1486
- const item = state.props.data[anchor.index];
1487
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1488
- if (!containersDidLayout) {
1489
- return;
1490
- }
1491
- const id = getId(state, anchor.index);
1492
- if (state.positions.get(id) === void 0) {
1493
- return;
1494
- }
1495
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1496
- if (size === void 0) {
1497
- return;
1498
- }
1499
- const availableSpace = Math.max(0, state.scrollLength - size);
1500
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1501
- const contentSize = getContentSize(ctx);
1502
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1503
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1504
- const delta = clampedDesiredOffset - state.scroll;
1505
- if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1506
- const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1507
- if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1508
- state.initialAnchor = void 0;
1509
- } else {
1510
- anchor.settledTicks = settledTicks;
1511
- }
1512
- return;
1513
- }
1514
- if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1515
- state.initialAnchor = void 0;
1516
- return;
1517
- }
1518
- const lastDelta = anchor.lastDelta;
1519
- if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1520
- state.initialAnchor = void 0;
1521
- return;
1522
- }
1523
- Object.assign(anchor, {
1524
- attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1525
- lastDelta: delta,
1526
- settledTicks: 0
1527
- });
1528
- requestAdjust(ctx, state, delta);
1529
- }
1530
-
1531
1611
  // src/core/mvcp.ts
1532
- function prepareMVCP(ctx, state, dataChanged) {
1612
+ function prepareMVCP(ctx, dataChanged) {
1613
+ const state = ctx.state;
1533
1614
  const { idsInView, positions, props } = state;
1534
1615
  const { maintainVisibleContentPosition } = props;
1535
- const scrollingTo = peek$(ctx, "scrollingTo");
1616
+ const scrollingTo = state.scrollingTo;
1536
1617
  let prevPosition;
1537
1618
  let targetId;
1538
1619
  const idsInViewWithPositions = [];
1539
1620
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1621
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1540
1622
  const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1541
1623
  const indexByKey = state.indexByKey;
1542
1624
  if (shouldMVCP) {
1543
1625
  if (scrollTarget !== void 0) {
1544
1626
  targetId = getId(state, scrollTarget);
1545
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1627
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1546
1628
  if (dataChanged) {
1547
1629
  for (let i = 0; i < idsInView.length; i++) {
1548
1630
  const id = idsInView[i];
@@ -1559,7 +1641,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1559
1641
  prevPosition = positions.get(targetId);
1560
1642
  }
1561
1643
  return () => {
1562
- let positionDiff;
1644
+ let positionDiff = 0;
1563
1645
  if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1564
1646
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1565
1647
  const { id, position } = idsInViewWithPositions[i];
@@ -1585,16 +1667,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1585
1667
  positionDiff = diff;
1586
1668
  }
1587
1669
  }
1588
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1589
- requestAdjust(ctx, state, positionDiff);
1670
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1671
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1672
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1673
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1674
+ const diff = newSize - prevSize;
1675
+ if (diff !== 0) {
1676
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1677
+ scrollingTo.itemSize = newSize;
1678
+ }
1679
+ }
1680
+ }
1681
+ if (Math.abs(positionDiff) > 0.1) {
1682
+ requestAdjust(ctx, positionDiff);
1590
1683
  }
1591
1684
  };
1592
1685
  }
1593
1686
  }
1594
1687
 
1595
1688
  // src/core/prepareColumnStartState.ts
1596
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1689
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1597
1690
  var _a3;
1691
+ const state = ctx.state;
1598
1692
  const numColumns = peek$(ctx, "numColumns");
1599
1693
  let rowStartIndex = startIndex;
1600
1694
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1609,7 +1703,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1609
1703
  const prevId = state.idCache[prevIndex];
1610
1704
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1611
1705
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1612
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1706
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1613
1707
  currentRowTop = prevPosition + prevRowHeight;
1614
1708
  }
1615
1709
  return {
@@ -1632,7 +1726,8 @@ function findRowStartIndex(state, numColumns, index) {
1632
1726
  }
1633
1727
  return rowStart;
1634
1728
  }
1635
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1729
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1730
+ const state = ctx.state;
1636
1731
  if (endIndex < startIndex) {
1637
1732
  return 0;
1638
1733
  }
@@ -1646,7 +1741,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1646
1741
  continue;
1647
1742
  }
1648
1743
  const id = state.idCache[i];
1649
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1744
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1650
1745
  if (size > maxSize) {
1651
1746
  maxSize = size;
1652
1747
  }
@@ -1655,22 +1750,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1655
1750
  }
1656
1751
 
1657
1752
  // src/core/updateTotalSize.ts
1658
- function updateTotalSize(ctx, state) {
1753
+ function updateTotalSize(ctx) {
1754
+ const state = ctx.state;
1659
1755
  const {
1660
1756
  positions,
1661
1757
  props: { data }
1662
1758
  } = state;
1663
1759
  if (data.length === 0) {
1664
- addTotalSize(ctx, state, null, 0);
1760
+ addTotalSize(ctx, null, 0);
1665
1761
  } else {
1666
1762
  const lastId = getId(state, data.length - 1);
1667
1763
  if (lastId !== void 0) {
1668
1764
  const lastPosition = positions.get(lastId);
1669
1765
  if (lastPosition !== void 0) {
1670
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1766
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1671
1767
  if (lastSize !== void 0) {
1672
1768
  const totalSize = lastPosition + lastSize;
1673
- addTotalSize(ctx, state, null, totalSize);
1769
+ addTotalSize(ctx, null, totalSize);
1674
1770
  }
1675
1771
  }
1676
1772
  }
@@ -1716,7 +1812,8 @@ var getScrollVelocity = (state) => {
1716
1812
  };
1717
1813
 
1718
1814
  // src/utils/updateSnapToOffsets.ts
1719
- function updateSnapToOffsets(ctx, state) {
1815
+ function updateSnapToOffsets(ctx) {
1816
+ const state = ctx.state;
1720
1817
  const {
1721
1818
  positions,
1722
1819
  props: { snapToIndices }
@@ -1731,30 +1828,30 @@ function updateSnapToOffsets(ctx, state) {
1731
1828
  }
1732
1829
 
1733
1830
  // src/core/updateItemPositions.ts
1734
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1831
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1735
1832
  doMVCP: false,
1736
1833
  forceFullUpdate: false,
1737
1834
  scrollBottomBuffered: -1,
1738
1835
  startIndex: 0
1739
1836
  }) {
1740
1837
  var _a3, _b, _c, _d, _e;
1838
+ const state = ctx.state;
1741
1839
  const {
1742
1840
  columns,
1743
1841
  indexByKey,
1744
1842
  positions,
1745
1843
  idCache,
1746
1844
  sizesKnown,
1747
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1845
+ props: { data, getEstimatedItemSize, snapToIndices },
1846
+ scrollingTo
1748
1847
  } = state;
1749
- const data = state.props.data;
1750
1848
  const dataLength = data.length;
1751
1849
  const numColumns = peek$(ctx, "numColumns");
1752
- const scrollingTo = peek$(ctx, "scrollingTo");
1753
1850
  const hasColumns = numColumns > 1;
1754
1851
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1755
1852
  const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1756
1853
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1757
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1854
+ const useAverageSize = !getEstimatedItemSize;
1758
1855
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1759
1856
  let currentRowTop = 0;
1760
1857
  let column = 1;
@@ -1763,7 +1860,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1763
1860
  if (hasColumns) {
1764
1861
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1765
1862
  ctx,
1766
- state,
1767
1863
  startIndex,
1768
1864
  useAverageSize
1769
1865
  );
@@ -1773,7 +1869,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1773
1869
  const prevIndex = startIndex - 1;
1774
1870
  const prevId = getId(state, prevIndex);
1775
1871
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1776
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1872
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1777
1873
  currentRowTop = prevPosition + prevSize;
1778
1874
  }
1779
1875
  }
@@ -1790,7 +1886,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1790
1886
  breakAt = i + itemsPerRow + 10;
1791
1887
  }
1792
1888
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1793
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1889
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1794
1890
  if (IS_DEV && needsIndexByKey) {
1795
1891
  if (indexByKeyForChecking.has(id)) {
1796
1892
  console.error(
@@ -1799,7 +1895,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1799
1895
  }
1800
1896
  indexByKeyForChecking.set(id, i);
1801
1897
  }
1802
- positions.set(id, currentRowTop);
1898
+ if (currentRowTop !== positions.get(id)) {
1899
+ positions.set(id, currentRowTop);
1900
+ notifyPosition$(ctx, id, currentRowTop);
1901
+ }
1803
1902
  if (needsIndexByKey) {
1804
1903
  indexByKey.set(id, i);
1805
1904
  }
@@ -1819,10 +1918,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1819
1918
  }
1820
1919
  }
1821
1920
  if (!didBreakEarly) {
1822
- updateTotalSize(ctx, state);
1921
+ updateTotalSize(ctx);
1823
1922
  }
1824
1923
  if (snapToIndices) {
1825
- updateSnapToOffsets(ctx, state);
1924
+ updateSnapToOffsets(ctx);
1826
1925
  }
1827
1926
  }
1828
1927
 
@@ -1900,7 +1999,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1900
1999
  if (previousViewableItems) {
1901
2000
  for (const viewToken of previousViewableItems) {
1902
2001
  const containerId = findContainerId(ctx, viewToken.key);
1903
- if (!isViewable(
2002
+ if (!checkIsViewable(
1904
2003
  state,
1905
2004
  ctx,
1906
2005
  viewabilityConfig,
@@ -1921,7 +2020,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1921
2020
  if (item) {
1922
2021
  const key = getId(state, i);
1923
2022
  const containerId = findContainerId(ctx, key);
1924
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2023
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1925
2024
  const viewToken = {
1926
2025
  containerId,
1927
2026
  index: i,
@@ -1981,11 +2080,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1981
2080
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
1982
2081
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
1983
2082
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
1984
- const isViewable2 = percent >= viewablePercentThreshold;
2083
+ const isViewable = percent >= viewablePercentThreshold;
1985
2084
  const value = {
1986
2085
  containerId,
1987
2086
  index,
1988
- isViewable: isViewable2,
2087
+ isViewable,
1989
2088
  item,
1990
2089
  key,
1991
2090
  percentOfScroller,
@@ -2004,8 +2103,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2004
2103
  }
2005
2104
  return value;
2006
2105
  }
2007
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2008
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2106
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2107
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2108
+ if (!value || value.key !== key) {
2109
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2110
+ }
2009
2111
  return value.isViewable;
2010
2112
  }
2011
2113
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -2033,8 +2135,9 @@ function checkAllSizesKnown(state) {
2033
2135
  }
2034
2136
 
2035
2137
  // src/utils/findAvailableContainers.ts
2036
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2138
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2037
2139
  const numContainers = peek$(ctx, "numContainers");
2140
+ const state = ctx.state;
2038
2141
  const { stickyContainerPool, containerItemTypes } = state;
2039
2142
  const result = [];
2040
2143
  const availableContainers = [];
@@ -2078,14 +2181,14 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
2078
2181
  continue;
2079
2182
  }
2080
2183
  const key = peek$(ctx, `containerItemKey${u}`);
2081
- let isOk = key === void 0;
2082
- if (!isOk && pendingRemovalSet.has(u)) {
2083
- pendingRemovalSet.delete(u);
2084
- pendingRemovalChanged = true;
2085
- const requiredType = neededTypes[typeIndex];
2086
- isOk = canReuseContainer(u, requiredType);
2087
- }
2088
- if (isOk) {
2184
+ const requiredType = neededTypes[typeIndex];
2185
+ const isPending = key !== void 0 && pendingRemovalSet.has(u);
2186
+ const canUse = key === void 0 || isPending && canReuseContainer(u, requiredType);
2187
+ if (canUse) {
2188
+ if (isPending) {
2189
+ pendingRemovalSet.delete(u);
2190
+ pendingRemovalChanged = true;
2191
+ }
2089
2192
  result.push(u);
2090
2193
  if (requiredItemTypes) {
2091
2194
  typeIndex++;
@@ -2154,21 +2257,26 @@ function comparatorByDistance(a, b) {
2154
2257
  }
2155
2258
 
2156
2259
  // src/core/scrollToIndex.ts
2157
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2158
- if (index >= state.props.data.length) {
2159
- index = state.props.data.length - 1;
2260
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2261
+ const state = ctx.state;
2262
+ const { data } = state.props;
2263
+ if (index >= data.length) {
2264
+ index = data.length - 1;
2160
2265
  } else if (index < 0) {
2161
2266
  index = 0;
2162
2267
  }
2163
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2164
- const isLast = index === state.props.data.length - 1;
2268
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2269
+ const isLast = index === data.length - 1;
2165
2270
  if (isLast && viewPosition === void 0) {
2166
2271
  viewPosition = 1;
2167
2272
  }
2168
2273
  state.scrollForNextCalculateItemsInView = void 0;
2169
- scrollTo(ctx, state, {
2274
+ const targetId = getId(state, index);
2275
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2276
+ scrollTo(ctx, {
2170
2277
  animated,
2171
2278
  index,
2279
+ itemSize,
2172
2280
  offset: firstIndexOffset,
2173
2281
  viewOffset,
2174
2282
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2176,16 +2284,17 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2176
2284
  }
2177
2285
 
2178
2286
  // src/utils/setDidLayout.ts
2179
- function setDidLayout(ctx, state) {
2287
+ function setDidLayout(ctx) {
2288
+ const state = ctx.state;
2180
2289
  const {
2181
2290
  loadStartTime,
2182
2291
  initialScroll,
2183
2292
  props: { onLoad }
2184
2293
  } = state;
2185
2294
  state.queuedInitialLayout = true;
2186
- checkAtBottom(ctx, state);
2295
+ checkAtBottom(ctx);
2187
2296
  const setIt = () => {
2188
- set$(ctx, "containersDidLayout", true);
2297
+ setInitialRenderState(ctx, { didLayout: true });
2189
2298
  if (onLoad) {
2190
2299
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2191
2300
  }
@@ -2210,15 +2319,17 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2210
2319
  }
2211
2320
  return -1;
2212
2321
  }
2213
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2322
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2323
+ const state = ctx.state;
2214
2324
  return new Set(
2215
2325
  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))
2216
2326
  );
2217
2327
  }
2218
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2328
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2219
2329
  var _a3;
2220
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2221
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2330
+ const state = ctx.state;
2331
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2332
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2222
2333
  for (let offset = 0; offset <= 1; offset++) {
2223
2334
  const idx = currentStickyIdx - offset;
2224
2335
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -2229,8 +2340,9 @@ function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, cu
2229
2340
  }
2230
2341
  }
2231
2342
  }
2232
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2343
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2233
2344
  var _a3, _b, _c;
2345
+ const state = ctx.state;
2234
2346
  for (const containerIndex of state.stickyContainerPool) {
2235
2347
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2236
2348
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
@@ -2254,7 +2366,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2254
2366
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2255
2367
  if (currentId) {
2256
2368
  const currentPos = state.positions.get(currentId);
2257
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2369
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2258
2370
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2259
2371
  }
2260
2372
  }
@@ -2263,7 +2375,8 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2263
2375
  }
2264
2376
  }
2265
2377
  }
2266
- function calculateItemsInView(ctx, state, params = {}) {
2378
+ function calculateItemsInView(ctx, params = {}) {
2379
+ const state = ctx.state;
2267
2380
  unstable_batchedUpdates(() => {
2268
2381
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2269
2382
  const {
@@ -2287,9 +2400,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2287
2400
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2288
2401
  const prevNumContainers = peek$(ctx, "numContainers");
2289
2402
  if (!data || scrollLength === 0 || !prevNumContainers) {
2290
- if (state.initialAnchor) {
2291
- ensureInitialAnchor(ctx, state);
2292
- }
2293
2403
  return;
2294
2404
  }
2295
2405
  const totalSize = getContentSize(ctx);
@@ -2303,15 +2413,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2303
2413
  if (!queuedInitialLayout && initialScroll) {
2304
2414
  const updatedOffset = calculateOffsetWithOffsetPosition(
2305
2415
  ctx,
2306
- state,
2307
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2416
+ calculateOffsetForIndex(ctx, initialScroll.index),
2308
2417
  initialScroll
2309
2418
  );
2310
2419
  scrollState = updatedOffset;
2311
2420
  }
2312
2421
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2313
2422
  const scrollAdjustPad = scrollAdjustPending - topPad;
2314
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2423
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2315
2424
  if (scroll + scrollLength > totalSize) {
2316
2425
  scroll = Math.max(0, totalSize - scrollLength);
2317
2426
  }
@@ -2319,11 +2428,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2319
2428
  set$(ctx, "debugRawScroll", scrollState);
2320
2429
  set$(ctx, "debugComputedScroll", scroll);
2321
2430
  }
2322
- const previousStickyIndex = state.activeStickyIndex;
2431
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2323
2432
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2324
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2325
- state.activeStickyIndex = nextActiveStickyIndex;
2326
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2433
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2434
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2435
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2436
+ }
2327
2437
  let scrollBufferTop = scrollBuffer;
2328
2438
  let scrollBufferBottom = scrollBuffer;
2329
2439
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2336,23 +2446,20 @@ function calculateItemsInView(ctx, state, params = {}) {
2336
2446
  const scrollTopBuffered = scroll - scrollBufferTop;
2337
2447
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2338
2448
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2339
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2449
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2340
2450
  const { top, bottom } = scrollForNextCalculateItemsInView;
2341
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2342
- if (state.initialAnchor) {
2343
- ensureInitialAnchor(ctx, state);
2344
- }
2451
+ if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2345
2452
  return;
2346
2453
  }
2347
2454
  }
2348
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2455
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2349
2456
  if (dataChanged) {
2350
2457
  indexByKey.clear();
2351
2458
  idCache.length = 0;
2352
2459
  positions.clear();
2353
2460
  }
2354
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2355
- updateItemPositions(ctx, state, dataChanged, {
2461
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2462
+ updateItemPositions(ctx, dataChanged, {
2356
2463
  doMVCP,
2357
2464
  forceFullUpdate: !!forceFullItemPositions,
2358
2465
  scrollBottomBuffered,
@@ -2371,9 +2478,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2371
2478
  for (let i = loopStart; i >= 0; i--) {
2372
2479
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2373
2480
  const top = positions.get(id);
2374
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2481
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2375
2482
  const bottom = top + size;
2376
- if (bottom > scroll - scrollBuffer) {
2483
+ if (bottom > scroll - scrollBufferTop) {
2377
2484
  loopStart = i;
2378
2485
  } else {
2379
2486
  break;
@@ -2398,7 +2505,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2398
2505
  const dataLength = data.length;
2399
2506
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2400
2507
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2401
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2508
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2402
2509
  const top = positions.get(id);
2403
2510
  if (!foundEnd) {
2404
2511
  if (startNoBuffer === null && top + size > scroll) {
@@ -2410,7 +2517,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2410
2517
  if (startBuffered === null && top + size > scrollTopBuffered) {
2411
2518
  startBuffered = i;
2412
2519
  startBufferedId = id;
2413
- nextTop = top;
2520
+ if (scrollTopBuffered < 0) {
2521
+ nextTop = null;
2522
+ } else {
2523
+ nextTop = top;
2524
+ }
2414
2525
  }
2415
2526
  if (startNoBuffer !== null) {
2416
2527
  if (top <= scrollBottom) {
@@ -2418,7 +2529,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2418
2529
  }
2419
2530
  if (top <= scrollBottomBuffered) {
2420
2531
  endBuffered = i;
2421
- nextBottom = top + size;
2532
+ if (scrollBottomBuffered > totalSize) {
2533
+ nextBottom = null;
2534
+ } else {
2535
+ nextBottom = top + size;
2536
+ }
2422
2537
  } else {
2423
2538
  foundEnd = true;
2424
2539
  }
@@ -2445,7 +2560,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2445
2560
  top: nextTop
2446
2561
  } : void 0;
2447
2562
  }
2448
- const numContainers = peek$(ctx, "numContainers");
2563
+ let numContainers = prevNumContainers;
2449
2564
  const pendingRemoval = [];
2450
2565
  if (dataChanged) {
2451
2566
  for (let i = 0; i < numContainers; i++) {
@@ -2456,7 +2571,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2456
2571
  }
2457
2572
  }
2458
2573
  if (startBuffered !== null && endBuffered !== null) {
2459
- let numContainers2 = prevNumContainers;
2460
2574
  const needNewContainers = [];
2461
2575
  for (let i = startBuffered; i <= endBuffered; i++) {
2462
2576
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
@@ -2467,7 +2581,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2467
2581
  if (stickyIndicesArr.length > 0) {
2468
2582
  handleStickyActivation(
2469
2583
  ctx,
2470
- state,
2471
2584
  stickyIndicesSet,
2472
2585
  stickyIndicesArr,
2473
2586
  currentStickyIdx,
@@ -2475,9 +2588,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2475
2588
  startBuffered,
2476
2589
  endBuffered
2477
2590
  );
2478
- } else {
2479
- state.activeStickyIndex = void 0;
2480
- set$(ctx, "activeStickyIndex", void 0);
2591
+ } else if (previousStickyIndex !== -1) {
2592
+ set$(ctx, "activeStickyIndex", -1);
2481
2593
  }
2482
2594
  if (needNewContainers.length > 0) {
2483
2595
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2486,7 +2598,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2486
2598
  }) : void 0;
2487
2599
  const availableContainers = findAvailableContainers(
2488
2600
  ctx,
2489
- state,
2490
2601
  needNewContainers.length,
2491
2602
  startBuffered,
2492
2603
  endBuffered,
@@ -2508,29 +2619,30 @@ function calculateItemsInView(ctx, state, params = {}) {
2508
2619
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2509
2620
  }
2510
2621
  containerItemKeys.add(id);
2622
+ const containerSticky = `containerSticky${containerIndex}`;
2511
2623
  if (stickyIndicesSet.has(i)) {
2512
- set$(ctx, `containerSticky${containerIndex}`, true);
2624
+ set$(ctx, containerSticky, true);
2513
2625
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2514
2626
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2515
2627
  state.stickyContainerPool.add(containerIndex);
2516
- } else {
2517
- set$(ctx, `containerSticky${containerIndex}`, false);
2628
+ } else if (peek$(ctx, containerSticky)) {
2629
+ set$(ctx, containerSticky, false);
2518
2630
  state.stickyContainerPool.delete(containerIndex);
2519
2631
  }
2520
- if (containerIndex >= numContainers2) {
2521
- numContainers2 = containerIndex + 1;
2632
+ if (containerIndex >= numContainers) {
2633
+ numContainers = containerIndex + 1;
2522
2634
  }
2523
2635
  }
2524
- if (numContainers2 !== prevNumContainers) {
2525
- set$(ctx, "numContainers", numContainers2);
2526
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2527
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2636
+ if (numContainers !== prevNumContainers) {
2637
+ set$(ctx, "numContainers", numContainers);
2638
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2639
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2528
2640
  }
2529
2641
  }
2530
2642
  }
2531
2643
  }
2532
2644
  if (stickyIndicesArr.length > 0) {
2533
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2645
+ handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2534
2646
  }
2535
2647
  let didChangePositions = false;
2536
2648
  for (let i = 0; i < numContainers; i++) {
@@ -2582,7 +2694,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2582
2694
  }
2583
2695
  if (!queuedInitialLayout && endBuffered !== null) {
2584
2696
  if (checkAllSizesKnown(state)) {
2585
- setDidLayout(ctx, state);
2697
+ setDidLayout(ctx);
2586
2698
  }
2587
2699
  }
2588
2700
  if (viewabilityConfigCallbackPairs) {
@@ -2595,9 +2707,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2595
2707
  }
2596
2708
  }
2597
2709
  });
2598
- if (state.initialAnchor) {
2599
- ensureInitialAnchor(ctx, state);
2600
- }
2601
2710
  }
2602
2711
 
2603
2712
  // src/core/checkActualChange.ts
@@ -2620,20 +2729,69 @@ function checkActualChange(state, dataProp, previousData) {
2620
2729
  return false;
2621
2730
  }
2622
2731
 
2732
+ // src/core/checkFinishedScroll.ts
2733
+ function checkFinishedScroll(ctx) {
2734
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2735
+ }
2736
+ function checkFinishedScrollFrame(ctx) {
2737
+ const scrollingTo = ctx.state.scrollingTo;
2738
+ if (scrollingTo) {
2739
+ const { state } = ctx;
2740
+ state.animFrameCheckFinishedScroll = void 0;
2741
+ const scroll = state.scroll;
2742
+ const adjust = state.scrollAdjustHandler.getAdjust();
2743
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
2744
+ const maxOffset = clampScrollOffset(ctx, scroll);
2745
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
2746
+ const diff2 = Math.abs(diff1 - adjust);
2747
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
2748
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
2749
+ finishScrollTo(ctx);
2750
+ }
2751
+ }
2752
+ }
2753
+ function checkFinishedScrollFallback(ctx) {
2754
+ const state = ctx.state;
2755
+ const scrollingTo = state.scrollingTo;
2756
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
2757
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
2758
+ () => {
2759
+ let numChecks = 0;
2760
+ const checkHasScrolled = () => {
2761
+ state.timeoutCheckFinishedScrollFallback = void 0;
2762
+ const isStillScrollingTo = state.scrollingTo;
2763
+ if (isStillScrollingTo) {
2764
+ numChecks++;
2765
+ if (state.hasScrolled || numChecks > 5) {
2766
+ finishScrollTo(ctx);
2767
+ } else {
2768
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
2769
+ }
2770
+ }
2771
+ };
2772
+ checkHasScrolled();
2773
+ },
2774
+ slowTimeout ? 500 : 100
2775
+ );
2776
+ }
2777
+
2623
2778
  // src/core/doMaintainScrollAtEnd.ts
2624
- function doMaintainScrollAtEnd(ctx, state, animated) {
2779
+ function doMaintainScrollAtEnd(ctx, animated) {
2780
+ const state = ctx.state;
2625
2781
  const {
2782
+ didContainersLayout,
2783
+ isAtEnd,
2626
2784
  refScroller,
2627
2785
  props: { maintainScrollAtEnd }
2628
2786
  } = state;
2629
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2787
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2630
2788
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2631
2789
  if (paddingTop > 0) {
2632
2790
  state.scroll = 0;
2633
2791
  }
2634
2792
  requestAnimationFrame(() => {
2635
2793
  var _a3;
2636
- if (state == null ? void 0 : state.isAtEnd) {
2794
+ if (state.isAtEnd) {
2637
2795
  state.maintainingScrollAtEnd = true;
2638
2796
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2639
2797
  animated
@@ -2704,28 +2862,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2704
2862
  }
2705
2863
 
2706
2864
  // src/core/checkResetContainers.ts
2707
- function checkResetContainers(ctx, state, dataProp) {
2865
+ function checkResetContainers(ctx, dataProp) {
2866
+ const state = ctx.state;
2708
2867
  const { previousData } = state;
2709
2868
  if (previousData) {
2710
2869
  updateAveragesOnDataChange(state, previousData, dataProp);
2711
2870
  }
2712
2871
  const { maintainScrollAtEnd } = state.props;
2713
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2872
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2714
2873
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2715
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2874
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2716
2875
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2717
2876
  state.isEndReached = false;
2718
2877
  }
2719
2878
  if (!didMaintainScrollAtEnd) {
2720
2879
  checkAtTop(state);
2721
- checkAtBottom(ctx, state);
2880
+ checkAtBottom(ctx);
2722
2881
  }
2723
2882
  delete state.previousData;
2724
2883
  }
2725
2884
 
2726
2885
  // src/core/doInitialAllocateContainers.ts
2727
- function doInitialAllocateContainers(ctx, state) {
2886
+ function doInitialAllocateContainers(ctx) {
2728
2887
  var _a3, _b, _c;
2888
+ const state = ctx.state;
2729
2889
  const {
2730
2890
  scrollLength,
2731
2891
  props: {
@@ -2763,10 +2923,10 @@ function doInitialAllocateContainers(ctx, state) {
2763
2923
  if (state.lastLayout) {
2764
2924
  if (state.initialScroll) {
2765
2925
  requestAnimationFrame(() => {
2766
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2926
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2767
2927
  });
2768
2928
  } else {
2769
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2929
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2770
2930
  }
2771
2931
  }
2772
2932
  return true;
@@ -2774,7 +2934,8 @@ function doInitialAllocateContainers(ctx, state) {
2774
2934
  }
2775
2935
 
2776
2936
  // src/core/handleLayout.ts
2777
- function handleLayout(ctx, state, layout, setCanRender) {
2937
+ function handleLayout(ctx, layout, setCanRender) {
2938
+ const state = ctx.state;
2778
2939
  const { maintainScrollAtEnd } = state.props;
2779
2940
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2780
2941
  const previousLength = state.scrollLength;
@@ -2790,19 +2951,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2790
2951
  state.lastBatchingAction = Date.now();
2791
2952
  state.scrollForNextCalculateItemsInView = void 0;
2792
2953
  if (scrollLength > 0) {
2793
- doInitialAllocateContainers(ctx, state);
2954
+ doInitialAllocateContainers(ctx);
2794
2955
  }
2795
2956
  if (needsCalculate) {
2796
- calculateItemsInView(ctx, state, { doMVCP: true });
2957
+ calculateItemsInView(ctx, { doMVCP: true });
2797
2958
  }
2798
2959
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2799
2960
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2800
2961
  }
2801
2962
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2802
- doMaintainScrollAtEnd(ctx, state, false);
2963
+ doMaintainScrollAtEnd(ctx, false);
2803
2964
  }
2804
- updateAlignItemsPaddingTop(ctx, state);
2805
- checkAtBottom(ctx, state);
2965
+ updateAlignItemsPaddingTop(ctx);
2966
+ checkAtBottom(ctx);
2806
2967
  checkAtTop(state);
2807
2968
  if (state) {
2808
2969
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2818,8 +2979,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2818
2979
  }
2819
2980
 
2820
2981
  // src/core/onScroll.ts
2821
- function onScroll(ctx, state, event) {
2982
+ function onScroll(ctx, event) {
2822
2983
  var _a3, _b, _c;
2984
+ const state = ctx.state;
2823
2985
  const {
2824
2986
  scrollProcessingEnabled,
2825
2987
  props: { onScroll: onScrollProp }
@@ -2830,9 +2992,23 @@ function onScroll(ctx, state, event) {
2830
2992
  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) {
2831
2993
  return;
2832
2994
  }
2833
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2995
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2834
2996
  state.scrollPending = newScroll;
2835
- updateScroll(ctx, state, newScroll);
2997
+ if (state.scrollingTo) {
2998
+ const maxOffset = clampScrollOffset(ctx, newScroll);
2999
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3000
+ newScroll = maxOffset;
3001
+ scrollTo(ctx, {
3002
+ forceScroll: true,
3003
+ isInitialScroll: true,
3004
+ noScrollingTo: true,
3005
+ offset: newScroll
3006
+ });
3007
+ return;
3008
+ }
3009
+ }
3010
+ updateScroll(ctx, newScroll);
3011
+ checkFinishedScroll(ctx);
2836
3012
  onScrollProp == null ? void 0 : onScrollProp(event);
2837
3013
  }
2838
3014
 
@@ -2841,51 +3017,47 @@ var ScrollAdjustHandler = class {
2841
3017
  constructor(ctx) {
2842
3018
  this.appliedAdjust = 0;
2843
3019
  this.pendingAdjust = 0;
2844
- this.mounted = false;
2845
- this.context = ctx;
2846
- {
2847
- const commitPendingAdjust = () => {
2848
- const state = this.context.internalState;
2849
- const pending = this.pendingAdjust;
2850
- if (pending !== 0) {
2851
- this.pendingAdjust = 0;
2852
- this.appliedAdjust += pending;
2853
- state.scroll += pending;
2854
- state.scrollForNextCalculateItemsInView = void 0;
2855
- set$(this.context, "scrollAdjustPending", 0);
2856
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2857
- calculateItemsInView(this.context, this.context.internalState);
2858
- }
2859
- };
2860
- listen$(this.context, "scrollingTo", (value) => {
2861
- if (value === void 0) {
2862
- commitPendingAdjust();
2863
- }
2864
- });
2865
- }
3020
+ this.ctx = ctx;
2866
3021
  }
2867
3022
  requestAdjust(add) {
2868
- const scrollingTo = peek$(this.context, "scrollingTo");
3023
+ const scrollingTo = this.ctx.state.scrollingTo;
2869
3024
  if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2870
3025
  this.pendingAdjust += add;
2871
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
3026
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2872
3027
  } else {
2873
3028
  this.appliedAdjust += add;
2874
- set$(this.context, "scrollAdjust", this.appliedAdjust);
3029
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3030
+ }
3031
+ if (this.ctx.state.scrollingTo) {
3032
+ checkFinishedScroll(this.ctx);
2875
3033
  }
2876
- }
2877
- setMounted() {
2878
- this.mounted = true;
2879
3034
  }
2880
3035
  getAdjust() {
2881
3036
  return this.appliedAdjust;
2882
3037
  }
3038
+ commitPendingAdjust() {
3039
+ {
3040
+ const state = this.ctx.state;
3041
+ const pending = this.pendingAdjust;
3042
+ if (pending !== 0) {
3043
+ this.pendingAdjust = 0;
3044
+ this.appliedAdjust += pending;
3045
+ state.scroll += pending;
3046
+ state.scrollForNextCalculateItemsInView = void 0;
3047
+ set$(this.ctx, "scrollAdjustPending", 0);
3048
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3049
+ calculateItemsInView(this.ctx);
3050
+ }
3051
+ }
3052
+ }
2883
3053
  };
2884
3054
 
2885
3055
  // src/core/updateItemSize.ts
2886
- function updateItemSize(ctx, state, itemKey, sizeObj) {
3056
+ function updateItemSize(ctx, itemKey, sizeObj) {
2887
3057
  var _a3;
3058
+ const state = ctx.state;
2888
3059
  const {
3060
+ didContainersLayout,
2889
3061
  sizesKnown,
2890
3062
  props: {
2891
3063
  getFixedItemSize,
@@ -2913,13 +3085,12 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2913
3085
  return;
2914
3086
  }
2915
3087
  }
2916
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2917
- let needsRecalculate = !containersDidLayout;
3088
+ let needsRecalculate = !didContainersLayout;
2918
3089
  let shouldMaintainScrollAtEnd = false;
2919
3090
  let minIndexSizeChanged;
2920
3091
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2921
3092
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2922
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3093
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
2923
3094
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2924
3095
  if (diff !== 0) {
2925
3096
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
@@ -2968,22 +3139,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2968
3139
  if (!cur || maxOtherAxisSize > cur) {
2969
3140
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
2970
3141
  }
2971
- if (containersDidLayout || checkAllSizesKnown(state)) {
3142
+ if (didContainersLayout || checkAllSizesKnown(state)) {
2972
3143
  if (needsRecalculate) {
2973
3144
  state.scrollForNextCalculateItemsInView = void 0;
2974
- calculateItemsInView(ctx, state, { doMVCP: true });
3145
+ calculateItemsInView(ctx, { doMVCP: true });
2975
3146
  }
2976
3147
  if (shouldMaintainScrollAtEnd) {
2977
3148
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2978
- doMaintainScrollAtEnd(ctx, state, false);
3149
+ doMaintainScrollAtEnd(ctx, false);
2979
3150
  }
2980
3151
  }
2981
3152
  }
2982
3153
  }
2983
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3154
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
2984
3155
  var _a3;
3156
+ const state = ctx.state;
2985
3157
  const {
2986
- sizes,
2987
3158
  indexByKey,
2988
3159
  sizesKnown,
2989
3160
  averageSizes,
@@ -2991,9 +3162,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2991
3162
  } = state;
2992
3163
  if (!data) return 0;
2993
3164
  const index = indexByKey.get(itemKey);
2994
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3165
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
2995
3166
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2996
3167
  const size = Math.round(rawSize) ;
3168
+ const prevSizeKnown = sizesKnown.get(itemKey);
2997
3169
  sizesKnown.set(itemKey, size);
2998
3170
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2999
3171
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -3001,11 +3173,15 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3001
3173
  if (!averages) {
3002
3174
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3003
3175
  }
3004
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3005
- averages.num++;
3176
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3177
+ averages.avg += (size - prevSizeKnown) / averages.num;
3178
+ } else {
3179
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3180
+ averages.num++;
3181
+ }
3006
3182
  }
3007
3183
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
3008
- setSize(ctx, state, itemKey, size);
3184
+ setSize(ctx, itemKey, size);
3009
3185
  return size - prevSize;
3010
3186
  }
3011
3187
  return 0;
@@ -3052,14 +3228,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
3052
3228
  }
3053
3229
 
3054
3230
  // src/utils/createImperativeHandle.ts
3055
- function createImperativeHandle(ctx, state) {
3231
+ function createImperativeHandle(ctx) {
3232
+ const state = ctx.state;
3056
3233
  const scrollIndexIntoView = (options) => {
3057
3234
  if (state) {
3058
3235
  const { index, ...rest } = options;
3059
3236
  const { startNoBuffer, endNoBuffer } = state;
3060
3237
  if (index < startNoBuffer || index > endNoBuffer) {
3061
3238
  const viewPosition = index < startNoBuffer ? 0 : 1;
3062
- scrollToIndex(ctx, state, {
3239
+ scrollToIndex(ctx, {
3063
3240
  ...rest,
3064
3241
  index,
3065
3242
  viewPosition
@@ -3074,7 +3251,7 @@ function createImperativeHandle(ctx, state) {
3074
3251
  getScrollableNode: () => refScroller.current.getScrollableNode(),
3075
3252
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3076
3253
  getState: () => ({
3077
- activeStickyIndex: state.activeStickyIndex,
3254
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3078
3255
  contentLength: state.totalSize,
3079
3256
  data: state.props.data,
3080
3257
  elementAtIndex: (index) => {
@@ -3085,6 +3262,8 @@ function createImperativeHandle(ctx, state) {
3085
3262
  endBuffered: state.endBuffered,
3086
3263
  isAtEnd: state.isAtEnd,
3087
3264
  isAtStart: state.isAtStart,
3265
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3266
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3088
3267
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
3089
3268
  positions: state.positions,
3090
3269
  scroll: state.scroll,
@@ -3109,23 +3288,23 @@ function createImperativeHandle(ctx, state) {
3109
3288
  if (index !== -1) {
3110
3289
  const paddingBottom = stylePaddingBottom || 0;
3111
3290
  const footerSize = peek$(ctx, "footerSize") || 0;
3112
- scrollToIndex(ctx, state, {
3291
+ scrollToIndex(ctx, {
3292
+ ...options,
3113
3293
  index,
3114
3294
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3115
- viewPosition: 1,
3116
- ...options
3295
+ viewPosition: 1
3117
3296
  });
3118
3297
  }
3119
3298
  },
3120
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3299
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
3121
3300
  scrollToItem: ({ item, ...props }) => {
3122
3301
  const data = state.props.data;
3123
3302
  const index = data.indexOf(item);
3124
3303
  if (index !== -1) {
3125
- scrollToIndex(ctx, state, { index, ...props });
3304
+ scrollToIndex(ctx, { index, ...props });
3126
3305
  }
3127
3306
  },
3128
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3307
+ scrollToOffset: (params) => scrollTo(ctx, params),
3129
3308
  setScrollProcessingEnabled: (enabled) => {
3130
3309
  state.scrollProcessingEnabled = enabled;
3131
3310
  },
@@ -3135,8 +3314,9 @@ function createImperativeHandle(ctx, state) {
3135
3314
  }
3136
3315
  };
3137
3316
  }
3138
- function getRenderedItem(ctx, state, key) {
3317
+ function getRenderedItem(ctx, key) {
3139
3318
  var _a3;
3319
+ const state = ctx.state;
3140
3320
  if (!state) {
3141
3321
  return null;
3142
3322
  }
@@ -3213,11 +3393,13 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3213
3393
  var DEFAULT_DRAW_DISTANCE = 250;
3214
3394
  var DEFAULT_ITEM_SIZE = 100;
3215
3395
  var LegendList = typedMemo(
3396
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3216
3397
  typedForwardRef(function LegendList2(props, forwardedRef) {
3217
3398
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3218
3399
  const isChildrenMode = children !== void 0 && dataProp === void 0;
3219
3400
  const processedProps = isChildrenMode ? {
3220
3401
  ...restProps,
3402
+ childrenMode: true,
3221
3403
  data: (isArray(children) ? children : React3.Children.toArray(children)).flat(1),
3222
3404
  renderItem: ({ item }) => item
3223
3405
  } : {
@@ -3234,10 +3416,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3234
3416
  alignItemsAtEnd = false,
3235
3417
  columnWrapperStyle,
3236
3418
  contentContainerStyle: contentContainerStyleProp,
3419
+ contentInset,
3237
3420
  data: dataProp = [],
3238
3421
  dataVersion,
3239
3422
  drawDistance = 250,
3240
- enableAverages = true,
3241
3423
  estimatedItemSize: estimatedItemSizeProp,
3242
3424
  estimatedListSize,
3243
3425
  extraData,
@@ -3279,6 +3461,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3279
3461
  snapToIndices,
3280
3462
  stickyHeaderIndices: stickyHeaderIndicesProp,
3281
3463
  stickyIndices: stickyIndicesDeprecated,
3464
+ // TODOV3: Remove from v3 release
3282
3465
  style: styleProp,
3283
3466
  suggestEstimatedItemSize,
3284
3467
  viewabilityConfig,
@@ -3286,6 +3469,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3286
3469
  waitForInitialLayout = true,
3287
3470
  ...rest
3288
3471
  } = props;
3472
+ const animatedPropsInternal = props.animatedPropsInternal;
3473
+ const { childrenMode } = rest;
3289
3474
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3290
3475
  const style = { ...StyleSheet.flatten(styleProp) };
3291
3476
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
@@ -3309,10 +3494,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3309
3494
  }
3310
3495
  const refState = useRef();
3311
3496
  if (!refState.current) {
3312
- if (!ctx.internalState) {
3497
+ if (!ctx.state) {
3313
3498
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
3314
- ctx.internalState = {
3315
- activeStickyIndex: void 0,
3499
+ ctx.state = {
3500
+ activeStickyIndex: -1,
3316
3501
  averageSizes: {},
3317
3502
  columns: /* @__PURE__ */ new Map(),
3318
3503
  containerItemKeys: /* @__PURE__ */ new Set(),
@@ -3338,9 +3523,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3338
3523
  initialScroll: initialScrollProp,
3339
3524
  isAtEnd: false,
3340
3525
  isAtStart: false,
3341
- isEndReached: false,
3526
+ isEndReached: null,
3342
3527
  isFirst: true,
3343
- isStartReached: false,
3528
+ isStartReached: null,
3344
3529
  lastBatchingAction: Date.now(),
3345
3530
  lastLayout: void 0,
3346
3531
  loadStartTime: Date.now(),
@@ -3372,12 +3557,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3372
3557
  totalSize: 0,
3373
3558
  viewabilityConfigCallbackPairs: void 0
3374
3559
  };
3375
- const internalState = ctx.internalState;
3376
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3560
+ const internalState = ctx.state;
3561
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3377
3562
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3378
3563
  set$(ctx, "extraData", extraData);
3379
3564
  }
3380
- refState.current = ctx.internalState;
3565
+ refState.current = ctx.state;
3381
3566
  }
3382
3567
  const state = refState.current;
3383
3568
  const isFirstLocal = state.isFirst;
@@ -3391,9 +3576,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3391
3576
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3392
3577
  state.props = {
3393
3578
  alignItemsAtEnd,
3579
+ animatedProps: animatedPropsInternal,
3580
+ contentInset,
3394
3581
  data: dataProp,
3395
3582
  dataVersion,
3396
- enableAverages,
3397
3583
  estimatedItemSize,
3398
3584
  getEstimatedItemSize,
3399
3585
  getFixedItemSize,
@@ -3436,62 +3622,52 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3436
3622
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3437
3623
  set$(ctx, "numColumns", numColumnsProp);
3438
3624
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3439
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3625
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3440
3626
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3441
3627
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3442
3628
  if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3443
3629
  if (state.scroll < 0) {
3444
3630
  paddingDiff += state.scroll;
3445
3631
  }
3446
- requestAdjust(ctx, state, paddingDiff);
3632
+ requestAdjust(ctx, paddingDiff);
3447
3633
  }
3448
3634
  };
3449
3635
  if (isFirstLocal) {
3450
3636
  initializeStateVars();
3451
3637
  updateItemPositions(
3452
3638
  ctx,
3453
- state,
3454
3639
  /*dataChanged*/
3455
3640
  true
3456
3641
  );
3457
3642
  }
3458
3643
  const initialContentOffset = useMemo(() => {
3459
- var _a4, _b2;
3460
- const { initialScroll } = refState.current;
3461
- if (!initialScroll) {
3644
+ let value;
3645
+ const { initialScroll, initialAnchor } = refState.current;
3646
+ if (initialScroll) {
3647
+ if (initialScroll.contentOffset !== void 0) {
3648
+ value = initialScroll.contentOffset;
3649
+ } else {
3650
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3651
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3652
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3653
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3654
+ refState.current.initialScroll = updatedInitialScroll;
3655
+ state.initialScroll = updatedInitialScroll;
3656
+ value = clampedOffset;
3657
+ }
3658
+ } else {
3462
3659
  refState.current.initialAnchor = void 0;
3463
- return 0;
3464
- }
3465
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3466
- refState.current.initialAnchor = {
3467
- attempts: 0,
3468
- index: initialScroll.index,
3469
- settledTicks: 0,
3470
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3471
- viewPosition: initialScroll.viewPosition
3472
- };
3660
+ value = 0;
3661
+ }
3662
+ if (!value) {
3663
+ state.didFinishInitialScroll = true;
3473
3664
  }
3474
- if (initialScroll.contentOffset !== void 0) {
3475
- return initialScroll.contentOffset;
3476
- }
3477
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3478
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3479
- let clampedOffset = resolvedOffset;
3480
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3481
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3482
- clampedOffset = Math.min(clampedOffset, maxOffset);
3483
- }
3484
- clampedOffset = Math.max(0, clampedOffset);
3485
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3486
- refState.current.initialScroll = updatedInitialScroll;
3487
- state.initialScroll = updatedInitialScroll;
3488
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3489
- return clampedOffset;
3665
+ return value;
3490
3666
  }, [renderNum]);
3491
3667
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3492
3668
  refState.current.lastBatchingAction = Date.now();
3493
3669
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3494
- IS_DEV && warnDevOnce(
3670
+ IS_DEV && !childrenMode && warnDevOnce(
3495
3671
  "keyExtractor",
3496
3672
  "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."
3497
3673
  );
@@ -3514,12 +3690,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3514
3690
  }
3515
3691
  }, []);
3516
3692
  const doInitialScroll = useCallback(() => {
3517
- var _a4;
3518
3693
  const initialScroll = state.initialScroll;
3519
3694
  if (initialScroll) {
3520
- scrollTo(ctx, state, {
3695
+ scrollTo(ctx, {
3521
3696
  animated: false,
3522
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3697
+ index: initialScroll == null ? void 0 : initialScroll.index,
3523
3698
  isInitialScroll: true,
3524
3699
  offset: initialContentOffset,
3525
3700
  precomputedWithViewOffset: true
@@ -3528,7 +3703,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3528
3703
  }, [initialContentOffset]);
3529
3704
  const onLayoutChange = useCallback((layout) => {
3530
3705
  doInitialScroll();
3531
- handleLayout(ctx, state, layout, setCanRender);
3706
+ handleLayout(ctx, layout, setCanRender);
3532
3707
  }, []);
3533
3708
  const { onLayout } = useOnLayoutSync({
3534
3709
  onLayoutChange,
@@ -3538,7 +3713,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3538
3713
  });
3539
3714
  useLayoutEffect(() => {
3540
3715
  if (snapToIndices) {
3541
- updateSnapToOffsets(ctx, state);
3716
+ updateSnapToOffsets(ctx);
3542
3717
  }
3543
3718
  }, [snapToIndices]);
3544
3719
  useLayoutEffect(() => {
@@ -3548,9 +3723,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3548
3723
  isFirst,
3549
3724
  props: { data }
3550
3725
  } = state;
3551
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3726
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3552
3727
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3553
- checkResetContainers(ctx, state, data);
3728
+ checkResetContainers(ctx, data);
3554
3729
  }
3555
3730
  state.didColumnsChange = false;
3556
3731
  state.didDataChange = false;
@@ -3575,15 +3750,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3575
3750
  state.viewabilityConfigCallbackPairs = viewability;
3576
3751
  state.enableScrollForNextCalculateItemsInView = !viewability;
3577
3752
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3578
- useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3753
+ useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3579
3754
  {
3580
3755
  useEffect(doInitialScroll, []);
3581
3756
  }
3582
3757
  const fns = useMemo(
3583
3758
  () => ({
3584
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3585
- onScroll: (event) => onScroll(ctx, state, event),
3586
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3759
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
3760
+ onMomentumScrollEnd: (event) => {
3761
+ checkFinishedScrollFallback(ctx);
3762
+ if (onMomentumScrollEnd) {
3763
+ onMomentumScrollEnd(event);
3764
+ }
3765
+ },
3766
+ onScroll: (event) => onScroll(ctx, event),
3767
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3587
3768
  }),
3588
3769
  []
3589
3770
  );
@@ -3595,6 +3776,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3595
3776
  alignItemsAtEnd,
3596
3777
  canRender,
3597
3778
  contentContainerStyle,
3779
+ contentInset,
3598
3780
  getRenderedItem: fns.getRenderedItem,
3599
3781
  horizontal,
3600
3782
  initialContentOffset,
@@ -3603,16 +3785,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3603
3785
  maintainVisibleContentPosition,
3604
3786
  onLayout,
3605
3787
  onLayoutHeader,
3606
- onMomentumScrollEnd: (event) => {
3607
- {
3608
- requestAnimationFrame(() => {
3609
- finishScrollTo(ctx, refState.current);
3610
- });
3611
- }
3612
- if (onMomentumScrollEnd) {
3613
- onMomentumScrollEnd(event);
3614
- }
3615
- },
3788
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3616
3789
  onScroll: onScrollHandler,
3617
3790
  recycleItems,
3618
3791
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
@@ -3627,7 +3800,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3627
3800
  ),
3628
3801
  refScrollView: combinedRef,
3629
3802
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3630
- scrollEventThrottle: 16 ,
3803
+ scrollEventThrottle: 0,
3631
3804
  snapToIndices,
3632
3805
  stickyHeaderIndices,
3633
3806
  style,
@@ -3673,8 +3846,8 @@ function buildSectionListData({
3673
3846
  if (hasHeader) {
3674
3847
  const headerIndex = data.length;
3675
3848
  data.push({
3676
- kind: "header",
3677
3849
  key: `${sectionKey}:header`,
3850
+ kind: "header",
3678
3851
  section,
3679
3852
  sectionIndex
3680
3853
  });
@@ -3688,31 +3861,31 @@ function buildSectionListData({
3688
3861
  const itemKeyExtractor = (_b = section.keyExtractor) != null ? _b : keyExtractor;
3689
3862
  const itemKey = itemKeyExtractor(item, itemIndex);
3690
3863
  data.push({
3691
- kind: "item",
3692
- key: `${sectionKey}:item:${itemKey}`,
3693
- section,
3694
- sectionIndex,
3864
+ absoluteItemIndex: absoluteItemIndex++,
3695
3865
  item,
3696
3866
  itemIndex,
3697
- absoluteItemIndex: absoluteItemIndex++
3867
+ key: `${sectionKey}:item:${itemKey}`,
3868
+ kind: "item",
3869
+ section,
3870
+ sectionIndex
3698
3871
  });
3699
3872
  meta.items.push(data.length - 1);
3700
3873
  if (hasItemSeparator && itemIndex < items.length - 1) {
3701
3874
  data.push({
3702
- kind: "item-separator",
3703
3875
  key: `${sectionKey}:separator:${itemIndex}`,
3704
- section,
3705
- sectionIndex,
3876
+ kind: "item-separator",
3706
3877
  leadingItem: item,
3707
3878
  leadingItemIndex: itemIndex,
3879
+ section,
3880
+ sectionIndex,
3708
3881
  trailingItem: items[itemIndex + 1]
3709
3882
  });
3710
3883
  }
3711
3884
  }
3712
3885
  if (hasFooter) {
3713
3886
  data.push({
3714
- kind: "footer",
3715
3887
  key: `${sectionKey}:footer`,
3888
+ kind: "footer",
3716
3889
  section,
3717
3890
  sectionIndex
3718
3891
  });
@@ -3721,8 +3894,8 @@ function buildSectionListData({
3721
3894
  const isLastSection = sectionIndex === sections.length - 1;
3722
3895
  if (hasSectionSeparator && !isLastSection) {
3723
3896
  data.push({
3724
- kind: "section-separator",
3725
3897
  key: `${sectionKey}:section-separator`,
3898
+ kind: "section-separator",
3726
3899
  leadingSection: section,
3727
3900
  leadingSectionIndex: sectionIndex,
3728
3901
  trailingSection: sections[sectionIndex + 1]