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

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