@legendapp/list 3.0.0-beta.0 → 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.js CHANGED
@@ -34,31 +34,65 @@ var View = React3.forwardRef(function View2(props, ref) {
34
34
  });
35
35
  var Text = View;
36
36
 
37
+ // src/state/getContentInsetEnd.ts
38
+ function getContentInsetEnd(state) {
39
+ var _a3;
40
+ const { props } = state;
41
+ const horizontal = props.horizontal;
42
+ let contentInset = props.contentInset;
43
+ if (!contentInset) {
44
+ const animatedInset = (_a3 = props.animatedProps) == null ? void 0 : _a3.contentInset;
45
+ if (animatedInset) {
46
+ if ("get" in animatedInset) {
47
+ contentInset = animatedInset.get();
48
+ } else {
49
+ contentInset = animatedInset;
50
+ }
51
+ }
52
+ }
53
+ return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
54
+ }
55
+
56
+ // src/state/getContentSize.ts
57
+ function getContentSize(ctx) {
58
+ var _a3;
59
+ const { values, state } = ctx;
60
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
61
+ const stylePaddingBottom = state.props.stylePaddingBottom || 0;
62
+ const headerSize = values.get("headerSize") || 0;
63
+ const footerSize = values.get("footerSize") || 0;
64
+ const contentInsetBottom = getContentInsetEnd(state);
65
+ const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
66
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
67
+ }
68
+
37
69
  // src/platform/Animated.tsx
38
70
  var createAnimatedValue = (value) => value;
39
71
 
40
72
  // src/state/state.tsx
41
73
  var ContextState = React3__namespace.createContext(null);
74
+ var contextNum = 0;
42
75
  function StateProvider({ children }) {
43
76
  const [value] = React3__namespace.useState(() => ({
44
77
  animatedScrollY: createAnimatedValue(0),
45
78
  columnWrapperStyle: void 0,
46
- internalState: void 0,
79
+ contextNum: contextNum++,
47
80
  listeners: /* @__PURE__ */ new Map(),
48
81
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
49
82
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
50
83
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
51
84
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
52
85
  mapViewabilityValues: /* @__PURE__ */ new Map(),
86
+ positionListeners: /* @__PURE__ */ new Map(),
87
+ state: void 0,
53
88
  values: /* @__PURE__ */ new Map([
54
89
  ["alignItemsPaddingTop", 0],
55
90
  ["stylePaddingTop", 0],
56
91
  ["headerSize", 0],
57
92
  ["numContainers", 0],
58
- ["activeStickyIndex", void 0],
93
+ ["activeStickyIndex", -1],
59
94
  ["totalSize", 0],
60
- ["scrollAdjustPending", 0],
61
- ["scrollingTo", void 0]
95
+ ["scrollAdjustPending", 0]
62
96
  ]),
63
97
  viewRefs: /* @__PURE__ */ new Map()
64
98
  }));
@@ -126,14 +160,24 @@ function set$(ctx, signalName, value) {
126
160
  }
127
161
  }
128
162
  }
129
- function getContentSize(ctx) {
130
- var _a3, _b;
131
- const { values } = ctx;
132
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
133
- const headerSize = values.get("headerSize") || 0;
134
- const footerSize = values.get("footerSize") || 0;
135
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
136
- return headerSize + footerSize + totalSize + stylePaddingTop;
163
+ function listenPosition$(ctx, key, cb) {
164
+ const { positionListeners } = ctx;
165
+ let setListeners = positionListeners.get(key);
166
+ if (!setListeners) {
167
+ setListeners = /* @__PURE__ */ new Set();
168
+ positionListeners.set(key, setListeners);
169
+ }
170
+ setListeners.add(cb);
171
+ return () => setListeners.delete(cb);
172
+ }
173
+ function notifyPosition$(ctx, key, value) {
174
+ const { positionListeners } = ctx;
175
+ const setListeners = positionListeners.get(key);
176
+ if (setListeners) {
177
+ for (const listener of setListeners) {
178
+ listener(value);
179
+ }
180
+ }
137
181
  }
138
182
  function useArr$(signalNames) {
139
183
  const ctx = React3__namespace.useContext(ContextState);
@@ -255,12 +299,12 @@ function findContainerId(ctx, key) {
255
299
  }
256
300
 
257
301
  // src/components/PositionView.tsx
258
- var PositionViewState = typedMemo(function PositionView({
302
+ var PositionViewState = typedMemo(function PositionViewState2({
259
303
  id,
260
304
  horizontal,
261
305
  style,
262
306
  refView,
263
- ...rest
307
+ ...props
264
308
  }) {
265
309
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
266
310
  const base = {
@@ -268,7 +312,8 @@ var PositionViewState = typedMemo(function PositionView({
268
312
  };
269
313
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
270
314
  const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
271
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: combinedStyle, ...rest });
315
+ const { animatedScrollY, stickyOffset, onLayout, ...webProps } = props;
316
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, ...webProps, style: combinedStyle });
272
317
  });
273
318
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
274
319
  id,
@@ -313,7 +358,7 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
313
358
  }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
314
359
  return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
315
360
  });
316
- var PositionView2 = PositionViewState;
361
+ var PositionView = PositionViewState;
317
362
 
318
363
  // src/constants-platform.ts
319
364
  var IsNewArchitecture = true;
@@ -368,10 +413,9 @@ function createResizeObserver(element, callback) {
368
413
  }
369
414
  callbacks.add(callback);
370
415
  return () => {
371
- const callbacks2 = callbackMap.get(element);
372
- if (callbacks2) {
373
- callbacks2.delete(callback);
374
- if (callbacks2.size === 0) {
416
+ if (callbacks) {
417
+ callbacks.delete(callback);
418
+ if (callbacks.size === 0) {
375
419
  callbackMap.delete(element);
376
420
  observer.unobserve(element);
377
421
  }
@@ -406,10 +450,10 @@ function useOnLayoutSync({
406
450
  return createResizeObserver(element, (entry) => {
407
451
  var _a4;
408
452
  const target = entry.target instanceof HTMLElement ? entry.target : void 0;
409
- const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
410
- if (rect2.width !== prevRect.width || rect2.height !== prevRect.height) {
411
- prevRect = rect2;
412
- emit(toLayout(rect2), false);
453
+ const rectObserved = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
454
+ if (rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height) {
455
+ prevRect = rectObserved;
456
+ emit(toLayout(rectObserved), false);
413
457
  }
414
458
  });
415
459
  }, deps || []);
@@ -537,7 +581,7 @@ var Container = typedMemo(function Container2({
537
581
  },
538
582
  [itemKey, layoutRenderCount]
539
583
  );
540
- const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
584
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
541
585
  return /* @__PURE__ */ React3__namespace.createElement(
542
586
  PositionComponent,
543
587
  {
@@ -730,7 +774,8 @@ var Containers = typedMemo(function Containers2({
730
774
  return /* @__PURE__ */ React3__namespace.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
731
775
  });
732
776
  function DevNumbers() {
733
- return IS_DEV && React3__namespace.memo(function DevNumbers2() {
777
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
778
+ React3__namespace.memo(function DevNumbers2() {
734
779
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3__namespace.createElement(
735
780
  "div",
736
781
  {
@@ -778,7 +823,6 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
778
823
  }, ref) {
779
824
  const scrollRef = React3.useRef(null);
780
825
  const contentRef = React3.useRef(null);
781
- const momentumTimeout = React3.useRef(null);
782
826
  React3.useImperativeHandle(ref, () => {
783
827
  const api = {
784
828
  getBoundingClientRect: () => {
@@ -844,16 +888,6 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
844
888
  }
845
889
  };
846
890
  onScroll2(scrollEvent);
847
- if (onMomentumScrollEnd) {
848
- if (momentumTimeout.current != null) clearTimeout(momentumTimeout.current);
849
- momentumTimeout.current = setTimeout(() => {
850
- onMomentumScrollEnd({
851
- nativeEvent: {
852
- contentOffset: scrollEvent.nativeEvent.contentOffset
853
- }
854
- });
855
- }, 100);
856
- }
857
891
  },
858
892
  [onScroll2, onMomentumScrollEnd]
859
893
  );
@@ -915,7 +949,8 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
915
949
  minWidth: horizontal ? "100%" : void 0,
916
950
  ...StyleSheet.flatten(contentContainerStyle)
917
951
  };
918
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3__namespace.createElement("div", { ref: contentRef, style: contentStyle }, children));
952
+ const { contentInset, scrollEventThrottle, ScrollComponent, ...webProps } = props;
953
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3__namespace.createElement("div", { ref: contentRef, style: contentStyle }, children));
919
954
  });
920
955
  function Padding() {
921
956
  const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
@@ -956,7 +991,7 @@ function ScrollAdjust() {
956
991
  const scrollAdjust = peek$(ctx, "scrollAdjust");
957
992
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
958
993
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
959
- const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
994
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
960
995
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
961
996
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
962
997
  if (scrollDelta !== 0) {
@@ -964,16 +999,16 @@ function ScrollAdjust() {
964
999
  const prevScroll = el.scrollTop;
965
1000
  const nextScroll = prevScroll + scrollDelta;
966
1001
  const totalSize = el.scrollHeight;
967
- if (scrollDelta > 0 && !ctx.internalState.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1002
+ if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
968
1003
  const child = el.firstElementChild;
969
1004
  const prevPaddingBottom = child.style.paddingBottom;
970
1005
  const pad = (nextScroll + el.clientHeight - totalSize) * 2;
971
1006
  child.style.paddingBottom = `${pad}px`;
972
1007
  void el.offsetHeight;
973
1008
  scrollView.scrollBy(0, scrollDelta);
974
- setTimeout(() => {
1009
+ requestAnimationFrame(() => {
975
1010
  child.style.paddingBottom = prevPaddingBottom;
976
- }, 100);
1011
+ });
977
1012
  } else {
978
1013
  scrollView.scrollBy(0, scrollDelta);
979
1014
  }
@@ -983,7 +1018,7 @@ function ScrollAdjust() {
983
1018
  }
984
1019
  lastScrollOffsetRef.current = scrollOffset;
985
1020
  }
986
- }, []);
1021
+ }, [ctx]);
987
1022
  useValueListener$("scrollAdjust", callback);
988
1023
  useValueListener$("scrollAdjustUserOffset", callback);
989
1024
  return null;
@@ -1041,13 +1076,6 @@ var ListComponent = typedMemo(function ListComponent2({
1041
1076
  () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1042
1077
  [renderScrollComponent]
1043
1078
  ) : ListComponentScrollView;
1044
- React3__namespace.useEffect(() => {
1045
- if (canRender) {
1046
- setTimeout(() => {
1047
- scrollAdjustHandler.setMounted();
1048
- }, 0);
1049
- }
1050
- }, [canRender]);
1051
1079
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1052
1080
  return /* @__PURE__ */ React3__namespace.createElement(
1053
1081
  SnapOrScroll,
@@ -1111,10 +1139,11 @@ function getId(state, index) {
1111
1139
  }
1112
1140
 
1113
1141
  // src/core/calculateOffsetForIndex.ts
1114
- function calculateOffsetForIndex(ctx, state, index) {
1142
+ function calculateOffsetForIndex(ctx, index) {
1143
+ const state = ctx.state;
1115
1144
  let position = 0;
1116
1145
  if (index !== void 0) {
1117
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
1146
+ position = state.positions.get(getId(state, index)) || 0;
1118
1147
  const paddingTop = peek$(ctx, "stylePaddingTop");
1119
1148
  if (paddingTop) {
1120
1149
  position += paddingTop;
@@ -1128,7 +1157,8 @@ function calculateOffsetForIndex(ctx, state, index) {
1128
1157
  }
1129
1158
 
1130
1159
  // src/utils/setPaddingTop.ts
1131
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1160
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1161
+ const state = ctx.state;
1132
1162
  if (stylePaddingTop !== void 0) {
1133
1163
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1134
1164
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -1147,7 +1177,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1147
1177
  }
1148
1178
 
1149
1179
  // src/utils/updateAlignItemsPaddingTop.ts
1150
- function updateAlignItemsPaddingTop(ctx, state) {
1180
+ function updateAlignItemsPaddingTop(ctx) {
1181
+ const state = ctx.state;
1151
1182
  const {
1152
1183
  scrollLength,
1153
1184
  props: { alignItemsAtEnd, data }
@@ -1158,12 +1189,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
1158
1189
  const contentSize = getContentSize(ctx);
1159
1190
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1160
1191
  }
1161
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1192
+ setPaddingTop(ctx, { alignItemsPaddingTop });
1162
1193
  }
1163
1194
  }
1164
1195
 
1165
1196
  // src/core/addTotalSize.ts
1166
- function addTotalSize(ctx, state, key, add) {
1197
+ function addTotalSize(ctx, key, add) {
1198
+ const state = ctx.state;
1167
1199
  const { alignItemsAtEnd } = state.props;
1168
1200
  const prevTotalSize = state.totalSize;
1169
1201
  let totalSize = state.totalSize;
@@ -1182,31 +1214,34 @@ function addTotalSize(ctx, state, key, add) {
1182
1214
  state.totalSize = totalSize;
1183
1215
  set$(ctx, "totalSize", totalSize);
1184
1216
  if (alignItemsAtEnd) {
1185
- updateAlignItemsPaddingTop(ctx, state);
1217
+ updateAlignItemsPaddingTop(ctx);
1186
1218
  }
1187
1219
  }
1188
1220
  }
1189
1221
  }
1190
1222
 
1191
1223
  // src/core/setSize.ts
1192
- function setSize(ctx, state, itemKey, size) {
1224
+ function setSize(ctx, itemKey, size) {
1225
+ const state = ctx.state;
1193
1226
  const { sizes } = state;
1194
1227
  const previousSize = sizes.get(itemKey);
1195
1228
  const diff = previousSize !== void 0 ? size - previousSize : size;
1196
1229
  if (diff !== 0) {
1197
- addTotalSize(ctx, state, itemKey, diff);
1230
+ addTotalSize(ctx, itemKey, diff);
1198
1231
  }
1199
1232
  sizes.set(itemKey, size);
1200
1233
  }
1201
1234
 
1202
1235
  // src/utils/getItemSize.ts
1203
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1236
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1204
1237
  var _a3, _b;
1238
+ const state = ctx.state;
1205
1239
  const {
1206
1240
  sizesKnown,
1207
1241
  sizes,
1208
1242
  averageSizes,
1209
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1243
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1244
+ scrollingTo
1210
1245
  } = state;
1211
1246
  const sizeKnown = sizesKnown.get(key);
1212
1247
  if (sizeKnown !== void 0) {
@@ -1214,7 +1249,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1214
1249
  }
1215
1250
  let size;
1216
1251
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1217
- const scrollingTo = peek$(ctx, "scrollingTo");
1218
1252
  if (preferCachedSize) {
1219
1253
  const cachedSize = sizes.get(key);
1220
1254
  if (cachedSize !== void 0) {
@@ -1242,81 +1276,169 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1242
1276
  if (size === void 0) {
1243
1277
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1244
1278
  }
1245
- setSize(ctx, state, key, size);
1279
+ setSize(ctx, key, size);
1246
1280
  return size;
1247
1281
  }
1248
1282
 
1249
1283
  // src/core/calculateOffsetWithOffsetPosition.ts
1250
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1284
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1285
+ const state = ctx.state;
1251
1286
  const { index, viewOffset, viewPosition } = params;
1252
1287
  let offset = offsetParam;
1253
1288
  if (viewOffset) {
1254
1289
  offset -= viewOffset;
1255
1290
  }
1256
1291
  if (viewPosition !== void 0 && index !== void 0) {
1257
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1292
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1293
+ const trailingInset = getContentInsetEnd(state);
1294
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1258
1295
  }
1259
1296
  return offset;
1260
1297
  }
1261
1298
 
1299
+ // src/core/clampScrollOffset.ts
1300
+ function clampScrollOffset(ctx, offset) {
1301
+ const state = ctx.state;
1302
+ const contentSize = getContentSize(ctx);
1303
+ let clampedOffset = offset;
1304
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1305
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1306
+ clampedOffset = Math.min(offset, maxOffset);
1307
+ }
1308
+ clampedOffset = Math.max(0, clampedOffset);
1309
+ return clampedOffset;
1310
+ }
1311
+
1312
+ // src/utils/setInitialRenderState.ts
1313
+ function setInitialRenderState(ctx, {
1314
+ didLayout,
1315
+ didInitialScroll
1316
+ }) {
1317
+ const { state } = ctx;
1318
+ if (didLayout) {
1319
+ state.didContainersLayout = true;
1320
+ }
1321
+ if (didInitialScroll) {
1322
+ state.didFinishInitialScroll = true;
1323
+ }
1324
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1325
+ set$(ctx, "readyToRender", true);
1326
+ }
1327
+ }
1328
+
1262
1329
  // src/core/finishScrollTo.ts
1263
- function finishScrollTo(ctx, state) {
1330
+ function finishScrollTo(ctx) {
1264
1331
  var _a3, _b;
1265
- if (state) {
1332
+ const state = ctx.state;
1333
+ if (state == null ? void 0 : state.scrollingTo) {
1266
1334
  state.scrollHistory.length = 0;
1267
1335
  state.initialScroll = void 0;
1268
1336
  state.initialAnchor = void 0;
1269
- set$(ctx, "scrollingTo", void 0);
1337
+ state.scrollingTo = void 0;
1270
1338
  if (state.pendingTotalSize !== void 0) {
1271
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1339
+ addTotalSize(ctx, null, state.pendingTotalSize);
1272
1340
  }
1273
1341
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1274
1342
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1275
1343
  }
1344
+ {
1345
+ state.scrollAdjustHandler.commitPendingAdjust();
1346
+ }
1347
+ setInitialRenderState(ctx, { didInitialScroll: true });
1276
1348
  }
1277
1349
  }
1278
1350
 
1351
+ // src/core/doScrollTo.ts
1352
+ var SCROLL_END_IDLE_MS = 80;
1353
+ var SCROLL_END_MAX_MS = 1500;
1354
+ var SMOOTH_SCROLL_DURATION_MS = 320;
1355
+ function doScrollTo(ctx, params) {
1356
+ const state = ctx.state;
1357
+ const { animated, horizontal, offset } = params;
1358
+ const scroller = state.refScroller.current;
1359
+ const node = typeof (scroller == null ? void 0 : scroller.getScrollableNode) === "function" ? scroller.getScrollableNode() : scroller;
1360
+ if (node) {
1361
+ const left = horizontal ? offset : 0;
1362
+ const top = horizontal ? 0 : offset;
1363
+ node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1364
+ if (animated) {
1365
+ listenForScrollEnd(ctx, node);
1366
+ } else {
1367
+ state.scroll = offset;
1368
+ setTimeout(() => {
1369
+ finishScrollTo(ctx);
1370
+ }, 100);
1371
+ }
1372
+ }
1373
+ }
1374
+ function listenForScrollEnd(ctx, node) {
1375
+ const supportsScrollEnd = "onscrollend" in node;
1376
+ let idleTimeout;
1377
+ let maxTimeout;
1378
+ let settled = false;
1379
+ const targetToken = ctx.state.scrollingTo;
1380
+ const finish = () => {
1381
+ if (settled) return;
1382
+ settled = true;
1383
+ cleanup();
1384
+ if (targetToken === ctx.state.scrollingTo) {
1385
+ finishScrollTo(ctx);
1386
+ }
1387
+ };
1388
+ const onScroll2 = () => {
1389
+ if (idleTimeout) {
1390
+ clearTimeout(idleTimeout);
1391
+ }
1392
+ idleTimeout = setTimeout(finish, SCROLL_END_IDLE_MS);
1393
+ };
1394
+ const cleanup = () => {
1395
+ if (supportsScrollEnd) {
1396
+ node.removeEventListener("scrollend", finish);
1397
+ } else {
1398
+ node.removeEventListener("scroll", onScroll2);
1399
+ }
1400
+ if (idleTimeout) {
1401
+ clearTimeout(idleTimeout);
1402
+ }
1403
+ if (maxTimeout) {
1404
+ clearTimeout(maxTimeout);
1405
+ }
1406
+ };
1407
+ if (supportsScrollEnd) {
1408
+ node.addEventListener("scrollend", finish, { once: true });
1409
+ } else {
1410
+ node.addEventListener("scroll", onScroll2);
1411
+ idleTimeout = setTimeout(finish, SMOOTH_SCROLL_DURATION_MS);
1412
+ maxTimeout = setTimeout(finish, SCROLL_END_MAX_MS);
1413
+ }
1414
+ return cleanup;
1415
+ }
1416
+
1279
1417
  // src/core/scrollTo.ts
1280
- function scrollTo(ctx, state, params) {
1281
- var _a3;
1282
- const { noScrollingTo, ...scrollTarget } = params;
1418
+ function scrollTo(ctx, params) {
1419
+ const state = ctx.state;
1420
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1283
1421
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1284
1422
  const {
1285
- refScroller,
1286
1423
  props: { horizontal }
1287
1424
  } = state;
1288
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1289
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1290
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1291
- offset = Math.min(offset, maxOffset);
1425
+ if (state.animFrameCheckFinishedScroll) {
1426
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1427
+ }
1428
+ if (state.timeoutCheckFinishedScrollFallback) {
1429
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1292
1430
  }
1431
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1432
+ offset = clampScrollOffset(ctx, offset);
1293
1433
  state.scrollHistory.length = 0;
1294
1434
  if (!noScrollingTo) {
1295
- set$(ctx, "scrollingTo", scrollTarget);
1435
+ state.scrollingTo = scrollTarget;
1296
1436
  }
1297
1437
  state.scrollPending = offset;
1298
- if (!isInitialScroll || Platform.OS === "android") {
1299
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1300
- animated: !!animated,
1301
- x: horizontal ? offset : 0,
1302
- y: horizontal ? 0 : offset
1303
- });
1304
- }
1305
- if (!animated) {
1438
+ if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1439
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1440
+ } else {
1306
1441
  state.scroll = offset;
1307
- {
1308
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1309
- if (value && peek$(ctx, "scrollingTo")) {
1310
- finishScrollTo(ctx, state);
1311
- unlisten();
1312
- }
1313
- });
1314
- }
1315
- if (isInitialScroll) {
1316
- setTimeout(() => {
1317
- state.initialScroll = void 0;
1318
- }, 500);
1319
- }
1320
1442
  }
1321
1443
  }
1322
1444
 
@@ -1325,6 +1447,12 @@ var HYSTERESIS_MULTIPLIER = 1.3;
1325
1447
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1326
1448
  const absDistance = Math.abs(distance);
1327
1449
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1450
+ if (wasReached === null) {
1451
+ if (!within && distance >= 0) {
1452
+ return false;
1453
+ }
1454
+ return null;
1455
+ }
1328
1456
  const updateSnapshot = () => {
1329
1457
  setSnapshot == null ? void 0 : setSnapshot({
1330
1458
  atThreshold,
@@ -1357,8 +1485,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1357
1485
  };
1358
1486
 
1359
1487
  // src/utils/checkAtBottom.ts
1360
- function checkAtBottom(ctx, state) {
1488
+ function checkAtBottom(ctx) {
1361
1489
  var _a3;
1490
+ const state = ctx.state;
1362
1491
  if (!state) {
1363
1492
  return;
1364
1493
  }
@@ -1431,15 +1560,15 @@ function checkAtTop(state) {
1431
1560
  }
1432
1561
 
1433
1562
  // src/core/updateScroll.ts
1434
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1563
+ function updateScroll(ctx, newScroll, forceUpdate) {
1435
1564
  var _a3;
1436
- const scrollingTo = peek$(ctx, "scrollingTo");
1565
+ const state = ctx.state;
1566
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1437
1567
  state.hasScrolled = true;
1438
1568
  state.lastBatchingAction = Date.now();
1439
1569
  const currentTime = Date.now();
1440
- const adjust = state.scrollAdjustHandler.getAdjust();
1441
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1442
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1570
+ const adjust = scrollAdjustHandler.getAdjust();
1571
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1443
1572
  if (adjustChanged) {
1444
1573
  state.scrollHistory.length = 0;
1445
1574
  }
@@ -1464,17 +1593,21 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1464
1593
  return;
1465
1594
  }
1466
1595
  }
1467
- if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1596
+ const lastCalculated = state.scrollLastCalculate;
1597
+ const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1598
+ if (shouldUpdate) {
1599
+ state.scrollLastCalculate = state.scroll;
1468
1600
  state.ignoreScrollFromMVCPIgnored = false;
1469
1601
  (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1470
- checkAtBottom(ctx, state);
1602
+ checkAtBottom(ctx);
1471
1603
  checkAtTop(state);
1472
1604
  state.dataChangeNeedsScrollUpdate = false;
1473
1605
  }
1474
1606
  }
1475
1607
 
1476
1608
  // src/utils/requestAdjust.ts
1477
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1609
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1610
+ const state = ctx.state;
1478
1611
  if (Math.abs(positionDiff) > 0.1) {
1479
1612
  const doit = () => {
1480
1613
  {
@@ -1486,8 +1619,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1486
1619
  };
1487
1620
  state.scroll += positionDiff;
1488
1621
  state.scrollForNextCalculateItemsInView = void 0;
1489
- const didLayout = peek$(ctx, "containersDidLayout");
1490
- if (didLayout) {
1622
+ const readyToRender = peek$(ctx, "readyToRender");
1623
+ if (readyToRender) {
1491
1624
  doit();
1492
1625
  } else {
1493
1626
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -1496,73 +1629,23 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1496
1629
  }
1497
1630
  }
1498
1631
 
1499
- // src/core/ensureInitialAnchor.ts
1500
- var INITIAL_ANCHOR_TOLERANCE = 0.5;
1501
- var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1502
- var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1503
- function ensureInitialAnchor(ctx, state) {
1504
- var _a3, _b, _c, _d, _e;
1505
- const anchor = state.initialAnchor;
1506
- const item = state.props.data[anchor.index];
1507
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1508
- if (!containersDidLayout) {
1509
- return;
1510
- }
1511
- const id = getId(state, anchor.index);
1512
- if (state.positions.get(id) === void 0) {
1513
- return;
1514
- }
1515
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1516
- if (size === void 0) {
1517
- return;
1518
- }
1519
- const availableSpace = Math.max(0, state.scrollLength - size);
1520
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1521
- const contentSize = getContentSize(ctx);
1522
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1523
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1524
- const delta = clampedDesiredOffset - state.scroll;
1525
- if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1526
- const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1527
- if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1528
- state.initialAnchor = void 0;
1529
- } else {
1530
- anchor.settledTicks = settledTicks;
1531
- }
1532
- return;
1533
- }
1534
- if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1535
- state.initialAnchor = void 0;
1536
- return;
1537
- }
1538
- const lastDelta = anchor.lastDelta;
1539
- if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1540
- state.initialAnchor = void 0;
1541
- return;
1542
- }
1543
- Object.assign(anchor, {
1544
- attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1545
- lastDelta: delta,
1546
- settledTicks: 0
1547
- });
1548
- requestAdjust(ctx, state, delta);
1549
- }
1550
-
1551
1632
  // src/core/mvcp.ts
1552
- function prepareMVCP(ctx, state, dataChanged) {
1633
+ function prepareMVCP(ctx, dataChanged) {
1634
+ const state = ctx.state;
1553
1635
  const { idsInView, positions, props } = state;
1554
1636
  const { maintainVisibleContentPosition } = props;
1555
- const scrollingTo = peek$(ctx, "scrollingTo");
1637
+ const scrollingTo = state.scrollingTo;
1556
1638
  let prevPosition;
1557
1639
  let targetId;
1558
1640
  const idsInViewWithPositions = [];
1559
1641
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1642
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1560
1643
  const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1561
1644
  const indexByKey = state.indexByKey;
1562
1645
  if (shouldMVCP) {
1563
1646
  if (scrollTarget !== void 0) {
1564
1647
  targetId = getId(state, scrollTarget);
1565
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1648
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1566
1649
  if (dataChanged) {
1567
1650
  for (let i = 0; i < idsInView.length; i++) {
1568
1651
  const id = idsInView[i];
@@ -1579,7 +1662,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1579
1662
  prevPosition = positions.get(targetId);
1580
1663
  }
1581
1664
  return () => {
1582
- let positionDiff;
1665
+ let positionDiff = 0;
1583
1666
  if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1584
1667
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1585
1668
  const { id, position } = idsInViewWithPositions[i];
@@ -1605,16 +1688,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1605
1688
  positionDiff = diff;
1606
1689
  }
1607
1690
  }
1608
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1609
- requestAdjust(ctx, state, positionDiff);
1691
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1692
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1693
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1694
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1695
+ const diff = newSize - prevSize;
1696
+ if (diff !== 0) {
1697
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1698
+ scrollingTo.itemSize = newSize;
1699
+ }
1700
+ }
1701
+ }
1702
+ if (Math.abs(positionDiff) > 0.1) {
1703
+ requestAdjust(ctx, positionDiff);
1610
1704
  }
1611
1705
  };
1612
1706
  }
1613
1707
  }
1614
1708
 
1615
1709
  // src/core/prepareColumnStartState.ts
1616
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1710
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1617
1711
  var _a3;
1712
+ const state = ctx.state;
1618
1713
  const numColumns = peek$(ctx, "numColumns");
1619
1714
  let rowStartIndex = startIndex;
1620
1715
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1629,7 +1724,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1629
1724
  const prevId = state.idCache[prevIndex];
1630
1725
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1631
1726
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1632
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1727
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1633
1728
  currentRowTop = prevPosition + prevRowHeight;
1634
1729
  }
1635
1730
  return {
@@ -1652,7 +1747,8 @@ function findRowStartIndex(state, numColumns, index) {
1652
1747
  }
1653
1748
  return rowStart;
1654
1749
  }
1655
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1750
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1751
+ const state = ctx.state;
1656
1752
  if (endIndex < startIndex) {
1657
1753
  return 0;
1658
1754
  }
@@ -1666,7 +1762,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1666
1762
  continue;
1667
1763
  }
1668
1764
  const id = state.idCache[i];
1669
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1765
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1670
1766
  if (size > maxSize) {
1671
1767
  maxSize = size;
1672
1768
  }
@@ -1675,22 +1771,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1675
1771
  }
1676
1772
 
1677
1773
  // src/core/updateTotalSize.ts
1678
- function updateTotalSize(ctx, state) {
1774
+ function updateTotalSize(ctx) {
1775
+ const state = ctx.state;
1679
1776
  const {
1680
1777
  positions,
1681
1778
  props: { data }
1682
1779
  } = state;
1683
1780
  if (data.length === 0) {
1684
- addTotalSize(ctx, state, null, 0);
1781
+ addTotalSize(ctx, null, 0);
1685
1782
  } else {
1686
1783
  const lastId = getId(state, data.length - 1);
1687
1784
  if (lastId !== void 0) {
1688
1785
  const lastPosition = positions.get(lastId);
1689
1786
  if (lastPosition !== void 0) {
1690
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1787
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1691
1788
  if (lastSize !== void 0) {
1692
1789
  const totalSize = lastPosition + lastSize;
1693
- addTotalSize(ctx, state, null, totalSize);
1790
+ addTotalSize(ctx, null, totalSize);
1694
1791
  }
1695
1792
  }
1696
1793
  }
@@ -1736,7 +1833,8 @@ var getScrollVelocity = (state) => {
1736
1833
  };
1737
1834
 
1738
1835
  // src/utils/updateSnapToOffsets.ts
1739
- function updateSnapToOffsets(ctx, state) {
1836
+ function updateSnapToOffsets(ctx) {
1837
+ const state = ctx.state;
1740
1838
  const {
1741
1839
  positions,
1742
1840
  props: { snapToIndices }
@@ -1751,30 +1849,30 @@ function updateSnapToOffsets(ctx, state) {
1751
1849
  }
1752
1850
 
1753
1851
  // src/core/updateItemPositions.ts
1754
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1852
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1755
1853
  doMVCP: false,
1756
1854
  forceFullUpdate: false,
1757
1855
  scrollBottomBuffered: -1,
1758
1856
  startIndex: 0
1759
1857
  }) {
1760
1858
  var _a3, _b, _c, _d, _e;
1859
+ const state = ctx.state;
1761
1860
  const {
1762
1861
  columns,
1763
1862
  indexByKey,
1764
1863
  positions,
1765
1864
  idCache,
1766
1865
  sizesKnown,
1767
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1866
+ props: { data, getEstimatedItemSize, snapToIndices },
1867
+ scrollingTo
1768
1868
  } = state;
1769
- const data = state.props.data;
1770
1869
  const dataLength = data.length;
1771
1870
  const numColumns = peek$(ctx, "numColumns");
1772
- const scrollingTo = peek$(ctx, "scrollingTo");
1773
1871
  const hasColumns = numColumns > 1;
1774
1872
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1775
1873
  const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1776
1874
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1777
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1875
+ const useAverageSize = !getEstimatedItemSize;
1778
1876
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1779
1877
  let currentRowTop = 0;
1780
1878
  let column = 1;
@@ -1783,7 +1881,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1783
1881
  if (hasColumns) {
1784
1882
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1785
1883
  ctx,
1786
- state,
1787
1884
  startIndex,
1788
1885
  useAverageSize
1789
1886
  );
@@ -1793,7 +1890,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1793
1890
  const prevIndex = startIndex - 1;
1794
1891
  const prevId = getId(state, prevIndex);
1795
1892
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1796
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1893
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1797
1894
  currentRowTop = prevPosition + prevSize;
1798
1895
  }
1799
1896
  }
@@ -1810,7 +1907,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1810
1907
  breakAt = i + itemsPerRow + 10;
1811
1908
  }
1812
1909
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1813
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1910
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1814
1911
  if (IS_DEV && needsIndexByKey) {
1815
1912
  if (indexByKeyForChecking.has(id)) {
1816
1913
  console.error(
@@ -1819,7 +1916,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1819
1916
  }
1820
1917
  indexByKeyForChecking.set(id, i);
1821
1918
  }
1822
- positions.set(id, currentRowTop);
1919
+ if (currentRowTop !== positions.get(id)) {
1920
+ positions.set(id, currentRowTop);
1921
+ notifyPosition$(ctx, id, currentRowTop);
1922
+ }
1823
1923
  if (needsIndexByKey) {
1824
1924
  indexByKey.set(id, i);
1825
1925
  }
@@ -1839,10 +1939,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1839
1939
  }
1840
1940
  }
1841
1941
  if (!didBreakEarly) {
1842
- updateTotalSize(ctx, state);
1942
+ updateTotalSize(ctx);
1843
1943
  }
1844
1944
  if (snapToIndices) {
1845
- updateSnapToOffsets(ctx, state);
1945
+ updateSnapToOffsets(ctx);
1846
1946
  }
1847
1947
  }
1848
1948
 
@@ -1920,7 +2020,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1920
2020
  if (previousViewableItems) {
1921
2021
  for (const viewToken of previousViewableItems) {
1922
2022
  const containerId = findContainerId(ctx, viewToken.key);
1923
- if (!isViewable(
2023
+ if (!checkIsViewable(
1924
2024
  state,
1925
2025
  ctx,
1926
2026
  viewabilityConfig,
@@ -1941,7 +2041,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1941
2041
  if (item) {
1942
2042
  const key = getId(state, i);
1943
2043
  const containerId = findContainerId(ctx, key);
1944
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2044
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1945
2045
  const viewToken = {
1946
2046
  containerId,
1947
2047
  index: i,
@@ -2001,11 +2101,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2001
2101
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
2002
2102
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
2003
2103
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
2004
- const isViewable2 = percent >= viewablePercentThreshold;
2104
+ const isViewable = percent >= viewablePercentThreshold;
2005
2105
  const value = {
2006
2106
  containerId,
2007
2107
  index,
2008
- isViewable: isViewable2,
2108
+ isViewable,
2009
2109
  item,
2010
2110
  key,
2011
2111
  percentOfScroller,
@@ -2024,8 +2124,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2024
2124
  }
2025
2125
  return value;
2026
2126
  }
2027
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2028
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2127
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2128
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2129
+ if (!value || value.key !== key) {
2130
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2131
+ }
2029
2132
  return value.isViewable;
2030
2133
  }
2031
2134
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -2053,8 +2156,9 @@ function checkAllSizesKnown(state) {
2053
2156
  }
2054
2157
 
2055
2158
  // src/utils/findAvailableContainers.ts
2056
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2159
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2057
2160
  const numContainers = peek$(ctx, "numContainers");
2161
+ const state = ctx.state;
2058
2162
  const { stickyContainerPool, containerItemTypes } = state;
2059
2163
  const result = [];
2060
2164
  const availableContainers = [];
@@ -2098,14 +2202,14 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
2098
2202
  continue;
2099
2203
  }
2100
2204
  const key = peek$(ctx, `containerItemKey${u}`);
2101
- let isOk = key === void 0;
2102
- if (!isOk && pendingRemovalSet.has(u)) {
2103
- pendingRemovalSet.delete(u);
2104
- pendingRemovalChanged = true;
2105
- const requiredType = neededTypes[typeIndex];
2106
- isOk = canReuseContainer(u, requiredType);
2107
- }
2108
- if (isOk) {
2205
+ const requiredType = neededTypes[typeIndex];
2206
+ const isPending = key !== void 0 && pendingRemovalSet.has(u);
2207
+ const canUse = key === void 0 || isPending && canReuseContainer(u, requiredType);
2208
+ if (canUse) {
2209
+ if (isPending) {
2210
+ pendingRemovalSet.delete(u);
2211
+ pendingRemovalChanged = true;
2212
+ }
2109
2213
  result.push(u);
2110
2214
  if (requiredItemTypes) {
2111
2215
  typeIndex++;
@@ -2174,21 +2278,26 @@ function comparatorByDistance(a, b) {
2174
2278
  }
2175
2279
 
2176
2280
  // src/core/scrollToIndex.ts
2177
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2178
- if (index >= state.props.data.length) {
2179
- index = state.props.data.length - 1;
2281
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2282
+ const state = ctx.state;
2283
+ const { data } = state.props;
2284
+ if (index >= data.length) {
2285
+ index = data.length - 1;
2180
2286
  } else if (index < 0) {
2181
2287
  index = 0;
2182
2288
  }
2183
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2184
- const isLast = index === state.props.data.length - 1;
2289
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2290
+ const isLast = index === data.length - 1;
2185
2291
  if (isLast && viewPosition === void 0) {
2186
2292
  viewPosition = 1;
2187
2293
  }
2188
2294
  state.scrollForNextCalculateItemsInView = void 0;
2189
- scrollTo(ctx, state, {
2295
+ const targetId = getId(state, index);
2296
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2297
+ scrollTo(ctx, {
2190
2298
  animated,
2191
2299
  index,
2300
+ itemSize,
2192
2301
  offset: firstIndexOffset,
2193
2302
  viewOffset,
2194
2303
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2196,16 +2305,17 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2196
2305
  }
2197
2306
 
2198
2307
  // src/utils/setDidLayout.ts
2199
- function setDidLayout(ctx, state) {
2308
+ function setDidLayout(ctx) {
2309
+ const state = ctx.state;
2200
2310
  const {
2201
2311
  loadStartTime,
2202
2312
  initialScroll,
2203
2313
  props: { onLoad }
2204
2314
  } = state;
2205
2315
  state.queuedInitialLayout = true;
2206
- checkAtBottom(ctx, state);
2316
+ checkAtBottom(ctx);
2207
2317
  const setIt = () => {
2208
- set$(ctx, "containersDidLayout", true);
2318
+ setInitialRenderState(ctx, { didLayout: true });
2209
2319
  if (onLoad) {
2210
2320
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2211
2321
  }
@@ -2230,15 +2340,17 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2230
2340
  }
2231
2341
  return -1;
2232
2342
  }
2233
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2343
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2344
+ const state = ctx.state;
2234
2345
  return new Set(
2235
2346
  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))
2236
2347
  );
2237
2348
  }
2238
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2349
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2239
2350
  var _a3;
2240
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2241
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2351
+ const state = ctx.state;
2352
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2353
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2242
2354
  for (let offset = 0; offset <= 1; offset++) {
2243
2355
  const idx = currentStickyIdx - offset;
2244
2356
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -2249,8 +2361,9 @@ function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, cu
2249
2361
  }
2250
2362
  }
2251
2363
  }
2252
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2364
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2253
2365
  var _a3, _b, _c;
2366
+ const state = ctx.state;
2254
2367
  for (const containerIndex of state.stickyContainerPool) {
2255
2368
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2256
2369
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
@@ -2274,7 +2387,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2274
2387
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2275
2388
  if (currentId) {
2276
2389
  const currentPos = state.positions.get(currentId);
2277
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2390
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2278
2391
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2279
2392
  }
2280
2393
  }
@@ -2283,7 +2396,8 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2283
2396
  }
2284
2397
  }
2285
2398
  }
2286
- function calculateItemsInView(ctx, state, params = {}) {
2399
+ function calculateItemsInView(ctx, params = {}) {
2400
+ const state = ctx.state;
2287
2401
  reactDom.unstable_batchedUpdates(() => {
2288
2402
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2289
2403
  const {
@@ -2307,9 +2421,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2307
2421
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2308
2422
  const prevNumContainers = peek$(ctx, "numContainers");
2309
2423
  if (!data || scrollLength === 0 || !prevNumContainers) {
2310
- if (state.initialAnchor) {
2311
- ensureInitialAnchor(ctx, state);
2312
- }
2313
2424
  return;
2314
2425
  }
2315
2426
  const totalSize = getContentSize(ctx);
@@ -2323,15 +2434,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2323
2434
  if (!queuedInitialLayout && initialScroll) {
2324
2435
  const updatedOffset = calculateOffsetWithOffsetPosition(
2325
2436
  ctx,
2326
- state,
2327
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2437
+ calculateOffsetForIndex(ctx, initialScroll.index),
2328
2438
  initialScroll
2329
2439
  );
2330
2440
  scrollState = updatedOffset;
2331
2441
  }
2332
2442
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2333
2443
  const scrollAdjustPad = scrollAdjustPending - topPad;
2334
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2444
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2335
2445
  if (scroll + scrollLength > totalSize) {
2336
2446
  scroll = Math.max(0, totalSize - scrollLength);
2337
2447
  }
@@ -2339,11 +2449,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2339
2449
  set$(ctx, "debugRawScroll", scrollState);
2340
2450
  set$(ctx, "debugComputedScroll", scroll);
2341
2451
  }
2342
- const previousStickyIndex = state.activeStickyIndex;
2452
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2343
2453
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2344
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2345
- state.activeStickyIndex = nextActiveStickyIndex;
2346
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2454
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2455
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2456
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2457
+ }
2347
2458
  let scrollBufferTop = scrollBuffer;
2348
2459
  let scrollBufferBottom = scrollBuffer;
2349
2460
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2356,23 +2467,20 @@ function calculateItemsInView(ctx, state, params = {}) {
2356
2467
  const scrollTopBuffered = scroll - scrollBufferTop;
2357
2468
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2358
2469
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2359
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2470
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2360
2471
  const { top, bottom } = scrollForNextCalculateItemsInView;
2361
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2362
- if (state.initialAnchor) {
2363
- ensureInitialAnchor(ctx, state);
2364
- }
2472
+ if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2365
2473
  return;
2366
2474
  }
2367
2475
  }
2368
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2476
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2369
2477
  if (dataChanged) {
2370
2478
  indexByKey.clear();
2371
2479
  idCache.length = 0;
2372
2480
  positions.clear();
2373
2481
  }
2374
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2375
- updateItemPositions(ctx, state, dataChanged, {
2482
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2483
+ updateItemPositions(ctx, dataChanged, {
2376
2484
  doMVCP,
2377
2485
  forceFullUpdate: !!forceFullItemPositions,
2378
2486
  scrollBottomBuffered,
@@ -2391,9 +2499,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2391
2499
  for (let i = loopStart; i >= 0; i--) {
2392
2500
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2393
2501
  const top = positions.get(id);
2394
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2502
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2395
2503
  const bottom = top + size;
2396
- if (bottom > scroll - scrollBuffer) {
2504
+ if (bottom > scroll - scrollBufferTop) {
2397
2505
  loopStart = i;
2398
2506
  } else {
2399
2507
  break;
@@ -2418,7 +2526,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2418
2526
  const dataLength = data.length;
2419
2527
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2420
2528
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2421
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2529
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2422
2530
  const top = positions.get(id);
2423
2531
  if (!foundEnd) {
2424
2532
  if (startNoBuffer === null && top + size > scroll) {
@@ -2430,7 +2538,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2430
2538
  if (startBuffered === null && top + size > scrollTopBuffered) {
2431
2539
  startBuffered = i;
2432
2540
  startBufferedId = id;
2433
- nextTop = top;
2541
+ if (scrollTopBuffered < 0) {
2542
+ nextTop = null;
2543
+ } else {
2544
+ nextTop = top;
2545
+ }
2434
2546
  }
2435
2547
  if (startNoBuffer !== null) {
2436
2548
  if (top <= scrollBottom) {
@@ -2438,7 +2550,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2438
2550
  }
2439
2551
  if (top <= scrollBottomBuffered) {
2440
2552
  endBuffered = i;
2441
- nextBottom = top + size;
2553
+ if (scrollBottomBuffered > totalSize) {
2554
+ nextBottom = null;
2555
+ } else {
2556
+ nextBottom = top + size;
2557
+ }
2442
2558
  } else {
2443
2559
  foundEnd = true;
2444
2560
  }
@@ -2465,7 +2581,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2465
2581
  top: nextTop
2466
2582
  } : void 0;
2467
2583
  }
2468
- const numContainers = peek$(ctx, "numContainers");
2584
+ let numContainers = prevNumContainers;
2469
2585
  const pendingRemoval = [];
2470
2586
  if (dataChanged) {
2471
2587
  for (let i = 0; i < numContainers; i++) {
@@ -2476,7 +2592,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2476
2592
  }
2477
2593
  }
2478
2594
  if (startBuffered !== null && endBuffered !== null) {
2479
- let numContainers2 = prevNumContainers;
2480
2595
  const needNewContainers = [];
2481
2596
  for (let i = startBuffered; i <= endBuffered; i++) {
2482
2597
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
@@ -2487,7 +2602,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2487
2602
  if (stickyIndicesArr.length > 0) {
2488
2603
  handleStickyActivation(
2489
2604
  ctx,
2490
- state,
2491
2605
  stickyIndicesSet,
2492
2606
  stickyIndicesArr,
2493
2607
  currentStickyIdx,
@@ -2495,9 +2609,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2495
2609
  startBuffered,
2496
2610
  endBuffered
2497
2611
  );
2498
- } else {
2499
- state.activeStickyIndex = void 0;
2500
- set$(ctx, "activeStickyIndex", void 0);
2612
+ } else if (previousStickyIndex !== -1) {
2613
+ set$(ctx, "activeStickyIndex", -1);
2501
2614
  }
2502
2615
  if (needNewContainers.length > 0) {
2503
2616
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2506,7 +2619,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2506
2619
  }) : void 0;
2507
2620
  const availableContainers = findAvailableContainers(
2508
2621
  ctx,
2509
- state,
2510
2622
  needNewContainers.length,
2511
2623
  startBuffered,
2512
2624
  endBuffered,
@@ -2528,29 +2640,30 @@ function calculateItemsInView(ctx, state, params = {}) {
2528
2640
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2529
2641
  }
2530
2642
  containerItemKeys.add(id);
2643
+ const containerSticky = `containerSticky${containerIndex}`;
2531
2644
  if (stickyIndicesSet.has(i)) {
2532
- set$(ctx, `containerSticky${containerIndex}`, true);
2645
+ set$(ctx, containerSticky, true);
2533
2646
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2534
2647
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2535
2648
  state.stickyContainerPool.add(containerIndex);
2536
- } else {
2537
- set$(ctx, `containerSticky${containerIndex}`, false);
2649
+ } else if (peek$(ctx, containerSticky)) {
2650
+ set$(ctx, containerSticky, false);
2538
2651
  state.stickyContainerPool.delete(containerIndex);
2539
2652
  }
2540
- if (containerIndex >= numContainers2) {
2541
- numContainers2 = containerIndex + 1;
2653
+ if (containerIndex >= numContainers) {
2654
+ numContainers = containerIndex + 1;
2542
2655
  }
2543
2656
  }
2544
- if (numContainers2 !== prevNumContainers) {
2545
- set$(ctx, "numContainers", numContainers2);
2546
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2547
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2657
+ if (numContainers !== prevNumContainers) {
2658
+ set$(ctx, "numContainers", numContainers);
2659
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2660
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2548
2661
  }
2549
2662
  }
2550
2663
  }
2551
2664
  }
2552
2665
  if (stickyIndicesArr.length > 0) {
2553
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2666
+ handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2554
2667
  }
2555
2668
  let didChangePositions = false;
2556
2669
  for (let i = 0; i < numContainers; i++) {
@@ -2602,7 +2715,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2602
2715
  }
2603
2716
  if (!queuedInitialLayout && endBuffered !== null) {
2604
2717
  if (checkAllSizesKnown(state)) {
2605
- setDidLayout(ctx, state);
2718
+ setDidLayout(ctx);
2606
2719
  }
2607
2720
  }
2608
2721
  if (viewabilityConfigCallbackPairs) {
@@ -2615,9 +2728,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2615
2728
  }
2616
2729
  }
2617
2730
  });
2618
- if (state.initialAnchor) {
2619
- ensureInitialAnchor(ctx, state);
2620
- }
2621
2731
  }
2622
2732
 
2623
2733
  // src/core/checkActualChange.ts
@@ -2640,20 +2750,69 @@ function checkActualChange(state, dataProp, previousData) {
2640
2750
  return false;
2641
2751
  }
2642
2752
 
2753
+ // src/core/checkFinishedScroll.ts
2754
+ function checkFinishedScroll(ctx) {
2755
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2756
+ }
2757
+ function checkFinishedScrollFrame(ctx) {
2758
+ const scrollingTo = ctx.state.scrollingTo;
2759
+ if (scrollingTo) {
2760
+ const { state } = ctx;
2761
+ state.animFrameCheckFinishedScroll = void 0;
2762
+ const scroll = state.scroll;
2763
+ const adjust = state.scrollAdjustHandler.getAdjust();
2764
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
2765
+ const maxOffset = clampScrollOffset(ctx, scroll);
2766
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
2767
+ const diff2 = Math.abs(diff1 - adjust);
2768
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
2769
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
2770
+ finishScrollTo(ctx);
2771
+ }
2772
+ }
2773
+ }
2774
+ function checkFinishedScrollFallback(ctx) {
2775
+ const state = ctx.state;
2776
+ const scrollingTo = state.scrollingTo;
2777
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
2778
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
2779
+ () => {
2780
+ let numChecks = 0;
2781
+ const checkHasScrolled = () => {
2782
+ state.timeoutCheckFinishedScrollFallback = void 0;
2783
+ const isStillScrollingTo = state.scrollingTo;
2784
+ if (isStillScrollingTo) {
2785
+ numChecks++;
2786
+ if (state.hasScrolled || numChecks > 5) {
2787
+ finishScrollTo(ctx);
2788
+ } else {
2789
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
2790
+ }
2791
+ }
2792
+ };
2793
+ checkHasScrolled();
2794
+ },
2795
+ slowTimeout ? 500 : 100
2796
+ );
2797
+ }
2798
+
2643
2799
  // src/core/doMaintainScrollAtEnd.ts
2644
- function doMaintainScrollAtEnd(ctx, state, animated) {
2800
+ function doMaintainScrollAtEnd(ctx, animated) {
2801
+ const state = ctx.state;
2645
2802
  const {
2803
+ didContainersLayout,
2804
+ isAtEnd,
2646
2805
  refScroller,
2647
2806
  props: { maintainScrollAtEnd }
2648
2807
  } = state;
2649
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2808
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2650
2809
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2651
2810
  if (paddingTop > 0) {
2652
2811
  state.scroll = 0;
2653
2812
  }
2654
2813
  requestAnimationFrame(() => {
2655
2814
  var _a3;
2656
- if (state == null ? void 0 : state.isAtEnd) {
2815
+ if (state.isAtEnd) {
2657
2816
  state.maintainingScrollAtEnd = true;
2658
2817
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2659
2818
  animated
@@ -2724,28 +2883,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2724
2883
  }
2725
2884
 
2726
2885
  // src/core/checkResetContainers.ts
2727
- function checkResetContainers(ctx, state, dataProp) {
2886
+ function checkResetContainers(ctx, dataProp) {
2887
+ const state = ctx.state;
2728
2888
  const { previousData } = state;
2729
2889
  if (previousData) {
2730
2890
  updateAveragesOnDataChange(state, previousData, dataProp);
2731
2891
  }
2732
2892
  const { maintainScrollAtEnd } = state.props;
2733
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2893
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2734
2894
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2735
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2895
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2736
2896
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2737
2897
  state.isEndReached = false;
2738
2898
  }
2739
2899
  if (!didMaintainScrollAtEnd) {
2740
2900
  checkAtTop(state);
2741
- checkAtBottom(ctx, state);
2901
+ checkAtBottom(ctx);
2742
2902
  }
2743
2903
  delete state.previousData;
2744
2904
  }
2745
2905
 
2746
2906
  // src/core/doInitialAllocateContainers.ts
2747
- function doInitialAllocateContainers(ctx, state) {
2907
+ function doInitialAllocateContainers(ctx) {
2748
2908
  var _a3, _b, _c;
2909
+ const state = ctx.state;
2749
2910
  const {
2750
2911
  scrollLength,
2751
2912
  props: {
@@ -2783,10 +2944,10 @@ function doInitialAllocateContainers(ctx, state) {
2783
2944
  if (state.lastLayout) {
2784
2945
  if (state.initialScroll) {
2785
2946
  requestAnimationFrame(() => {
2786
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2947
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2787
2948
  });
2788
2949
  } else {
2789
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2950
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2790
2951
  }
2791
2952
  }
2792
2953
  return true;
@@ -2794,7 +2955,8 @@ function doInitialAllocateContainers(ctx, state) {
2794
2955
  }
2795
2956
 
2796
2957
  // src/core/handleLayout.ts
2797
- function handleLayout(ctx, state, layout, setCanRender) {
2958
+ function handleLayout(ctx, layout, setCanRender) {
2959
+ const state = ctx.state;
2798
2960
  const { maintainScrollAtEnd } = state.props;
2799
2961
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2800
2962
  const previousLength = state.scrollLength;
@@ -2810,19 +2972,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2810
2972
  state.lastBatchingAction = Date.now();
2811
2973
  state.scrollForNextCalculateItemsInView = void 0;
2812
2974
  if (scrollLength > 0) {
2813
- doInitialAllocateContainers(ctx, state);
2975
+ doInitialAllocateContainers(ctx);
2814
2976
  }
2815
2977
  if (needsCalculate) {
2816
- calculateItemsInView(ctx, state, { doMVCP: true });
2978
+ calculateItemsInView(ctx, { doMVCP: true });
2817
2979
  }
2818
2980
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2819
2981
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2820
2982
  }
2821
2983
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2822
- doMaintainScrollAtEnd(ctx, state, false);
2984
+ doMaintainScrollAtEnd(ctx, false);
2823
2985
  }
2824
- updateAlignItemsPaddingTop(ctx, state);
2825
- checkAtBottom(ctx, state);
2986
+ updateAlignItemsPaddingTop(ctx);
2987
+ checkAtBottom(ctx);
2826
2988
  checkAtTop(state);
2827
2989
  if (state) {
2828
2990
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2838,8 +3000,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2838
3000
  }
2839
3001
 
2840
3002
  // src/core/onScroll.ts
2841
- function onScroll(ctx, state, event) {
3003
+ function onScroll(ctx, event) {
2842
3004
  var _a3, _b, _c;
3005
+ const state = ctx.state;
2843
3006
  const {
2844
3007
  scrollProcessingEnabled,
2845
3008
  props: { onScroll: onScrollProp }
@@ -2850,9 +3013,23 @@ function onScroll(ctx, state, event) {
2850
3013
  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) {
2851
3014
  return;
2852
3015
  }
2853
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3016
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2854
3017
  state.scrollPending = newScroll;
2855
- updateScroll(ctx, state, newScroll);
3018
+ if (state.scrollingTo) {
3019
+ const maxOffset = clampScrollOffset(ctx, newScroll);
3020
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3021
+ newScroll = maxOffset;
3022
+ scrollTo(ctx, {
3023
+ forceScroll: true,
3024
+ isInitialScroll: true,
3025
+ noScrollingTo: true,
3026
+ offset: newScroll
3027
+ });
3028
+ return;
3029
+ }
3030
+ }
3031
+ updateScroll(ctx, newScroll);
3032
+ checkFinishedScroll(ctx);
2856
3033
  onScrollProp == null ? void 0 : onScrollProp(event);
2857
3034
  }
2858
3035
 
@@ -2861,51 +3038,47 @@ var ScrollAdjustHandler = class {
2861
3038
  constructor(ctx) {
2862
3039
  this.appliedAdjust = 0;
2863
3040
  this.pendingAdjust = 0;
2864
- this.mounted = false;
2865
- this.context = ctx;
2866
- {
2867
- const commitPendingAdjust = () => {
2868
- const state = this.context.internalState;
2869
- const pending = this.pendingAdjust;
2870
- if (pending !== 0) {
2871
- this.pendingAdjust = 0;
2872
- this.appliedAdjust += pending;
2873
- state.scroll += pending;
2874
- state.scrollForNextCalculateItemsInView = void 0;
2875
- set$(this.context, "scrollAdjustPending", 0);
2876
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2877
- calculateItemsInView(this.context, this.context.internalState);
2878
- }
2879
- };
2880
- listen$(this.context, "scrollingTo", (value) => {
2881
- if (value === void 0) {
2882
- commitPendingAdjust();
2883
- }
2884
- });
2885
- }
3041
+ this.ctx = ctx;
2886
3042
  }
2887
3043
  requestAdjust(add) {
2888
- const scrollingTo = peek$(this.context, "scrollingTo");
3044
+ const scrollingTo = this.ctx.state.scrollingTo;
2889
3045
  if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2890
3046
  this.pendingAdjust += add;
2891
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
3047
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2892
3048
  } else {
2893
3049
  this.appliedAdjust += add;
2894
- set$(this.context, "scrollAdjust", this.appliedAdjust);
3050
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3051
+ }
3052
+ if (this.ctx.state.scrollingTo) {
3053
+ checkFinishedScroll(this.ctx);
2895
3054
  }
2896
- }
2897
- setMounted() {
2898
- this.mounted = true;
2899
3055
  }
2900
3056
  getAdjust() {
2901
3057
  return this.appliedAdjust;
2902
3058
  }
3059
+ commitPendingAdjust() {
3060
+ {
3061
+ const state = this.ctx.state;
3062
+ const pending = this.pendingAdjust;
3063
+ if (pending !== 0) {
3064
+ this.pendingAdjust = 0;
3065
+ this.appliedAdjust += pending;
3066
+ state.scroll += pending;
3067
+ state.scrollForNextCalculateItemsInView = void 0;
3068
+ set$(this.ctx, "scrollAdjustPending", 0);
3069
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3070
+ calculateItemsInView(this.ctx);
3071
+ }
3072
+ }
3073
+ }
2903
3074
  };
2904
3075
 
2905
3076
  // src/core/updateItemSize.ts
2906
- function updateItemSize(ctx, state, itemKey, sizeObj) {
3077
+ function updateItemSize(ctx, itemKey, sizeObj) {
2907
3078
  var _a3;
3079
+ const state = ctx.state;
2908
3080
  const {
3081
+ didContainersLayout,
2909
3082
  sizesKnown,
2910
3083
  props: {
2911
3084
  getFixedItemSize,
@@ -2933,13 +3106,12 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2933
3106
  return;
2934
3107
  }
2935
3108
  }
2936
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2937
- let needsRecalculate = !containersDidLayout;
3109
+ let needsRecalculate = !didContainersLayout;
2938
3110
  let shouldMaintainScrollAtEnd = false;
2939
3111
  let minIndexSizeChanged;
2940
3112
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2941
3113
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2942
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3114
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
2943
3115
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2944
3116
  if (diff !== 0) {
2945
3117
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
@@ -2988,22 +3160,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2988
3160
  if (!cur || maxOtherAxisSize > cur) {
2989
3161
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
2990
3162
  }
2991
- if (containersDidLayout || checkAllSizesKnown(state)) {
3163
+ if (didContainersLayout || checkAllSizesKnown(state)) {
2992
3164
  if (needsRecalculate) {
2993
3165
  state.scrollForNextCalculateItemsInView = void 0;
2994
- calculateItemsInView(ctx, state, { doMVCP: true });
3166
+ calculateItemsInView(ctx, { doMVCP: true });
2995
3167
  }
2996
3168
  if (shouldMaintainScrollAtEnd) {
2997
3169
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2998
- doMaintainScrollAtEnd(ctx, state, false);
3170
+ doMaintainScrollAtEnd(ctx, false);
2999
3171
  }
3000
3172
  }
3001
3173
  }
3002
3174
  }
3003
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3175
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
3004
3176
  var _a3;
3177
+ const state = ctx.state;
3005
3178
  const {
3006
- sizes,
3007
3179
  indexByKey,
3008
3180
  sizesKnown,
3009
3181
  averageSizes,
@@ -3011,9 +3183,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3011
3183
  } = state;
3012
3184
  if (!data) return 0;
3013
3185
  const index = indexByKey.get(itemKey);
3014
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3186
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
3015
3187
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
3016
3188
  const size = Math.round(rawSize) ;
3189
+ const prevSizeKnown = sizesKnown.get(itemKey);
3017
3190
  sizesKnown.set(itemKey, size);
3018
3191
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
3019
3192
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -3021,11 +3194,15 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3021
3194
  if (!averages) {
3022
3195
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3023
3196
  }
3024
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3025
- averages.num++;
3197
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3198
+ averages.avg += (size - prevSizeKnown) / averages.num;
3199
+ } else {
3200
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3201
+ averages.num++;
3202
+ }
3026
3203
  }
3027
3204
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
3028
- setSize(ctx, state, itemKey, size);
3205
+ setSize(ctx, itemKey, size);
3029
3206
  return size - prevSize;
3030
3207
  }
3031
3208
  return 0;
@@ -3072,14 +3249,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
3072
3249
  }
3073
3250
 
3074
3251
  // src/utils/createImperativeHandle.ts
3075
- function createImperativeHandle(ctx, state) {
3252
+ function createImperativeHandle(ctx) {
3253
+ const state = ctx.state;
3076
3254
  const scrollIndexIntoView = (options) => {
3077
3255
  if (state) {
3078
3256
  const { index, ...rest } = options;
3079
3257
  const { startNoBuffer, endNoBuffer } = state;
3080
3258
  if (index < startNoBuffer || index > endNoBuffer) {
3081
3259
  const viewPosition = index < startNoBuffer ? 0 : 1;
3082
- scrollToIndex(ctx, state, {
3260
+ scrollToIndex(ctx, {
3083
3261
  ...rest,
3084
3262
  index,
3085
3263
  viewPosition
@@ -3094,7 +3272,7 @@ function createImperativeHandle(ctx, state) {
3094
3272
  getScrollableNode: () => refScroller.current.getScrollableNode(),
3095
3273
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3096
3274
  getState: () => ({
3097
- activeStickyIndex: state.activeStickyIndex,
3275
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3098
3276
  contentLength: state.totalSize,
3099
3277
  data: state.props.data,
3100
3278
  elementAtIndex: (index) => {
@@ -3105,6 +3283,8 @@ function createImperativeHandle(ctx, state) {
3105
3283
  endBuffered: state.endBuffered,
3106
3284
  isAtEnd: state.isAtEnd,
3107
3285
  isAtStart: state.isAtStart,
3286
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3287
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3108
3288
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
3109
3289
  positions: state.positions,
3110
3290
  scroll: state.scroll,
@@ -3129,23 +3309,23 @@ function createImperativeHandle(ctx, state) {
3129
3309
  if (index !== -1) {
3130
3310
  const paddingBottom = stylePaddingBottom || 0;
3131
3311
  const footerSize = peek$(ctx, "footerSize") || 0;
3132
- scrollToIndex(ctx, state, {
3312
+ scrollToIndex(ctx, {
3313
+ ...options,
3133
3314
  index,
3134
3315
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3135
- viewPosition: 1,
3136
- ...options
3316
+ viewPosition: 1
3137
3317
  });
3138
3318
  }
3139
3319
  },
3140
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3320
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
3141
3321
  scrollToItem: ({ item, ...props }) => {
3142
3322
  const data = state.props.data;
3143
3323
  const index = data.indexOf(item);
3144
3324
  if (index !== -1) {
3145
- scrollToIndex(ctx, state, { index, ...props });
3325
+ scrollToIndex(ctx, { index, ...props });
3146
3326
  }
3147
3327
  },
3148
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3328
+ scrollToOffset: (params) => scrollTo(ctx, params),
3149
3329
  setScrollProcessingEnabled: (enabled) => {
3150
3330
  state.scrollProcessingEnabled = enabled;
3151
3331
  },
@@ -3155,8 +3335,9 @@ function createImperativeHandle(ctx, state) {
3155
3335
  }
3156
3336
  };
3157
3337
  }
3158
- function getRenderedItem(ctx, state, key) {
3338
+ function getRenderedItem(ctx, key) {
3159
3339
  var _a3;
3340
+ const state = ctx.state;
3160
3341
  if (!state) {
3161
3342
  return null;
3162
3343
  }
@@ -3233,11 +3414,13 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3233
3414
  var DEFAULT_DRAW_DISTANCE = 250;
3234
3415
  var DEFAULT_ITEM_SIZE = 100;
3235
3416
  var LegendList = typedMemo(
3417
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3236
3418
  typedForwardRef(function LegendList2(props, forwardedRef) {
3237
3419
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3238
3420
  const isChildrenMode = children !== void 0 && dataProp === void 0;
3239
3421
  const processedProps = isChildrenMode ? {
3240
3422
  ...restProps,
3423
+ childrenMode: true,
3241
3424
  data: (isArray(children) ? children : React3__namespace.Children.toArray(children)).flat(1),
3242
3425
  renderItem: ({ item }) => item
3243
3426
  } : {
@@ -3254,10 +3437,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3254
3437
  alignItemsAtEnd = false,
3255
3438
  columnWrapperStyle,
3256
3439
  contentContainerStyle: contentContainerStyleProp,
3440
+ contentInset,
3257
3441
  data: dataProp = [],
3258
3442
  dataVersion,
3259
3443
  drawDistance = 250,
3260
- enableAverages = true,
3261
3444
  estimatedItemSize: estimatedItemSizeProp,
3262
3445
  estimatedListSize,
3263
3446
  extraData,
@@ -3299,6 +3482,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3299
3482
  snapToIndices,
3300
3483
  stickyHeaderIndices: stickyHeaderIndicesProp,
3301
3484
  stickyIndices: stickyIndicesDeprecated,
3485
+ // TODOV3: Remove from v3 release
3302
3486
  style: styleProp,
3303
3487
  suggestEstimatedItemSize,
3304
3488
  viewabilityConfig,
@@ -3306,6 +3490,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3306
3490
  waitForInitialLayout = true,
3307
3491
  ...rest
3308
3492
  } = props;
3493
+ const animatedPropsInternal = props.animatedPropsInternal;
3494
+ const { childrenMode } = rest;
3309
3495
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3310
3496
  const style = { ...StyleSheet.flatten(styleProp) };
3311
3497
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
@@ -3329,10 +3515,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3329
3515
  }
3330
3516
  const refState = React3.useRef();
3331
3517
  if (!refState.current) {
3332
- if (!ctx.internalState) {
3518
+ if (!ctx.state) {
3333
3519
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
3334
- ctx.internalState = {
3335
- activeStickyIndex: void 0,
3520
+ ctx.state = {
3521
+ activeStickyIndex: -1,
3336
3522
  averageSizes: {},
3337
3523
  columns: /* @__PURE__ */ new Map(),
3338
3524
  containerItemKeys: /* @__PURE__ */ new Set(),
@@ -3358,9 +3544,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3358
3544
  initialScroll: initialScrollProp,
3359
3545
  isAtEnd: false,
3360
3546
  isAtStart: false,
3361
- isEndReached: false,
3547
+ isEndReached: null,
3362
3548
  isFirst: true,
3363
- isStartReached: false,
3549
+ isStartReached: null,
3364
3550
  lastBatchingAction: Date.now(),
3365
3551
  lastLayout: void 0,
3366
3552
  loadStartTime: Date.now(),
@@ -3392,12 +3578,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3392
3578
  totalSize: 0,
3393
3579
  viewabilityConfigCallbackPairs: void 0
3394
3580
  };
3395
- const internalState = ctx.internalState;
3396
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3581
+ const internalState = ctx.state;
3582
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3397
3583
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3398
3584
  set$(ctx, "extraData", extraData);
3399
3585
  }
3400
- refState.current = ctx.internalState;
3586
+ refState.current = ctx.state;
3401
3587
  }
3402
3588
  const state = refState.current;
3403
3589
  const isFirstLocal = state.isFirst;
@@ -3411,9 +3597,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3411
3597
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3412
3598
  state.props = {
3413
3599
  alignItemsAtEnd,
3600
+ animatedProps: animatedPropsInternal,
3601
+ contentInset,
3414
3602
  data: dataProp,
3415
3603
  dataVersion,
3416
- enableAverages,
3417
3604
  estimatedItemSize,
3418
3605
  getEstimatedItemSize,
3419
3606
  getFixedItemSize,
@@ -3456,62 +3643,52 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3456
3643
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3457
3644
  set$(ctx, "numColumns", numColumnsProp);
3458
3645
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3459
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3646
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3460
3647
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3461
3648
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3462
3649
  if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3463
3650
  if (state.scroll < 0) {
3464
3651
  paddingDiff += state.scroll;
3465
3652
  }
3466
- requestAdjust(ctx, state, paddingDiff);
3653
+ requestAdjust(ctx, paddingDiff);
3467
3654
  }
3468
3655
  };
3469
3656
  if (isFirstLocal) {
3470
3657
  initializeStateVars();
3471
3658
  updateItemPositions(
3472
3659
  ctx,
3473
- state,
3474
3660
  /*dataChanged*/
3475
3661
  true
3476
3662
  );
3477
3663
  }
3478
3664
  const initialContentOffset = React3.useMemo(() => {
3479
- var _a4, _b2;
3480
- const { initialScroll } = refState.current;
3481
- if (!initialScroll) {
3665
+ let value;
3666
+ const { initialScroll, initialAnchor } = refState.current;
3667
+ if (initialScroll) {
3668
+ if (initialScroll.contentOffset !== void 0) {
3669
+ value = initialScroll.contentOffset;
3670
+ } else {
3671
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3672
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3673
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3674
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3675
+ refState.current.initialScroll = updatedInitialScroll;
3676
+ state.initialScroll = updatedInitialScroll;
3677
+ value = clampedOffset;
3678
+ }
3679
+ } else {
3482
3680
  refState.current.initialAnchor = void 0;
3483
- return 0;
3484
- }
3485
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3486
- refState.current.initialAnchor = {
3487
- attempts: 0,
3488
- index: initialScroll.index,
3489
- settledTicks: 0,
3490
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3491
- viewPosition: initialScroll.viewPosition
3492
- };
3681
+ value = 0;
3493
3682
  }
3494
- if (initialScroll.contentOffset !== void 0) {
3495
- return initialScroll.contentOffset;
3496
- }
3497
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3498
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3499
- let clampedOffset = resolvedOffset;
3500
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3501
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3502
- clampedOffset = Math.min(clampedOffset, maxOffset);
3503
- }
3504
- clampedOffset = Math.max(0, clampedOffset);
3505
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3506
- refState.current.initialScroll = updatedInitialScroll;
3507
- state.initialScroll = updatedInitialScroll;
3508
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3509
- return clampedOffset;
3683
+ if (!value) {
3684
+ state.didFinishInitialScroll = true;
3685
+ }
3686
+ return value;
3510
3687
  }, [renderNum]);
3511
3688
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3512
3689
  refState.current.lastBatchingAction = Date.now();
3513
3690
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3514
- IS_DEV && warnDevOnce(
3691
+ IS_DEV && !childrenMode && warnDevOnce(
3515
3692
  "keyExtractor",
3516
3693
  "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."
3517
3694
  );
@@ -3534,12 +3711,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3534
3711
  }
3535
3712
  }, []);
3536
3713
  const doInitialScroll = React3.useCallback(() => {
3537
- var _a4;
3538
3714
  const initialScroll = state.initialScroll;
3539
3715
  if (initialScroll) {
3540
- scrollTo(ctx, state, {
3716
+ scrollTo(ctx, {
3541
3717
  animated: false,
3542
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3718
+ index: initialScroll == null ? void 0 : initialScroll.index,
3543
3719
  isInitialScroll: true,
3544
3720
  offset: initialContentOffset,
3545
3721
  precomputedWithViewOffset: true
@@ -3548,7 +3724,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3548
3724
  }, [initialContentOffset]);
3549
3725
  const onLayoutChange = React3.useCallback((layout) => {
3550
3726
  doInitialScroll();
3551
- handleLayout(ctx, state, layout, setCanRender);
3727
+ handleLayout(ctx, layout, setCanRender);
3552
3728
  }, []);
3553
3729
  const { onLayout } = useOnLayoutSync({
3554
3730
  onLayoutChange,
@@ -3558,7 +3734,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3558
3734
  });
3559
3735
  React3.useLayoutEffect(() => {
3560
3736
  if (snapToIndices) {
3561
- updateSnapToOffsets(ctx, state);
3737
+ updateSnapToOffsets(ctx);
3562
3738
  }
3563
3739
  }, [snapToIndices]);
3564
3740
  React3.useLayoutEffect(() => {
@@ -3568,9 +3744,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3568
3744
  isFirst,
3569
3745
  props: { data }
3570
3746
  } = state;
3571
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3747
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3572
3748
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3573
- checkResetContainers(ctx, state, data);
3749
+ checkResetContainers(ctx, data);
3574
3750
  }
3575
3751
  state.didColumnsChange = false;
3576
3752
  state.didDataChange = false;
@@ -3595,15 +3771,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3595
3771
  state.viewabilityConfigCallbackPairs = viewability;
3596
3772
  state.enableScrollForNextCalculateItemsInView = !viewability;
3597
3773
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3598
- React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3774
+ React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3599
3775
  {
3600
3776
  React3.useEffect(doInitialScroll, []);
3601
3777
  }
3602
3778
  const fns = React3.useMemo(
3603
3779
  () => ({
3604
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3605
- onScroll: (event) => onScroll(ctx, state, event),
3606
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3780
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
3781
+ onMomentumScrollEnd: (event) => {
3782
+ checkFinishedScrollFallback(ctx);
3783
+ if (onMomentumScrollEnd) {
3784
+ onMomentumScrollEnd(event);
3785
+ }
3786
+ },
3787
+ onScroll: (event) => onScroll(ctx, event),
3788
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3607
3789
  }),
3608
3790
  []
3609
3791
  );
@@ -3615,6 +3797,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3615
3797
  alignItemsAtEnd,
3616
3798
  canRender,
3617
3799
  contentContainerStyle,
3800
+ contentInset,
3618
3801
  getRenderedItem: fns.getRenderedItem,
3619
3802
  horizontal,
3620
3803
  initialContentOffset,
@@ -3623,16 +3806,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3623
3806
  maintainVisibleContentPosition,
3624
3807
  onLayout,
3625
3808
  onLayoutHeader,
3626
- onMomentumScrollEnd: (event) => {
3627
- {
3628
- requestAnimationFrame(() => {
3629
- finishScrollTo(ctx, refState.current);
3630
- });
3631
- }
3632
- if (onMomentumScrollEnd) {
3633
- onMomentumScrollEnd(event);
3634
- }
3635
- },
3809
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3636
3810
  onScroll: onScrollHandler,
3637
3811
  recycleItems,
3638
3812
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControl, {
@@ -3647,7 +3821,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3647
3821
  ),
3648
3822
  refScrollView: combinedRef,
3649
3823
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3650
- scrollEventThrottle: 16 ,
3824
+ scrollEventThrottle: 0,
3651
3825
  snapToIndices,
3652
3826
  stickyHeaderIndices,
3653
3827
  style,
@@ -3693,8 +3867,8 @@ function buildSectionListData({
3693
3867
  if (hasHeader) {
3694
3868
  const headerIndex = data.length;
3695
3869
  data.push({
3696
- kind: "header",
3697
3870
  key: `${sectionKey}:header`,
3871
+ kind: "header",
3698
3872
  section,
3699
3873
  sectionIndex
3700
3874
  });
@@ -3708,31 +3882,31 @@ function buildSectionListData({
3708
3882
  const itemKeyExtractor = (_b = section.keyExtractor) != null ? _b : keyExtractor;
3709
3883
  const itemKey = itemKeyExtractor(item, itemIndex);
3710
3884
  data.push({
3711
- kind: "item",
3712
- key: `${sectionKey}:item:${itemKey}`,
3713
- section,
3714
- sectionIndex,
3885
+ absoluteItemIndex: absoluteItemIndex++,
3715
3886
  item,
3716
3887
  itemIndex,
3717
- absoluteItemIndex: absoluteItemIndex++
3888
+ key: `${sectionKey}:item:${itemKey}`,
3889
+ kind: "item",
3890
+ section,
3891
+ sectionIndex
3718
3892
  });
3719
3893
  meta.items.push(data.length - 1);
3720
3894
  if (hasItemSeparator && itemIndex < items.length - 1) {
3721
3895
  data.push({
3722
- kind: "item-separator",
3723
3896
  key: `${sectionKey}:separator:${itemIndex}`,
3724
- section,
3725
- sectionIndex,
3897
+ kind: "item-separator",
3726
3898
  leadingItem: item,
3727
3899
  leadingItemIndex: itemIndex,
3900
+ section,
3901
+ sectionIndex,
3728
3902
  trailingItem: items[itemIndex + 1]
3729
3903
  });
3730
3904
  }
3731
3905
  }
3732
3906
  if (hasFooter) {
3733
3907
  data.push({
3734
- kind: "footer",
3735
3908
  key: `${sectionKey}:footer`,
3909
+ kind: "footer",
3736
3910
  section,
3737
3911
  sectionIndex
3738
3912
  });
@@ -3741,8 +3915,8 @@ function buildSectionListData({
3741
3915
  const isLastSection = sectionIndex === sections.length - 1;
3742
3916
  if (hasSectionSeparator && !isLastSection) {
3743
3917
  data.push({
3744
- kind: "section-separator",
3745
3918
  key: `${sectionKey}:section-separator`,
3919
+ kind: "section-separator",
3746
3920
  leadingSection: section,
3747
3921
  leadingSectionIndex: sectionIndex,
3748
3922
  trailingSection: sections[sectionIndex + 1]