@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/index.mjs CHANGED
@@ -12,31 +12,65 @@ var View = forwardRef(function View2(props, ref) {
12
12
  });
13
13
  var Text = View;
14
14
 
15
+ // src/state/getContentInsetEnd.ts
16
+ function getContentInsetEnd(state) {
17
+ var _a3;
18
+ const { props } = state;
19
+ const horizontal = props.horizontal;
20
+ let contentInset = props.contentInset;
21
+ if (!contentInset) {
22
+ const animatedInset = (_a3 = props.animatedProps) == null ? void 0 : _a3.contentInset;
23
+ if (animatedInset) {
24
+ if ("get" in animatedInset) {
25
+ contentInset = animatedInset.get();
26
+ } else {
27
+ contentInset = animatedInset;
28
+ }
29
+ }
30
+ }
31
+ return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
32
+ }
33
+
34
+ // src/state/getContentSize.ts
35
+ function getContentSize(ctx) {
36
+ var _a3;
37
+ const { values, state } = ctx;
38
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
39
+ const stylePaddingBottom = state.props.stylePaddingBottom || 0;
40
+ const headerSize = values.get("headerSize") || 0;
41
+ const footerSize = values.get("footerSize") || 0;
42
+ const contentInsetBottom = getContentInsetEnd(state);
43
+ const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
44
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
45
+ }
46
+
15
47
  // src/platform/Animated.tsx
16
48
  var createAnimatedValue = (value) => value;
17
49
 
18
50
  // src/state/state.tsx
19
51
  var ContextState = React3.createContext(null);
52
+ var contextNum = 0;
20
53
  function StateProvider({ children }) {
21
54
  const [value] = React3.useState(() => ({
22
55
  animatedScrollY: createAnimatedValue(0),
23
56
  columnWrapperStyle: void 0,
24
- internalState: void 0,
57
+ contextNum: contextNum++,
25
58
  listeners: /* @__PURE__ */ new Map(),
26
59
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
27
60
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
28
61
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
29
62
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
30
63
  mapViewabilityValues: /* @__PURE__ */ new Map(),
64
+ positionListeners: /* @__PURE__ */ new Map(),
65
+ state: void 0,
31
66
  values: /* @__PURE__ */ new Map([
32
67
  ["alignItemsPaddingTop", 0],
33
68
  ["stylePaddingTop", 0],
34
69
  ["headerSize", 0],
35
70
  ["numContainers", 0],
36
- ["activeStickyIndex", void 0],
71
+ ["activeStickyIndex", -1],
37
72
  ["totalSize", 0],
38
- ["scrollAdjustPending", 0],
39
- ["scrollingTo", void 0]
73
+ ["scrollAdjustPending", 0]
40
74
  ]),
41
75
  viewRefs: /* @__PURE__ */ new Map()
42
76
  }));
@@ -104,14 +138,24 @@ function set$(ctx, signalName, value) {
104
138
  }
105
139
  }
106
140
  }
107
- function getContentSize(ctx) {
108
- var _a3, _b;
109
- const { values } = ctx;
110
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
111
- const headerSize = values.get("headerSize") || 0;
112
- const footerSize = values.get("footerSize") || 0;
113
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
114
- return headerSize + footerSize + totalSize + stylePaddingTop;
141
+ function listenPosition$(ctx, key, cb) {
142
+ const { positionListeners } = ctx;
143
+ let setListeners = positionListeners.get(key);
144
+ if (!setListeners) {
145
+ setListeners = /* @__PURE__ */ new Set();
146
+ positionListeners.set(key, setListeners);
147
+ }
148
+ setListeners.add(cb);
149
+ return () => setListeners.delete(cb);
150
+ }
151
+ function notifyPosition$(ctx, key, value) {
152
+ const { positionListeners } = ctx;
153
+ const setListeners = positionListeners.get(key);
154
+ if (setListeners) {
155
+ for (const listener of setListeners) {
156
+ listener(value);
157
+ }
158
+ }
115
159
  }
116
160
  function useArr$(signalNames) {
117
161
  const ctx = React3.useContext(ContextState);
@@ -233,12 +277,12 @@ function findContainerId(ctx, key) {
233
277
  }
234
278
 
235
279
  // src/components/PositionView.tsx
236
- var PositionViewState = typedMemo(function PositionView({
280
+ var PositionViewState = typedMemo(function PositionViewState2({
237
281
  id,
238
282
  horizontal,
239
283
  style,
240
284
  refView,
241
- ...rest
285
+ ...props
242
286
  }) {
243
287
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
244
288
  const base = {
@@ -246,7 +290,8 @@ var PositionViewState = typedMemo(function PositionView({
246
290
  };
247
291
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
248
292
  const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
249
- return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: combinedStyle, ...rest });
293
+ const { animatedScrollY, stickyOffset, onLayout, ...webProps } = props;
294
+ return /* @__PURE__ */ React3.createElement("div", { ref: refView, ...webProps, style: combinedStyle });
250
295
  });
251
296
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
252
297
  id,
@@ -291,17 +336,12 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
291
336
  }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
292
337
  return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
293
338
  });
294
- var PositionView2 = PositionViewState;
339
+ var PositionView = PositionViewState;
295
340
 
296
341
  // src/constants-platform.ts
297
342
  var IsNewArchitecture = true;
298
- var symbolFirst = Symbol();
299
343
  function useInit(cb) {
300
- const refValue = useRef(symbolFirst);
301
- if (refValue.current === symbolFirst) {
302
- refValue.current = cb();
303
- }
304
- return refValue.current;
344
+ useState(() => cb());
305
345
  }
306
346
 
307
347
  // src/state/ContextContainer.ts
@@ -449,10 +489,9 @@ function createResizeObserver(element, callback) {
449
489
  }
450
490
  callbacks.add(callback);
451
491
  return () => {
452
- const callbacks2 = callbackMap.get(element);
453
- if (callbacks2) {
454
- callbacks2.delete(callback);
455
- if (callbacks2.size === 0) {
492
+ if (callbacks) {
493
+ callbacks.delete(callback);
494
+ if (callbacks.size === 0) {
456
495
  callbackMap.delete(element);
457
496
  observer.unobserve(element);
458
497
  }
@@ -487,10 +526,10 @@ function useOnLayoutSync({
487
526
  return createResizeObserver(element, (entry) => {
488
527
  var _a4;
489
528
  const target = entry.target instanceof HTMLElement ? entry.target : void 0;
490
- const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
491
- if (rect2.width !== prevRect.width || rect2.height !== prevRect.height) {
492
- prevRect = rect2;
493
- emit(toLayout(rect2), false);
529
+ const rectObserved = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
530
+ if (rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height) {
531
+ prevRect = rectObserved;
532
+ emit(toLayout(rectObserved), false);
494
533
  }
495
534
  });
496
535
  }, deps || []);
@@ -618,7 +657,7 @@ var Container = typedMemo(function Container2({
618
657
  },
619
658
  [itemKey, layoutRenderCount]
620
659
  );
621
- const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
660
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
622
661
  return /* @__PURE__ */ React3.createElement(
623
662
  PositionComponent,
624
663
  {
@@ -811,7 +850,8 @@ var Containers = typedMemo(function Containers2({
811
850
  return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
812
851
  });
813
852
  function DevNumbers() {
814
- return IS_DEV && React3.memo(function DevNumbers2() {
853
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
854
+ React3.memo(function DevNumbers2() {
815
855
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3.createElement(
816
856
  "div",
817
857
  {
@@ -859,7 +899,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
859
899
  }, ref) {
860
900
  const scrollRef = useRef(null);
861
901
  const contentRef = useRef(null);
862
- const momentumTimeout = useRef(null);
863
902
  useImperativeHandle(ref, () => {
864
903
  const api = {
865
904
  getBoundingClientRect: () => {
@@ -925,16 +964,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
925
964
  }
926
965
  };
927
966
  onScroll2(scrollEvent);
928
- if (onMomentumScrollEnd) {
929
- if (momentumTimeout.current != null) clearTimeout(momentumTimeout.current);
930
- momentumTimeout.current = setTimeout(() => {
931
- onMomentumScrollEnd({
932
- nativeEvent: {
933
- contentOffset: scrollEvent.nativeEvent.contentOffset
934
- }
935
- });
936
- }, 100);
937
- }
938
967
  },
939
968
  [onScroll2, onMomentumScrollEnd]
940
969
  );
@@ -996,7 +1025,8 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
996
1025
  minWidth: horizontal ? "100%" : void 0,
997
1026
  ...StyleSheet.flatten(contentContainerStyle)
998
1027
  };
999
- return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
1028
+ const { contentInset, scrollEventThrottle, ScrollComponent, ...webProps } = props;
1029
+ return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
1000
1030
  });
1001
1031
  function Padding() {
1002
1032
  const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
@@ -1037,7 +1067,7 @@ function ScrollAdjust() {
1037
1067
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1038
1068
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1039
1069
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1040
- const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
1070
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1041
1071
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1042
1072
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1043
1073
  if (scrollDelta !== 0) {
@@ -1045,16 +1075,16 @@ function ScrollAdjust() {
1045
1075
  const prevScroll = el.scrollTop;
1046
1076
  const nextScroll = prevScroll + scrollDelta;
1047
1077
  const totalSize = el.scrollHeight;
1048
- if (scrollDelta > 0 && !ctx.internalState.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1078
+ if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1049
1079
  const child = el.firstElementChild;
1050
1080
  const prevPaddingBottom = child.style.paddingBottom;
1051
1081
  const pad = (nextScroll + el.clientHeight - totalSize) * 2;
1052
1082
  child.style.paddingBottom = `${pad}px`;
1053
1083
  void el.offsetHeight;
1054
1084
  scrollView.scrollBy(0, scrollDelta);
1055
- setTimeout(() => {
1085
+ requestAnimationFrame(() => {
1056
1086
  child.style.paddingBottom = prevPaddingBottom;
1057
- }, 100);
1087
+ });
1058
1088
  } else {
1059
1089
  scrollView.scrollBy(0, scrollDelta);
1060
1090
  }
@@ -1064,7 +1094,7 @@ function ScrollAdjust() {
1064
1094
  }
1065
1095
  lastScrollOffsetRef.current = scrollOffset;
1066
1096
  }
1067
- }, []);
1097
+ }, [ctx]);
1068
1098
  useValueListener$("scrollAdjust", callback);
1069
1099
  useValueListener$("scrollAdjustUserOffset", callback);
1070
1100
  return null;
@@ -1122,13 +1152,6 @@ var ListComponent = typedMemo(function ListComponent2({
1122
1152
  () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1123
1153
  [renderScrollComponent]
1124
1154
  ) : ListComponentScrollView;
1125
- React3.useEffect(() => {
1126
- if (canRender) {
1127
- setTimeout(() => {
1128
- scrollAdjustHandler.setMounted();
1129
- }, 0);
1130
- }
1131
- }, [canRender]);
1132
1155
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1133
1156
  return /* @__PURE__ */ React3.createElement(
1134
1157
  SnapOrScroll,
@@ -1192,10 +1215,11 @@ function getId(state, index) {
1192
1215
  }
1193
1216
 
1194
1217
  // src/core/calculateOffsetForIndex.ts
1195
- function calculateOffsetForIndex(ctx, state, index) {
1218
+ function calculateOffsetForIndex(ctx, index) {
1219
+ const state = ctx.state;
1196
1220
  let position = 0;
1197
1221
  if (index !== void 0) {
1198
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
1222
+ position = state.positions.get(getId(state, index)) || 0;
1199
1223
  const paddingTop = peek$(ctx, "stylePaddingTop");
1200
1224
  if (paddingTop) {
1201
1225
  position += paddingTop;
@@ -1209,7 +1233,8 @@ function calculateOffsetForIndex(ctx, state, index) {
1209
1233
  }
1210
1234
 
1211
1235
  // src/utils/setPaddingTop.ts
1212
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1236
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1237
+ const state = ctx.state;
1213
1238
  if (stylePaddingTop !== void 0) {
1214
1239
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1215
1240
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -1228,7 +1253,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1228
1253
  }
1229
1254
 
1230
1255
  // src/utils/updateAlignItemsPaddingTop.ts
1231
- function updateAlignItemsPaddingTop(ctx, state) {
1256
+ function updateAlignItemsPaddingTop(ctx) {
1257
+ const state = ctx.state;
1232
1258
  const {
1233
1259
  scrollLength,
1234
1260
  props: { alignItemsAtEnd, data }
@@ -1239,12 +1265,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
1239
1265
  const contentSize = getContentSize(ctx);
1240
1266
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1241
1267
  }
1242
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1268
+ setPaddingTop(ctx, { alignItemsPaddingTop });
1243
1269
  }
1244
1270
  }
1245
1271
 
1246
1272
  // src/core/addTotalSize.ts
1247
- function addTotalSize(ctx, state, key, add) {
1273
+ function addTotalSize(ctx, key, add) {
1274
+ const state = ctx.state;
1248
1275
  const { alignItemsAtEnd } = state.props;
1249
1276
  const prevTotalSize = state.totalSize;
1250
1277
  let totalSize = state.totalSize;
@@ -1263,31 +1290,34 @@ function addTotalSize(ctx, state, key, add) {
1263
1290
  state.totalSize = totalSize;
1264
1291
  set$(ctx, "totalSize", totalSize);
1265
1292
  if (alignItemsAtEnd) {
1266
- updateAlignItemsPaddingTop(ctx, state);
1293
+ updateAlignItemsPaddingTop(ctx);
1267
1294
  }
1268
1295
  }
1269
1296
  }
1270
1297
  }
1271
1298
 
1272
1299
  // src/core/setSize.ts
1273
- function setSize(ctx, state, itemKey, size) {
1300
+ function setSize(ctx, itemKey, size) {
1301
+ const state = ctx.state;
1274
1302
  const { sizes } = state;
1275
1303
  const previousSize = sizes.get(itemKey);
1276
1304
  const diff = previousSize !== void 0 ? size - previousSize : size;
1277
1305
  if (diff !== 0) {
1278
- addTotalSize(ctx, state, itemKey, diff);
1306
+ addTotalSize(ctx, itemKey, diff);
1279
1307
  }
1280
1308
  sizes.set(itemKey, size);
1281
1309
  }
1282
1310
 
1283
1311
  // src/utils/getItemSize.ts
1284
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1312
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1285
1313
  var _a3, _b;
1314
+ const state = ctx.state;
1286
1315
  const {
1287
1316
  sizesKnown,
1288
1317
  sizes,
1289
1318
  averageSizes,
1290
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1319
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1320
+ scrollingTo
1291
1321
  } = state;
1292
1322
  const sizeKnown = sizesKnown.get(key);
1293
1323
  if (sizeKnown !== void 0) {
@@ -1295,7 +1325,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1295
1325
  }
1296
1326
  let size;
1297
1327
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1298
- const scrollingTo = peek$(ctx, "scrollingTo");
1299
1328
  if (preferCachedSize) {
1300
1329
  const cachedSize = sizes.get(key);
1301
1330
  if (cachedSize !== void 0) {
@@ -1323,81 +1352,169 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1323
1352
  if (size === void 0) {
1324
1353
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1325
1354
  }
1326
- setSize(ctx, state, key, size);
1355
+ setSize(ctx, key, size);
1327
1356
  return size;
1328
1357
  }
1329
1358
 
1330
1359
  // src/core/calculateOffsetWithOffsetPosition.ts
1331
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1360
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1361
+ const state = ctx.state;
1332
1362
  const { index, viewOffset, viewPosition } = params;
1333
1363
  let offset = offsetParam;
1334
1364
  if (viewOffset) {
1335
1365
  offset -= viewOffset;
1336
1366
  }
1337
1367
  if (viewPosition !== void 0 && index !== void 0) {
1338
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1368
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1369
+ const trailingInset = getContentInsetEnd(state);
1370
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1339
1371
  }
1340
1372
  return offset;
1341
1373
  }
1342
1374
 
1375
+ // src/core/clampScrollOffset.ts
1376
+ function clampScrollOffset(ctx, offset) {
1377
+ const state = ctx.state;
1378
+ const contentSize = getContentSize(ctx);
1379
+ let clampedOffset = offset;
1380
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1381
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1382
+ clampedOffset = Math.min(offset, maxOffset);
1383
+ }
1384
+ clampedOffset = Math.max(0, clampedOffset);
1385
+ return clampedOffset;
1386
+ }
1387
+
1388
+ // src/utils/setInitialRenderState.ts
1389
+ function setInitialRenderState(ctx, {
1390
+ didLayout,
1391
+ didInitialScroll
1392
+ }) {
1393
+ const { state } = ctx;
1394
+ if (didLayout) {
1395
+ state.didContainersLayout = true;
1396
+ }
1397
+ if (didInitialScroll) {
1398
+ state.didFinishInitialScroll = true;
1399
+ }
1400
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1401
+ set$(ctx, "readyToRender", true);
1402
+ }
1403
+ }
1404
+
1343
1405
  // src/core/finishScrollTo.ts
1344
- function finishScrollTo(ctx, state) {
1406
+ function finishScrollTo(ctx) {
1345
1407
  var _a3, _b;
1346
- if (state) {
1408
+ const state = ctx.state;
1409
+ if (state == null ? void 0 : state.scrollingTo) {
1347
1410
  state.scrollHistory.length = 0;
1348
1411
  state.initialScroll = void 0;
1349
1412
  state.initialAnchor = void 0;
1350
- set$(ctx, "scrollingTo", void 0);
1413
+ state.scrollingTo = void 0;
1351
1414
  if (state.pendingTotalSize !== void 0) {
1352
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1415
+ addTotalSize(ctx, null, state.pendingTotalSize);
1353
1416
  }
1354
1417
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1355
1418
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1356
1419
  }
1420
+ {
1421
+ state.scrollAdjustHandler.commitPendingAdjust();
1422
+ }
1423
+ setInitialRenderState(ctx, { didInitialScroll: true });
1424
+ }
1425
+ }
1426
+
1427
+ // src/core/doScrollTo.ts
1428
+ var SCROLL_END_IDLE_MS = 80;
1429
+ var SCROLL_END_MAX_MS = 1500;
1430
+ var SMOOTH_SCROLL_DURATION_MS = 320;
1431
+ function doScrollTo(ctx, params) {
1432
+ const state = ctx.state;
1433
+ const { animated, horizontal, offset } = params;
1434
+ const scroller = state.refScroller.current;
1435
+ const node = typeof (scroller == null ? void 0 : scroller.getScrollableNode) === "function" ? scroller.getScrollableNode() : scroller;
1436
+ if (node) {
1437
+ const left = horizontal ? offset : 0;
1438
+ const top = horizontal ? 0 : offset;
1439
+ node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1440
+ if (animated) {
1441
+ listenForScrollEnd(ctx, node);
1442
+ } else {
1443
+ state.scroll = offset;
1444
+ setTimeout(() => {
1445
+ finishScrollTo(ctx);
1446
+ }, 100);
1447
+ }
1448
+ }
1449
+ }
1450
+ function listenForScrollEnd(ctx, node) {
1451
+ const supportsScrollEnd = "onscrollend" in node;
1452
+ let idleTimeout;
1453
+ let maxTimeout;
1454
+ let settled = false;
1455
+ const targetToken = ctx.state.scrollingTo;
1456
+ const finish = () => {
1457
+ if (settled) return;
1458
+ settled = true;
1459
+ cleanup();
1460
+ if (targetToken === ctx.state.scrollingTo) {
1461
+ finishScrollTo(ctx);
1462
+ }
1463
+ };
1464
+ const onScroll2 = () => {
1465
+ if (idleTimeout) {
1466
+ clearTimeout(idleTimeout);
1467
+ }
1468
+ idleTimeout = setTimeout(finish, SCROLL_END_IDLE_MS);
1469
+ };
1470
+ const cleanup = () => {
1471
+ if (supportsScrollEnd) {
1472
+ node.removeEventListener("scrollend", finish);
1473
+ } else {
1474
+ node.removeEventListener("scroll", onScroll2);
1475
+ }
1476
+ if (idleTimeout) {
1477
+ clearTimeout(idleTimeout);
1478
+ }
1479
+ if (maxTimeout) {
1480
+ clearTimeout(maxTimeout);
1481
+ }
1482
+ };
1483
+ if (supportsScrollEnd) {
1484
+ node.addEventListener("scrollend", finish, { once: true });
1485
+ } else {
1486
+ node.addEventListener("scroll", onScroll2);
1487
+ idleTimeout = setTimeout(finish, SMOOTH_SCROLL_DURATION_MS);
1488
+ maxTimeout = setTimeout(finish, SCROLL_END_MAX_MS);
1357
1489
  }
1490
+ return cleanup;
1358
1491
  }
1359
1492
 
1360
1493
  // src/core/scrollTo.ts
1361
- function scrollTo(ctx, state, params) {
1362
- var _a3;
1363
- const { noScrollingTo, ...scrollTarget } = params;
1494
+ function scrollTo(ctx, params) {
1495
+ const state = ctx.state;
1496
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1364
1497
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1365
1498
  const {
1366
- refScroller,
1367
1499
  props: { horizontal }
1368
1500
  } = state;
1369
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1370
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1371
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1372
- offset = Math.min(offset, maxOffset);
1501
+ if (state.animFrameCheckFinishedScroll) {
1502
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1503
+ }
1504
+ if (state.timeoutCheckFinishedScrollFallback) {
1505
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1373
1506
  }
1507
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1508
+ offset = clampScrollOffset(ctx, offset);
1374
1509
  state.scrollHistory.length = 0;
1375
1510
  if (!noScrollingTo) {
1376
- set$(ctx, "scrollingTo", scrollTarget);
1511
+ state.scrollingTo = scrollTarget;
1377
1512
  }
1378
1513
  state.scrollPending = offset;
1379
- if (!isInitialScroll || Platform.OS === "android") {
1380
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1381
- animated: !!animated,
1382
- x: horizontal ? offset : 0,
1383
- y: horizontal ? 0 : offset
1384
- });
1385
- }
1386
- if (!animated) {
1514
+ if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1515
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1516
+ } else {
1387
1517
  state.scroll = offset;
1388
- {
1389
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1390
- if (value && peek$(ctx, "scrollingTo")) {
1391
- finishScrollTo(ctx, state);
1392
- unlisten();
1393
- }
1394
- });
1395
- }
1396
- if (isInitialScroll) {
1397
- setTimeout(() => {
1398
- state.initialScroll = void 0;
1399
- }, 500);
1400
- }
1401
1518
  }
1402
1519
  }
1403
1520
 
@@ -1406,6 +1523,12 @@ var HYSTERESIS_MULTIPLIER = 1.3;
1406
1523
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1407
1524
  const absDistance = Math.abs(distance);
1408
1525
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1526
+ if (wasReached === null) {
1527
+ if (!within && distance >= 0) {
1528
+ return false;
1529
+ }
1530
+ return null;
1531
+ }
1409
1532
  const updateSnapshot = () => {
1410
1533
  setSnapshot == null ? void 0 : setSnapshot({
1411
1534
  atThreshold,
@@ -1438,8 +1561,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1438
1561
  };
1439
1562
 
1440
1563
  // src/utils/checkAtBottom.ts
1441
- function checkAtBottom(ctx, state) {
1564
+ function checkAtBottom(ctx) {
1442
1565
  var _a3;
1566
+ const state = ctx.state;
1443
1567
  if (!state) {
1444
1568
  return;
1445
1569
  }
@@ -1512,15 +1636,15 @@ function checkAtTop(state) {
1512
1636
  }
1513
1637
 
1514
1638
  // src/core/updateScroll.ts
1515
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1639
+ function updateScroll(ctx, newScroll, forceUpdate) {
1516
1640
  var _a3;
1517
- const scrollingTo = peek$(ctx, "scrollingTo");
1641
+ const state = ctx.state;
1642
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1518
1643
  state.hasScrolled = true;
1519
1644
  state.lastBatchingAction = Date.now();
1520
1645
  const currentTime = Date.now();
1521
- const adjust = state.scrollAdjustHandler.getAdjust();
1522
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1523
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1646
+ const adjust = scrollAdjustHandler.getAdjust();
1647
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1524
1648
  if (adjustChanged) {
1525
1649
  state.scrollHistory.length = 0;
1526
1650
  }
@@ -1545,17 +1669,21 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1545
1669
  return;
1546
1670
  }
1547
1671
  }
1548
- if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1672
+ const lastCalculated = state.scrollLastCalculate;
1673
+ const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1674
+ if (shouldUpdate) {
1675
+ state.scrollLastCalculate = state.scroll;
1549
1676
  state.ignoreScrollFromMVCPIgnored = false;
1550
1677
  (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1551
- checkAtBottom(ctx, state);
1678
+ checkAtBottom(ctx);
1552
1679
  checkAtTop(state);
1553
1680
  state.dataChangeNeedsScrollUpdate = false;
1554
1681
  }
1555
1682
  }
1556
1683
 
1557
1684
  // src/utils/requestAdjust.ts
1558
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1685
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1686
+ const state = ctx.state;
1559
1687
  if (Math.abs(positionDiff) > 0.1) {
1560
1688
  const doit = () => {
1561
1689
  {
@@ -1567,8 +1695,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1567
1695
  };
1568
1696
  state.scroll += positionDiff;
1569
1697
  state.scrollForNextCalculateItemsInView = void 0;
1570
- const didLayout = peek$(ctx, "containersDidLayout");
1571
- if (didLayout) {
1698
+ const readyToRender = peek$(ctx, "readyToRender");
1699
+ if (readyToRender) {
1572
1700
  doit();
1573
1701
  } else {
1574
1702
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -1577,73 +1705,23 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1577
1705
  }
1578
1706
  }
1579
1707
 
1580
- // src/core/ensureInitialAnchor.ts
1581
- var INITIAL_ANCHOR_TOLERANCE = 0.5;
1582
- var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1583
- var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1584
- function ensureInitialAnchor(ctx, state) {
1585
- var _a3, _b, _c, _d, _e;
1586
- const anchor = state.initialAnchor;
1587
- const item = state.props.data[anchor.index];
1588
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1589
- if (!containersDidLayout) {
1590
- return;
1591
- }
1592
- const id = getId(state, anchor.index);
1593
- if (state.positions.get(id) === void 0) {
1594
- return;
1595
- }
1596
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1597
- if (size === void 0) {
1598
- return;
1599
- }
1600
- const availableSpace = Math.max(0, state.scrollLength - size);
1601
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1602
- const contentSize = getContentSize(ctx);
1603
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1604
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1605
- const delta = clampedDesiredOffset - state.scroll;
1606
- if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1607
- const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1608
- if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1609
- state.initialAnchor = void 0;
1610
- } else {
1611
- anchor.settledTicks = settledTicks;
1612
- }
1613
- return;
1614
- }
1615
- if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1616
- state.initialAnchor = void 0;
1617
- return;
1618
- }
1619
- const lastDelta = anchor.lastDelta;
1620
- if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1621
- state.initialAnchor = void 0;
1622
- return;
1623
- }
1624
- Object.assign(anchor, {
1625
- attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1626
- lastDelta: delta,
1627
- settledTicks: 0
1628
- });
1629
- requestAdjust(ctx, state, delta);
1630
- }
1631
-
1632
1708
  // src/core/mvcp.ts
1633
- function prepareMVCP(ctx, state, dataChanged) {
1709
+ function prepareMVCP(ctx, dataChanged) {
1710
+ const state = ctx.state;
1634
1711
  const { idsInView, positions, props } = state;
1635
1712
  const { maintainVisibleContentPosition } = props;
1636
- const scrollingTo = peek$(ctx, "scrollingTo");
1713
+ const scrollingTo = state.scrollingTo;
1637
1714
  let prevPosition;
1638
1715
  let targetId;
1639
1716
  const idsInViewWithPositions = [];
1640
1717
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1718
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1641
1719
  const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1642
1720
  const indexByKey = state.indexByKey;
1643
1721
  if (shouldMVCP) {
1644
1722
  if (scrollTarget !== void 0) {
1645
1723
  targetId = getId(state, scrollTarget);
1646
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1724
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1647
1725
  if (dataChanged) {
1648
1726
  for (let i = 0; i < idsInView.length; i++) {
1649
1727
  const id = idsInView[i];
@@ -1660,7 +1738,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1660
1738
  prevPosition = positions.get(targetId);
1661
1739
  }
1662
1740
  return () => {
1663
- let positionDiff;
1741
+ let positionDiff = 0;
1664
1742
  if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1665
1743
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1666
1744
  const { id, position } = idsInViewWithPositions[i];
@@ -1686,16 +1764,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1686
1764
  positionDiff = diff;
1687
1765
  }
1688
1766
  }
1689
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1690
- requestAdjust(ctx, state, positionDiff);
1767
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1768
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1769
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1770
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1771
+ const diff = newSize - prevSize;
1772
+ if (diff !== 0) {
1773
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1774
+ scrollingTo.itemSize = newSize;
1775
+ }
1776
+ }
1777
+ }
1778
+ if (Math.abs(positionDiff) > 0.1) {
1779
+ requestAdjust(ctx, positionDiff);
1691
1780
  }
1692
1781
  };
1693
1782
  }
1694
1783
  }
1695
1784
 
1696
1785
  // src/core/prepareColumnStartState.ts
1697
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1786
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1698
1787
  var _a3;
1788
+ const state = ctx.state;
1699
1789
  const numColumns = peek$(ctx, "numColumns");
1700
1790
  let rowStartIndex = startIndex;
1701
1791
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1710,7 +1800,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1710
1800
  const prevId = state.idCache[prevIndex];
1711
1801
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1712
1802
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1713
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1803
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1714
1804
  currentRowTop = prevPosition + prevRowHeight;
1715
1805
  }
1716
1806
  return {
@@ -1733,7 +1823,8 @@ function findRowStartIndex(state, numColumns, index) {
1733
1823
  }
1734
1824
  return rowStart;
1735
1825
  }
1736
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1826
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1827
+ const state = ctx.state;
1737
1828
  if (endIndex < startIndex) {
1738
1829
  return 0;
1739
1830
  }
@@ -1747,7 +1838,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1747
1838
  continue;
1748
1839
  }
1749
1840
  const id = state.idCache[i];
1750
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1841
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1751
1842
  if (size > maxSize) {
1752
1843
  maxSize = size;
1753
1844
  }
@@ -1756,22 +1847,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1756
1847
  }
1757
1848
 
1758
1849
  // src/core/updateTotalSize.ts
1759
- function updateTotalSize(ctx, state) {
1850
+ function updateTotalSize(ctx) {
1851
+ const state = ctx.state;
1760
1852
  const {
1761
1853
  positions,
1762
1854
  props: { data }
1763
1855
  } = state;
1764
1856
  if (data.length === 0) {
1765
- addTotalSize(ctx, state, null, 0);
1857
+ addTotalSize(ctx, null, 0);
1766
1858
  } else {
1767
1859
  const lastId = getId(state, data.length - 1);
1768
1860
  if (lastId !== void 0) {
1769
1861
  const lastPosition = positions.get(lastId);
1770
1862
  if (lastPosition !== void 0) {
1771
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1863
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1772
1864
  if (lastSize !== void 0) {
1773
1865
  const totalSize = lastPosition + lastSize;
1774
- addTotalSize(ctx, state, null, totalSize);
1866
+ addTotalSize(ctx, null, totalSize);
1775
1867
  }
1776
1868
  }
1777
1869
  }
@@ -1817,7 +1909,8 @@ var getScrollVelocity = (state) => {
1817
1909
  };
1818
1910
 
1819
1911
  // src/utils/updateSnapToOffsets.ts
1820
- function updateSnapToOffsets(ctx, state) {
1912
+ function updateSnapToOffsets(ctx) {
1913
+ const state = ctx.state;
1821
1914
  const {
1822
1915
  positions,
1823
1916
  props: { snapToIndices }
@@ -1832,30 +1925,30 @@ function updateSnapToOffsets(ctx, state) {
1832
1925
  }
1833
1926
 
1834
1927
  // src/core/updateItemPositions.ts
1835
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1928
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1836
1929
  doMVCP: false,
1837
1930
  forceFullUpdate: false,
1838
1931
  scrollBottomBuffered: -1,
1839
1932
  startIndex: 0
1840
1933
  }) {
1841
1934
  var _a3, _b, _c, _d, _e;
1935
+ const state = ctx.state;
1842
1936
  const {
1843
1937
  columns,
1844
1938
  indexByKey,
1845
1939
  positions,
1846
1940
  idCache,
1847
1941
  sizesKnown,
1848
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1942
+ props: { data, getEstimatedItemSize, snapToIndices },
1943
+ scrollingTo
1849
1944
  } = state;
1850
- const data = state.props.data;
1851
1945
  const dataLength = data.length;
1852
1946
  const numColumns = peek$(ctx, "numColumns");
1853
- const scrollingTo = peek$(ctx, "scrollingTo");
1854
1947
  const hasColumns = numColumns > 1;
1855
1948
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1856
1949
  const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1857
1950
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1858
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1951
+ const useAverageSize = !getEstimatedItemSize;
1859
1952
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1860
1953
  let currentRowTop = 0;
1861
1954
  let column = 1;
@@ -1864,7 +1957,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1864
1957
  if (hasColumns) {
1865
1958
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1866
1959
  ctx,
1867
- state,
1868
1960
  startIndex,
1869
1961
  useAverageSize
1870
1962
  );
@@ -1874,7 +1966,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1874
1966
  const prevIndex = startIndex - 1;
1875
1967
  const prevId = getId(state, prevIndex);
1876
1968
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1877
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1969
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1878
1970
  currentRowTop = prevPosition + prevSize;
1879
1971
  }
1880
1972
  }
@@ -1891,7 +1983,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1891
1983
  breakAt = i + itemsPerRow + 10;
1892
1984
  }
1893
1985
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1894
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1986
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1895
1987
  if (IS_DEV && needsIndexByKey) {
1896
1988
  if (indexByKeyForChecking.has(id)) {
1897
1989
  console.error(
@@ -1900,7 +1992,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1900
1992
  }
1901
1993
  indexByKeyForChecking.set(id, i);
1902
1994
  }
1903
- positions.set(id, currentRowTop);
1995
+ if (currentRowTop !== positions.get(id)) {
1996
+ positions.set(id, currentRowTop);
1997
+ notifyPosition$(ctx, id, currentRowTop);
1998
+ }
1904
1999
  if (needsIndexByKey) {
1905
2000
  indexByKey.set(id, i);
1906
2001
  }
@@ -1920,10 +2015,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1920
2015
  }
1921
2016
  }
1922
2017
  if (!didBreakEarly) {
1923
- updateTotalSize(ctx, state);
2018
+ updateTotalSize(ctx);
1924
2019
  }
1925
2020
  if (snapToIndices) {
1926
- updateSnapToOffsets(ctx, state);
2021
+ updateSnapToOffsets(ctx);
1927
2022
  }
1928
2023
  }
1929
2024
 
@@ -2001,7 +2096,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
2001
2096
  if (previousViewableItems) {
2002
2097
  for (const viewToken of previousViewableItems) {
2003
2098
  const containerId = findContainerId(ctx, viewToken.key);
2004
- if (!isViewable(
2099
+ if (!checkIsViewable(
2005
2100
  state,
2006
2101
  ctx,
2007
2102
  viewabilityConfig,
@@ -2022,7 +2117,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
2022
2117
  if (item) {
2023
2118
  const key = getId(state, i);
2024
2119
  const containerId = findContainerId(ctx, key);
2025
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2120
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2026
2121
  const viewToken = {
2027
2122
  containerId,
2028
2123
  index: i,
@@ -2082,11 +2177,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2082
2177
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
2083
2178
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
2084
2179
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
2085
- const isViewable2 = percent >= viewablePercentThreshold;
2180
+ const isViewable = percent >= viewablePercentThreshold;
2086
2181
  const value = {
2087
2182
  containerId,
2088
2183
  index,
2089
- isViewable: isViewable2,
2184
+ isViewable,
2090
2185
  item,
2091
2186
  key,
2092
2187
  percentOfScroller,
@@ -2105,8 +2200,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2105
2200
  }
2106
2201
  return value;
2107
2202
  }
2108
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2109
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2203
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2204
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2205
+ if (!value || value.key !== key) {
2206
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2207
+ }
2110
2208
  return value.isViewable;
2111
2209
  }
2112
2210
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -2134,8 +2232,9 @@ function checkAllSizesKnown(state) {
2134
2232
  }
2135
2233
 
2136
2234
  // src/utils/findAvailableContainers.ts
2137
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2235
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2138
2236
  const numContainers = peek$(ctx, "numContainers");
2237
+ const state = ctx.state;
2139
2238
  const { stickyContainerPool, containerItemTypes } = state;
2140
2239
  const result = [];
2141
2240
  const availableContainers = [];
@@ -2179,14 +2278,14 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
2179
2278
  continue;
2180
2279
  }
2181
2280
  const key = peek$(ctx, `containerItemKey${u}`);
2182
- let isOk = key === void 0;
2183
- if (!isOk && pendingRemovalSet.has(u)) {
2184
- pendingRemovalSet.delete(u);
2185
- pendingRemovalChanged = true;
2186
- const requiredType = neededTypes[typeIndex];
2187
- isOk = canReuseContainer(u, requiredType);
2188
- }
2189
- if (isOk) {
2281
+ const requiredType = neededTypes[typeIndex];
2282
+ const isPending = key !== void 0 && pendingRemovalSet.has(u);
2283
+ const canUse = key === void 0 || isPending && canReuseContainer(u, requiredType);
2284
+ if (canUse) {
2285
+ if (isPending) {
2286
+ pendingRemovalSet.delete(u);
2287
+ pendingRemovalChanged = true;
2288
+ }
2190
2289
  result.push(u);
2191
2290
  if (requiredItemTypes) {
2192
2291
  typeIndex++;
@@ -2255,21 +2354,26 @@ function comparatorByDistance(a, b) {
2255
2354
  }
2256
2355
 
2257
2356
  // src/core/scrollToIndex.ts
2258
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2259
- if (index >= state.props.data.length) {
2260
- index = state.props.data.length - 1;
2357
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2358
+ const state = ctx.state;
2359
+ const { data } = state.props;
2360
+ if (index >= data.length) {
2361
+ index = data.length - 1;
2261
2362
  } else if (index < 0) {
2262
2363
  index = 0;
2263
2364
  }
2264
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2265
- const isLast = index === state.props.data.length - 1;
2365
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2366
+ const isLast = index === data.length - 1;
2266
2367
  if (isLast && viewPosition === void 0) {
2267
2368
  viewPosition = 1;
2268
2369
  }
2269
2370
  state.scrollForNextCalculateItemsInView = void 0;
2270
- scrollTo(ctx, state, {
2371
+ const targetId = getId(state, index);
2372
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2373
+ scrollTo(ctx, {
2271
2374
  animated,
2272
2375
  index,
2376
+ itemSize,
2273
2377
  offset: firstIndexOffset,
2274
2378
  viewOffset,
2275
2379
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2277,16 +2381,17 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2277
2381
  }
2278
2382
 
2279
2383
  // src/utils/setDidLayout.ts
2280
- function setDidLayout(ctx, state) {
2384
+ function setDidLayout(ctx) {
2385
+ const state = ctx.state;
2281
2386
  const {
2282
2387
  loadStartTime,
2283
2388
  initialScroll,
2284
2389
  props: { onLoad }
2285
2390
  } = state;
2286
2391
  state.queuedInitialLayout = true;
2287
- checkAtBottom(ctx, state);
2392
+ checkAtBottom(ctx);
2288
2393
  const setIt = () => {
2289
- set$(ctx, "containersDidLayout", true);
2394
+ setInitialRenderState(ctx, { didLayout: true });
2290
2395
  if (onLoad) {
2291
2396
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2292
2397
  }
@@ -2311,15 +2416,17 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2311
2416
  }
2312
2417
  return -1;
2313
2418
  }
2314
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2419
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2420
+ const state = ctx.state;
2315
2421
  return new Set(
2316
2422
  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))
2317
2423
  );
2318
2424
  }
2319
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2425
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2320
2426
  var _a3;
2321
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2322
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2427
+ const state = ctx.state;
2428
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2429
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2323
2430
  for (let offset = 0; offset <= 1; offset++) {
2324
2431
  const idx = currentStickyIdx - offset;
2325
2432
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -2330,8 +2437,9 @@ function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, cu
2330
2437
  }
2331
2438
  }
2332
2439
  }
2333
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2440
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2334
2441
  var _a3, _b, _c;
2442
+ const state = ctx.state;
2335
2443
  for (const containerIndex of state.stickyContainerPool) {
2336
2444
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2337
2445
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
@@ -2355,7 +2463,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2355
2463
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2356
2464
  if (currentId) {
2357
2465
  const currentPos = state.positions.get(currentId);
2358
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2466
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2359
2467
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2360
2468
  }
2361
2469
  }
@@ -2364,7 +2472,8 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2364
2472
  }
2365
2473
  }
2366
2474
  }
2367
- function calculateItemsInView(ctx, state, params = {}) {
2475
+ function calculateItemsInView(ctx, params = {}) {
2476
+ const state = ctx.state;
2368
2477
  unstable_batchedUpdates(() => {
2369
2478
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2370
2479
  const {
@@ -2388,9 +2497,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2388
2497
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2389
2498
  const prevNumContainers = peek$(ctx, "numContainers");
2390
2499
  if (!data || scrollLength === 0 || !prevNumContainers) {
2391
- if (state.initialAnchor) {
2392
- ensureInitialAnchor(ctx, state);
2393
- }
2394
2500
  return;
2395
2501
  }
2396
2502
  const totalSize = getContentSize(ctx);
@@ -2404,15 +2510,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2404
2510
  if (!queuedInitialLayout && initialScroll) {
2405
2511
  const updatedOffset = calculateOffsetWithOffsetPosition(
2406
2512
  ctx,
2407
- state,
2408
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2513
+ calculateOffsetForIndex(ctx, initialScroll.index),
2409
2514
  initialScroll
2410
2515
  );
2411
2516
  scrollState = updatedOffset;
2412
2517
  }
2413
2518
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2414
2519
  const scrollAdjustPad = scrollAdjustPending - topPad;
2415
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2520
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2416
2521
  if (scroll + scrollLength > totalSize) {
2417
2522
  scroll = Math.max(0, totalSize - scrollLength);
2418
2523
  }
@@ -2420,11 +2525,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2420
2525
  set$(ctx, "debugRawScroll", scrollState);
2421
2526
  set$(ctx, "debugComputedScroll", scroll);
2422
2527
  }
2423
- const previousStickyIndex = state.activeStickyIndex;
2528
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2424
2529
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2425
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2426
- state.activeStickyIndex = nextActiveStickyIndex;
2427
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2530
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2531
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2532
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2533
+ }
2428
2534
  let scrollBufferTop = scrollBuffer;
2429
2535
  let scrollBufferBottom = scrollBuffer;
2430
2536
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2437,23 +2543,20 @@ function calculateItemsInView(ctx, state, params = {}) {
2437
2543
  const scrollTopBuffered = scroll - scrollBufferTop;
2438
2544
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2439
2545
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2440
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2546
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2441
2547
  const { top, bottom } = scrollForNextCalculateItemsInView;
2442
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2443
- if (state.initialAnchor) {
2444
- ensureInitialAnchor(ctx, state);
2445
- }
2548
+ if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2446
2549
  return;
2447
2550
  }
2448
2551
  }
2449
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2552
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2450
2553
  if (dataChanged) {
2451
2554
  indexByKey.clear();
2452
2555
  idCache.length = 0;
2453
2556
  positions.clear();
2454
2557
  }
2455
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2456
- updateItemPositions(ctx, state, dataChanged, {
2558
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2559
+ updateItemPositions(ctx, dataChanged, {
2457
2560
  doMVCP,
2458
2561
  forceFullUpdate: !!forceFullItemPositions,
2459
2562
  scrollBottomBuffered,
@@ -2472,9 +2575,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2472
2575
  for (let i = loopStart; i >= 0; i--) {
2473
2576
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2474
2577
  const top = positions.get(id);
2475
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2578
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2476
2579
  const bottom = top + size;
2477
- if (bottom > scroll - scrollBuffer) {
2580
+ if (bottom > scroll - scrollBufferTop) {
2478
2581
  loopStart = i;
2479
2582
  } else {
2480
2583
  break;
@@ -2499,7 +2602,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2499
2602
  const dataLength = data.length;
2500
2603
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2501
2604
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2502
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2605
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2503
2606
  const top = positions.get(id);
2504
2607
  if (!foundEnd) {
2505
2608
  if (startNoBuffer === null && top + size > scroll) {
@@ -2511,7 +2614,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2511
2614
  if (startBuffered === null && top + size > scrollTopBuffered) {
2512
2615
  startBuffered = i;
2513
2616
  startBufferedId = id;
2514
- nextTop = top;
2617
+ if (scrollTopBuffered < 0) {
2618
+ nextTop = null;
2619
+ } else {
2620
+ nextTop = top;
2621
+ }
2515
2622
  }
2516
2623
  if (startNoBuffer !== null) {
2517
2624
  if (top <= scrollBottom) {
@@ -2519,7 +2626,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2519
2626
  }
2520
2627
  if (top <= scrollBottomBuffered) {
2521
2628
  endBuffered = i;
2522
- nextBottom = top + size;
2629
+ if (scrollBottomBuffered > totalSize) {
2630
+ nextBottom = null;
2631
+ } else {
2632
+ nextBottom = top + size;
2633
+ }
2523
2634
  } else {
2524
2635
  foundEnd = true;
2525
2636
  }
@@ -2546,7 +2657,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2546
2657
  top: nextTop
2547
2658
  } : void 0;
2548
2659
  }
2549
- const numContainers = peek$(ctx, "numContainers");
2660
+ let numContainers = prevNumContainers;
2550
2661
  const pendingRemoval = [];
2551
2662
  if (dataChanged) {
2552
2663
  for (let i = 0; i < numContainers; i++) {
@@ -2557,7 +2668,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2557
2668
  }
2558
2669
  }
2559
2670
  if (startBuffered !== null && endBuffered !== null) {
2560
- let numContainers2 = prevNumContainers;
2561
2671
  const needNewContainers = [];
2562
2672
  for (let i = startBuffered; i <= endBuffered; i++) {
2563
2673
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
@@ -2568,7 +2678,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2568
2678
  if (stickyIndicesArr.length > 0) {
2569
2679
  handleStickyActivation(
2570
2680
  ctx,
2571
- state,
2572
2681
  stickyIndicesSet,
2573
2682
  stickyIndicesArr,
2574
2683
  currentStickyIdx,
@@ -2576,9 +2685,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2576
2685
  startBuffered,
2577
2686
  endBuffered
2578
2687
  );
2579
- } else {
2580
- state.activeStickyIndex = void 0;
2581
- set$(ctx, "activeStickyIndex", void 0);
2688
+ } else if (previousStickyIndex !== -1) {
2689
+ set$(ctx, "activeStickyIndex", -1);
2582
2690
  }
2583
2691
  if (needNewContainers.length > 0) {
2584
2692
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2587,7 +2695,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2587
2695
  }) : void 0;
2588
2696
  const availableContainers = findAvailableContainers(
2589
2697
  ctx,
2590
- state,
2591
2698
  needNewContainers.length,
2592
2699
  startBuffered,
2593
2700
  endBuffered,
@@ -2609,29 +2716,30 @@ function calculateItemsInView(ctx, state, params = {}) {
2609
2716
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2610
2717
  }
2611
2718
  containerItemKeys.add(id);
2719
+ const containerSticky = `containerSticky${containerIndex}`;
2612
2720
  if (stickyIndicesSet.has(i)) {
2613
- set$(ctx, `containerSticky${containerIndex}`, true);
2721
+ set$(ctx, containerSticky, true);
2614
2722
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2615
2723
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2616
2724
  state.stickyContainerPool.add(containerIndex);
2617
- } else {
2618
- set$(ctx, `containerSticky${containerIndex}`, false);
2725
+ } else if (peek$(ctx, containerSticky)) {
2726
+ set$(ctx, containerSticky, false);
2619
2727
  state.stickyContainerPool.delete(containerIndex);
2620
2728
  }
2621
- if (containerIndex >= numContainers2) {
2622
- numContainers2 = containerIndex + 1;
2729
+ if (containerIndex >= numContainers) {
2730
+ numContainers = containerIndex + 1;
2623
2731
  }
2624
2732
  }
2625
- if (numContainers2 !== prevNumContainers) {
2626
- set$(ctx, "numContainers", numContainers2);
2627
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2628
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2733
+ if (numContainers !== prevNumContainers) {
2734
+ set$(ctx, "numContainers", numContainers);
2735
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2736
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2629
2737
  }
2630
2738
  }
2631
2739
  }
2632
2740
  }
2633
2741
  if (stickyIndicesArr.length > 0) {
2634
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2742
+ handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2635
2743
  }
2636
2744
  let didChangePositions = false;
2637
2745
  for (let i = 0; i < numContainers; i++) {
@@ -2683,7 +2791,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2683
2791
  }
2684
2792
  if (!queuedInitialLayout && endBuffered !== null) {
2685
2793
  if (checkAllSizesKnown(state)) {
2686
- setDidLayout(ctx, state);
2794
+ setDidLayout(ctx);
2687
2795
  }
2688
2796
  }
2689
2797
  if (viewabilityConfigCallbackPairs) {
@@ -2696,9 +2804,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2696
2804
  }
2697
2805
  }
2698
2806
  });
2699
- if (state.initialAnchor) {
2700
- ensureInitialAnchor(ctx, state);
2701
- }
2702
2807
  }
2703
2808
 
2704
2809
  // src/core/checkActualChange.ts
@@ -2721,20 +2826,69 @@ function checkActualChange(state, dataProp, previousData) {
2721
2826
  return false;
2722
2827
  }
2723
2828
 
2829
+ // src/core/checkFinishedScroll.ts
2830
+ function checkFinishedScroll(ctx) {
2831
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2832
+ }
2833
+ function checkFinishedScrollFrame(ctx) {
2834
+ const scrollingTo = ctx.state.scrollingTo;
2835
+ if (scrollingTo) {
2836
+ const { state } = ctx;
2837
+ state.animFrameCheckFinishedScroll = void 0;
2838
+ const scroll = state.scroll;
2839
+ const adjust = state.scrollAdjustHandler.getAdjust();
2840
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
2841
+ const maxOffset = clampScrollOffset(ctx, scroll);
2842
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
2843
+ const diff2 = Math.abs(diff1 - adjust);
2844
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
2845
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
2846
+ finishScrollTo(ctx);
2847
+ }
2848
+ }
2849
+ }
2850
+ function checkFinishedScrollFallback(ctx) {
2851
+ const state = ctx.state;
2852
+ const scrollingTo = state.scrollingTo;
2853
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
2854
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
2855
+ () => {
2856
+ let numChecks = 0;
2857
+ const checkHasScrolled = () => {
2858
+ state.timeoutCheckFinishedScrollFallback = void 0;
2859
+ const isStillScrollingTo = state.scrollingTo;
2860
+ if (isStillScrollingTo) {
2861
+ numChecks++;
2862
+ if (state.hasScrolled || numChecks > 5) {
2863
+ finishScrollTo(ctx);
2864
+ } else {
2865
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
2866
+ }
2867
+ }
2868
+ };
2869
+ checkHasScrolled();
2870
+ },
2871
+ slowTimeout ? 500 : 100
2872
+ );
2873
+ }
2874
+
2724
2875
  // src/core/doMaintainScrollAtEnd.ts
2725
- function doMaintainScrollAtEnd(ctx, state, animated) {
2876
+ function doMaintainScrollAtEnd(ctx, animated) {
2877
+ const state = ctx.state;
2726
2878
  const {
2879
+ didContainersLayout,
2880
+ isAtEnd,
2727
2881
  refScroller,
2728
2882
  props: { maintainScrollAtEnd }
2729
2883
  } = state;
2730
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2884
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2731
2885
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2732
2886
  if (paddingTop > 0) {
2733
2887
  state.scroll = 0;
2734
2888
  }
2735
2889
  requestAnimationFrame(() => {
2736
2890
  var _a3;
2737
- if (state == null ? void 0 : state.isAtEnd) {
2891
+ if (state.isAtEnd) {
2738
2892
  state.maintainingScrollAtEnd = true;
2739
2893
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2740
2894
  animated
@@ -2805,28 +2959,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2805
2959
  }
2806
2960
 
2807
2961
  // src/core/checkResetContainers.ts
2808
- function checkResetContainers(ctx, state, dataProp) {
2962
+ function checkResetContainers(ctx, dataProp) {
2963
+ const state = ctx.state;
2809
2964
  const { previousData } = state;
2810
2965
  if (previousData) {
2811
2966
  updateAveragesOnDataChange(state, previousData, dataProp);
2812
2967
  }
2813
2968
  const { maintainScrollAtEnd } = state.props;
2814
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2969
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2815
2970
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2816
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2971
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2817
2972
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2818
2973
  state.isEndReached = false;
2819
2974
  }
2820
2975
  if (!didMaintainScrollAtEnd) {
2821
2976
  checkAtTop(state);
2822
- checkAtBottom(ctx, state);
2977
+ checkAtBottom(ctx);
2823
2978
  }
2824
2979
  delete state.previousData;
2825
2980
  }
2826
2981
 
2827
2982
  // src/core/doInitialAllocateContainers.ts
2828
- function doInitialAllocateContainers(ctx, state) {
2983
+ function doInitialAllocateContainers(ctx) {
2829
2984
  var _a3, _b, _c;
2985
+ const state = ctx.state;
2830
2986
  const {
2831
2987
  scrollLength,
2832
2988
  props: {
@@ -2864,10 +3020,10 @@ function doInitialAllocateContainers(ctx, state) {
2864
3020
  if (state.lastLayout) {
2865
3021
  if (state.initialScroll) {
2866
3022
  requestAnimationFrame(() => {
2867
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
3023
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2868
3024
  });
2869
3025
  } else {
2870
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
3026
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2871
3027
  }
2872
3028
  }
2873
3029
  return true;
@@ -2875,7 +3031,8 @@ function doInitialAllocateContainers(ctx, state) {
2875
3031
  }
2876
3032
 
2877
3033
  // src/core/handleLayout.ts
2878
- function handleLayout(ctx, state, layout, setCanRender) {
3034
+ function handleLayout(ctx, layout, setCanRender) {
3035
+ const state = ctx.state;
2879
3036
  const { maintainScrollAtEnd } = state.props;
2880
3037
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2881
3038
  const previousLength = state.scrollLength;
@@ -2891,19 +3048,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2891
3048
  state.lastBatchingAction = Date.now();
2892
3049
  state.scrollForNextCalculateItemsInView = void 0;
2893
3050
  if (scrollLength > 0) {
2894
- doInitialAllocateContainers(ctx, state);
3051
+ doInitialAllocateContainers(ctx);
2895
3052
  }
2896
3053
  if (needsCalculate) {
2897
- calculateItemsInView(ctx, state, { doMVCP: true });
3054
+ calculateItemsInView(ctx, { doMVCP: true });
2898
3055
  }
2899
3056
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2900
3057
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2901
3058
  }
2902
3059
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2903
- doMaintainScrollAtEnd(ctx, state, false);
3060
+ doMaintainScrollAtEnd(ctx, false);
2904
3061
  }
2905
- updateAlignItemsPaddingTop(ctx, state);
2906
- checkAtBottom(ctx, state);
3062
+ updateAlignItemsPaddingTop(ctx);
3063
+ checkAtBottom(ctx);
2907
3064
  checkAtTop(state);
2908
3065
  if (state) {
2909
3066
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2919,8 +3076,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2919
3076
  }
2920
3077
 
2921
3078
  // src/core/onScroll.ts
2922
- function onScroll(ctx, state, event) {
3079
+ function onScroll(ctx, event) {
2923
3080
  var _a3, _b, _c;
3081
+ const state = ctx.state;
2924
3082
  const {
2925
3083
  scrollProcessingEnabled,
2926
3084
  props: { onScroll: onScrollProp }
@@ -2931,9 +3089,23 @@ function onScroll(ctx, state, event) {
2931
3089
  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) {
2932
3090
  return;
2933
3091
  }
2934
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3092
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2935
3093
  state.scrollPending = newScroll;
2936
- updateScroll(ctx, state, newScroll);
3094
+ if (state.scrollingTo) {
3095
+ const maxOffset = clampScrollOffset(ctx, newScroll);
3096
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3097
+ newScroll = maxOffset;
3098
+ scrollTo(ctx, {
3099
+ forceScroll: true,
3100
+ isInitialScroll: true,
3101
+ noScrollingTo: true,
3102
+ offset: newScroll
3103
+ });
3104
+ return;
3105
+ }
3106
+ }
3107
+ updateScroll(ctx, newScroll);
3108
+ checkFinishedScroll(ctx);
2937
3109
  onScrollProp == null ? void 0 : onScrollProp(event);
2938
3110
  }
2939
3111
 
@@ -2942,51 +3114,47 @@ var ScrollAdjustHandler = class {
2942
3114
  constructor(ctx) {
2943
3115
  this.appliedAdjust = 0;
2944
3116
  this.pendingAdjust = 0;
2945
- this.mounted = false;
2946
- this.context = ctx;
2947
- {
2948
- const commitPendingAdjust = () => {
2949
- const state = this.context.internalState;
2950
- const pending = this.pendingAdjust;
2951
- if (pending !== 0) {
2952
- this.pendingAdjust = 0;
2953
- this.appliedAdjust += pending;
2954
- state.scroll += pending;
2955
- state.scrollForNextCalculateItemsInView = void 0;
2956
- set$(this.context, "scrollAdjustPending", 0);
2957
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2958
- calculateItemsInView(this.context, this.context.internalState);
2959
- }
2960
- };
2961
- listen$(this.context, "scrollingTo", (value) => {
2962
- if (value === void 0) {
2963
- commitPendingAdjust();
2964
- }
2965
- });
2966
- }
3117
+ this.ctx = ctx;
2967
3118
  }
2968
3119
  requestAdjust(add) {
2969
- const scrollingTo = peek$(this.context, "scrollingTo");
3120
+ const scrollingTo = this.ctx.state.scrollingTo;
2970
3121
  if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2971
3122
  this.pendingAdjust += add;
2972
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
3123
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2973
3124
  } else {
2974
3125
  this.appliedAdjust += add;
2975
- set$(this.context, "scrollAdjust", this.appliedAdjust);
3126
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3127
+ }
3128
+ if (this.ctx.state.scrollingTo) {
3129
+ checkFinishedScroll(this.ctx);
2976
3130
  }
2977
- }
2978
- setMounted() {
2979
- this.mounted = true;
2980
3131
  }
2981
3132
  getAdjust() {
2982
3133
  return this.appliedAdjust;
2983
3134
  }
3135
+ commitPendingAdjust() {
3136
+ {
3137
+ const state = this.ctx.state;
3138
+ const pending = this.pendingAdjust;
3139
+ if (pending !== 0) {
3140
+ this.pendingAdjust = 0;
3141
+ this.appliedAdjust += pending;
3142
+ state.scroll += pending;
3143
+ state.scrollForNextCalculateItemsInView = void 0;
3144
+ set$(this.ctx, "scrollAdjustPending", 0);
3145
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3146
+ calculateItemsInView(this.ctx);
3147
+ }
3148
+ }
3149
+ }
2984
3150
  };
2985
3151
 
2986
3152
  // src/core/updateItemSize.ts
2987
- function updateItemSize(ctx, state, itemKey, sizeObj) {
3153
+ function updateItemSize(ctx, itemKey, sizeObj) {
2988
3154
  var _a3;
3155
+ const state = ctx.state;
2989
3156
  const {
3157
+ didContainersLayout,
2990
3158
  sizesKnown,
2991
3159
  props: {
2992
3160
  getFixedItemSize,
@@ -3014,13 +3182,12 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
3014
3182
  return;
3015
3183
  }
3016
3184
  }
3017
- const containersDidLayout = peek$(ctx, "containersDidLayout");
3018
- let needsRecalculate = !containersDidLayout;
3185
+ let needsRecalculate = !didContainersLayout;
3019
3186
  let shouldMaintainScrollAtEnd = false;
3020
3187
  let minIndexSizeChanged;
3021
3188
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
3022
3189
  const prevSizeKnown = state.sizesKnown.get(itemKey);
3023
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3190
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
3024
3191
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
3025
3192
  if (diff !== 0) {
3026
3193
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
@@ -3069,22 +3236,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
3069
3236
  if (!cur || maxOtherAxisSize > cur) {
3070
3237
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
3071
3238
  }
3072
- if (containersDidLayout || checkAllSizesKnown(state)) {
3239
+ if (didContainersLayout || checkAllSizesKnown(state)) {
3073
3240
  if (needsRecalculate) {
3074
3241
  state.scrollForNextCalculateItemsInView = void 0;
3075
- calculateItemsInView(ctx, state, { doMVCP: true });
3242
+ calculateItemsInView(ctx, { doMVCP: true });
3076
3243
  }
3077
3244
  if (shouldMaintainScrollAtEnd) {
3078
3245
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
3079
- doMaintainScrollAtEnd(ctx, state, false);
3246
+ doMaintainScrollAtEnd(ctx, false);
3080
3247
  }
3081
3248
  }
3082
3249
  }
3083
3250
  }
3084
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3251
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
3085
3252
  var _a3;
3253
+ const state = ctx.state;
3086
3254
  const {
3087
- sizes,
3088
3255
  indexByKey,
3089
3256
  sizesKnown,
3090
3257
  averageSizes,
@@ -3092,9 +3259,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3092
3259
  } = state;
3093
3260
  if (!data) return 0;
3094
3261
  const index = indexByKey.get(itemKey);
3095
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3262
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
3096
3263
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
3097
3264
  const size = Math.round(rawSize) ;
3265
+ const prevSizeKnown = sizesKnown.get(itemKey);
3098
3266
  sizesKnown.set(itemKey, size);
3099
3267
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
3100
3268
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -3102,11 +3270,15 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3102
3270
  if (!averages) {
3103
3271
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3104
3272
  }
3105
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3106
- averages.num++;
3273
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3274
+ averages.avg += (size - prevSizeKnown) / averages.num;
3275
+ } else {
3276
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3277
+ averages.num++;
3278
+ }
3107
3279
  }
3108
3280
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
3109
- setSize(ctx, state, itemKey, size);
3281
+ setSize(ctx, itemKey, size);
3110
3282
  return size - prevSize;
3111
3283
  }
3112
3284
  return 0;
@@ -3153,14 +3325,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
3153
3325
  }
3154
3326
 
3155
3327
  // src/utils/createImperativeHandle.ts
3156
- function createImperativeHandle(ctx, state) {
3328
+ function createImperativeHandle(ctx) {
3329
+ const state = ctx.state;
3157
3330
  const scrollIndexIntoView = (options) => {
3158
3331
  if (state) {
3159
3332
  const { index, ...rest } = options;
3160
3333
  const { startNoBuffer, endNoBuffer } = state;
3161
3334
  if (index < startNoBuffer || index > endNoBuffer) {
3162
3335
  const viewPosition = index < startNoBuffer ? 0 : 1;
3163
- scrollToIndex(ctx, state, {
3336
+ scrollToIndex(ctx, {
3164
3337
  ...rest,
3165
3338
  index,
3166
3339
  viewPosition
@@ -3175,7 +3348,7 @@ function createImperativeHandle(ctx, state) {
3175
3348
  getScrollableNode: () => refScroller.current.getScrollableNode(),
3176
3349
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3177
3350
  getState: () => ({
3178
- activeStickyIndex: state.activeStickyIndex,
3351
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3179
3352
  contentLength: state.totalSize,
3180
3353
  data: state.props.data,
3181
3354
  elementAtIndex: (index) => {
@@ -3186,6 +3359,8 @@ function createImperativeHandle(ctx, state) {
3186
3359
  endBuffered: state.endBuffered,
3187
3360
  isAtEnd: state.isAtEnd,
3188
3361
  isAtStart: state.isAtStart,
3362
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3363
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3189
3364
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
3190
3365
  positions: state.positions,
3191
3366
  scroll: state.scroll,
@@ -3210,23 +3385,23 @@ function createImperativeHandle(ctx, state) {
3210
3385
  if (index !== -1) {
3211
3386
  const paddingBottom = stylePaddingBottom || 0;
3212
3387
  const footerSize = peek$(ctx, "footerSize") || 0;
3213
- scrollToIndex(ctx, state, {
3388
+ scrollToIndex(ctx, {
3389
+ ...options,
3214
3390
  index,
3215
3391
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3216
- viewPosition: 1,
3217
- ...options
3392
+ viewPosition: 1
3218
3393
  });
3219
3394
  }
3220
3395
  },
3221
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3396
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
3222
3397
  scrollToItem: ({ item, ...props }) => {
3223
3398
  const data = state.props.data;
3224
3399
  const index = data.indexOf(item);
3225
3400
  if (index !== -1) {
3226
- scrollToIndex(ctx, state, { index, ...props });
3401
+ scrollToIndex(ctx, { index, ...props });
3227
3402
  }
3228
3403
  },
3229
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3404
+ scrollToOffset: (params) => scrollTo(ctx, params),
3230
3405
  setScrollProcessingEnabled: (enabled) => {
3231
3406
  state.scrollProcessingEnabled = enabled;
3232
3407
  },
@@ -3236,8 +3411,9 @@ function createImperativeHandle(ctx, state) {
3236
3411
  }
3237
3412
  };
3238
3413
  }
3239
- function getRenderedItem(ctx, state, key) {
3414
+ function getRenderedItem(ctx, key) {
3240
3415
  var _a3;
3416
+ const state = ctx.state;
3241
3417
  if (!state) {
3242
3418
  return null;
3243
3419
  }
@@ -3314,11 +3490,13 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3314
3490
  var DEFAULT_DRAW_DISTANCE = 250;
3315
3491
  var DEFAULT_ITEM_SIZE = 100;
3316
3492
  var LegendList = typedMemo(
3493
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3317
3494
  typedForwardRef(function LegendList2(props, forwardedRef) {
3318
3495
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3319
3496
  const isChildrenMode = children !== void 0 && dataProp === void 0;
3320
3497
  const processedProps = isChildrenMode ? {
3321
3498
  ...restProps,
3499
+ childrenMode: true,
3322
3500
  data: (isArray(children) ? children : React3.Children.toArray(children)).flat(1),
3323
3501
  renderItem: ({ item }) => item
3324
3502
  } : {
@@ -3335,10 +3513,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3335
3513
  alignItemsAtEnd = false,
3336
3514
  columnWrapperStyle,
3337
3515
  contentContainerStyle: contentContainerStyleProp,
3516
+ contentInset,
3338
3517
  data: dataProp = [],
3339
3518
  dataVersion,
3340
3519
  drawDistance = 250,
3341
- enableAverages = true,
3342
3520
  estimatedItemSize: estimatedItemSizeProp,
3343
3521
  estimatedListSize,
3344
3522
  extraData,
@@ -3380,6 +3558,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3380
3558
  snapToIndices,
3381
3559
  stickyHeaderIndices: stickyHeaderIndicesProp,
3382
3560
  stickyIndices: stickyIndicesDeprecated,
3561
+ // TODOV3: Remove from v3 release
3383
3562
  style: styleProp,
3384
3563
  suggestEstimatedItemSize,
3385
3564
  viewabilityConfig,
@@ -3387,6 +3566,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3387
3566
  waitForInitialLayout = true,
3388
3567
  ...rest
3389
3568
  } = props;
3569
+ const animatedPropsInternal = props.animatedPropsInternal;
3570
+ const { childrenMode } = rest;
3390
3571
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3391
3572
  const style = { ...StyleSheet.flatten(styleProp) };
3392
3573
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
@@ -3410,10 +3591,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3410
3591
  }
3411
3592
  const refState = useRef();
3412
3593
  if (!refState.current) {
3413
- if (!ctx.internalState) {
3594
+ if (!ctx.state) {
3414
3595
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
3415
- ctx.internalState = {
3416
- activeStickyIndex: void 0,
3596
+ ctx.state = {
3597
+ activeStickyIndex: -1,
3417
3598
  averageSizes: {},
3418
3599
  columns: /* @__PURE__ */ new Map(),
3419
3600
  containerItemKeys: /* @__PURE__ */ new Set(),
@@ -3439,9 +3620,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3439
3620
  initialScroll: initialScrollProp,
3440
3621
  isAtEnd: false,
3441
3622
  isAtStart: false,
3442
- isEndReached: false,
3623
+ isEndReached: null,
3443
3624
  isFirst: true,
3444
- isStartReached: false,
3625
+ isStartReached: null,
3445
3626
  lastBatchingAction: Date.now(),
3446
3627
  lastLayout: void 0,
3447
3628
  loadStartTime: Date.now(),
@@ -3473,12 +3654,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3473
3654
  totalSize: 0,
3474
3655
  viewabilityConfigCallbackPairs: void 0
3475
3656
  };
3476
- const internalState = ctx.internalState;
3477
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3657
+ const internalState = ctx.state;
3658
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3478
3659
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3479
3660
  set$(ctx, "extraData", extraData);
3480
3661
  }
3481
- refState.current = ctx.internalState;
3662
+ refState.current = ctx.state;
3482
3663
  }
3483
3664
  const state = refState.current;
3484
3665
  const isFirstLocal = state.isFirst;
@@ -3492,9 +3673,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3492
3673
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3493
3674
  state.props = {
3494
3675
  alignItemsAtEnd,
3676
+ animatedProps: animatedPropsInternal,
3677
+ contentInset,
3495
3678
  data: dataProp,
3496
3679
  dataVersion,
3497
- enableAverages,
3498
3680
  estimatedItemSize,
3499
3681
  getEstimatedItemSize,
3500
3682
  getFixedItemSize,
@@ -3537,62 +3719,52 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3537
3719
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3538
3720
  set$(ctx, "numColumns", numColumnsProp);
3539
3721
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3540
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3722
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3541
3723
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3542
3724
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3543
3725
  if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3544
3726
  if (state.scroll < 0) {
3545
3727
  paddingDiff += state.scroll;
3546
3728
  }
3547
- requestAdjust(ctx, state, paddingDiff);
3729
+ requestAdjust(ctx, paddingDiff);
3548
3730
  }
3549
3731
  };
3550
3732
  if (isFirstLocal) {
3551
3733
  initializeStateVars();
3552
3734
  updateItemPositions(
3553
3735
  ctx,
3554
- state,
3555
3736
  /*dataChanged*/
3556
3737
  true
3557
3738
  );
3558
3739
  }
3559
3740
  const initialContentOffset = useMemo(() => {
3560
- var _a4, _b2;
3561
- const { initialScroll } = refState.current;
3562
- if (!initialScroll) {
3741
+ let value;
3742
+ const { initialScroll, initialAnchor } = refState.current;
3743
+ if (initialScroll) {
3744
+ if (initialScroll.contentOffset !== void 0) {
3745
+ value = initialScroll.contentOffset;
3746
+ } else {
3747
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3748
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3749
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3750
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3751
+ refState.current.initialScroll = updatedInitialScroll;
3752
+ state.initialScroll = updatedInitialScroll;
3753
+ value = clampedOffset;
3754
+ }
3755
+ } else {
3563
3756
  refState.current.initialAnchor = void 0;
3564
- return 0;
3565
- }
3566
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3567
- refState.current.initialAnchor = {
3568
- attempts: 0,
3569
- index: initialScroll.index,
3570
- settledTicks: 0,
3571
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3572
- viewPosition: initialScroll.viewPosition
3573
- };
3757
+ value = 0;
3574
3758
  }
3575
- if (initialScroll.contentOffset !== void 0) {
3576
- return initialScroll.contentOffset;
3577
- }
3578
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3579
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3580
- let clampedOffset = resolvedOffset;
3581
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3582
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3583
- clampedOffset = Math.min(clampedOffset, maxOffset);
3584
- }
3585
- clampedOffset = Math.max(0, clampedOffset);
3586
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3587
- refState.current.initialScroll = updatedInitialScroll;
3588
- state.initialScroll = updatedInitialScroll;
3589
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3590
- return clampedOffset;
3759
+ if (!value) {
3760
+ state.didFinishInitialScroll = true;
3761
+ }
3762
+ return value;
3591
3763
  }, [renderNum]);
3592
3764
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3593
3765
  refState.current.lastBatchingAction = Date.now();
3594
3766
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3595
- IS_DEV && warnDevOnce(
3767
+ IS_DEV && !childrenMode && warnDevOnce(
3596
3768
  "keyExtractor",
3597
3769
  "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."
3598
3770
  );
@@ -3615,12 +3787,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3615
3787
  }
3616
3788
  }, []);
3617
3789
  const doInitialScroll = useCallback(() => {
3618
- var _a4;
3619
3790
  const initialScroll = state.initialScroll;
3620
3791
  if (initialScroll) {
3621
- scrollTo(ctx, state, {
3792
+ scrollTo(ctx, {
3622
3793
  animated: false,
3623
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3794
+ index: initialScroll == null ? void 0 : initialScroll.index,
3624
3795
  isInitialScroll: true,
3625
3796
  offset: initialContentOffset,
3626
3797
  precomputedWithViewOffset: true
@@ -3629,7 +3800,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3629
3800
  }, [initialContentOffset]);
3630
3801
  const onLayoutChange = useCallback((layout) => {
3631
3802
  doInitialScroll();
3632
- handleLayout(ctx, state, layout, setCanRender);
3803
+ handleLayout(ctx, layout, setCanRender);
3633
3804
  }, []);
3634
3805
  const { onLayout } = useOnLayoutSync({
3635
3806
  onLayoutChange,
@@ -3639,7 +3810,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3639
3810
  });
3640
3811
  useLayoutEffect(() => {
3641
3812
  if (snapToIndices) {
3642
- updateSnapToOffsets(ctx, state);
3813
+ updateSnapToOffsets(ctx);
3643
3814
  }
3644
3815
  }, [snapToIndices]);
3645
3816
  useLayoutEffect(() => {
@@ -3649,9 +3820,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3649
3820
  isFirst,
3650
3821
  props: { data }
3651
3822
  } = state;
3652
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3823
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3653
3824
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3654
- checkResetContainers(ctx, state, data);
3825
+ checkResetContainers(ctx, data);
3655
3826
  }
3656
3827
  state.didColumnsChange = false;
3657
3828
  state.didDataChange = false;
@@ -3676,15 +3847,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3676
3847
  state.viewabilityConfigCallbackPairs = viewability;
3677
3848
  state.enableScrollForNextCalculateItemsInView = !viewability;
3678
3849
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3679
- useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3850
+ useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3680
3851
  {
3681
3852
  useEffect(doInitialScroll, []);
3682
3853
  }
3683
3854
  const fns = useMemo(
3684
3855
  () => ({
3685
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3686
- onScroll: (event) => onScroll(ctx, state, event),
3687
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3856
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
3857
+ onMomentumScrollEnd: (event) => {
3858
+ checkFinishedScrollFallback(ctx);
3859
+ if (onMomentumScrollEnd) {
3860
+ onMomentumScrollEnd(event);
3861
+ }
3862
+ },
3863
+ onScroll: (event) => onScroll(ctx, event),
3864
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3688
3865
  }),
3689
3866
  []
3690
3867
  );
@@ -3696,6 +3873,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3696
3873
  alignItemsAtEnd,
3697
3874
  canRender,
3698
3875
  contentContainerStyle,
3876
+ contentInset,
3699
3877
  getRenderedItem: fns.getRenderedItem,
3700
3878
  horizontal,
3701
3879
  initialContentOffset,
@@ -3704,16 +3882,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3704
3882
  maintainVisibleContentPosition,
3705
3883
  onLayout,
3706
3884
  onLayoutHeader,
3707
- onMomentumScrollEnd: (event) => {
3708
- {
3709
- requestAnimationFrame(() => {
3710
- finishScrollTo(ctx, refState.current);
3711
- });
3712
- }
3713
- if (onMomentumScrollEnd) {
3714
- onMomentumScrollEnd(event);
3715
- }
3716
- },
3885
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3717
3886
  onScroll: onScrollHandler,
3718
3887
  recycleItems,
3719
3888
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
@@ -3728,7 +3897,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3728
3897
  ),
3729
3898
  refScrollView: combinedRef,
3730
3899
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3731
- scrollEventThrottle: 16 ,
3900
+ scrollEventThrottle: 0,
3732
3901
  snapToIndices,
3733
3902
  stickyHeaderIndices,
3734
3903
  style,