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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -33,31 +33,65 @@ var View = React3.forwardRef(function View2(props, ref) {
33
33
  });
34
34
  var Text = View;
35
35
 
36
+ // src/state/getContentInsetEnd.ts
37
+ function getContentInsetEnd(state) {
38
+ var _a3;
39
+ const { props } = state;
40
+ const horizontal = props.horizontal;
41
+ let contentInset = props.contentInset;
42
+ if (!contentInset) {
43
+ const animatedInset = (_a3 = props.animatedProps) == null ? void 0 : _a3.contentInset;
44
+ if (animatedInset) {
45
+ if ("get" in animatedInset) {
46
+ contentInset = animatedInset.get();
47
+ } else {
48
+ contentInset = animatedInset;
49
+ }
50
+ }
51
+ }
52
+ return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
53
+ }
54
+
55
+ // src/state/getContentSize.ts
56
+ function getContentSize(ctx) {
57
+ var _a3;
58
+ const { values, state } = ctx;
59
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
60
+ const stylePaddingBottom = state.props.stylePaddingBottom || 0;
61
+ const headerSize = values.get("headerSize") || 0;
62
+ const footerSize = values.get("footerSize") || 0;
63
+ const contentInsetBottom = getContentInsetEnd(state);
64
+ const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
65
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
66
+ }
67
+
36
68
  // src/platform/Animated.tsx
37
69
  var createAnimatedValue = (value) => value;
38
70
 
39
71
  // src/state/state.tsx
40
72
  var ContextState = React3__namespace.createContext(null);
73
+ var contextNum = 0;
41
74
  function StateProvider({ children }) {
42
75
  const [value] = React3__namespace.useState(() => ({
43
76
  animatedScrollY: createAnimatedValue(0),
44
77
  columnWrapperStyle: void 0,
45
- internalState: void 0,
78
+ contextNum: contextNum++,
46
79
  listeners: /* @__PURE__ */ new Map(),
47
80
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
48
81
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
49
82
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
50
83
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
51
84
  mapViewabilityValues: /* @__PURE__ */ new Map(),
85
+ positionListeners: /* @__PURE__ */ new Map(),
86
+ state: void 0,
52
87
  values: /* @__PURE__ */ new Map([
53
88
  ["alignItemsPaddingTop", 0],
54
89
  ["stylePaddingTop", 0],
55
90
  ["headerSize", 0],
56
91
  ["numContainers", 0],
57
- ["activeStickyIndex", void 0],
92
+ ["activeStickyIndex", -1],
58
93
  ["totalSize", 0],
59
- ["scrollAdjustPending", 0],
60
- ["scrollingTo", void 0]
94
+ ["scrollAdjustPending", 0]
61
95
  ]),
62
96
  viewRefs: /* @__PURE__ */ new Map()
63
97
  }));
@@ -125,14 +159,24 @@ function set$(ctx, signalName, value) {
125
159
  }
126
160
  }
127
161
  }
128
- function getContentSize(ctx) {
129
- var _a3, _b;
130
- const { values } = ctx;
131
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
132
- const headerSize = values.get("headerSize") || 0;
133
- const footerSize = values.get("footerSize") || 0;
134
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
135
- return headerSize + footerSize + totalSize + stylePaddingTop;
162
+ function listenPosition$(ctx, key, cb) {
163
+ const { positionListeners } = ctx;
164
+ let setListeners = positionListeners.get(key);
165
+ if (!setListeners) {
166
+ setListeners = /* @__PURE__ */ new Set();
167
+ positionListeners.set(key, setListeners);
168
+ }
169
+ setListeners.add(cb);
170
+ return () => setListeners.delete(cb);
171
+ }
172
+ function notifyPosition$(ctx, key, value) {
173
+ const { positionListeners } = ctx;
174
+ const setListeners = positionListeners.get(key);
175
+ if (setListeners) {
176
+ for (const listener of setListeners) {
177
+ listener(value);
178
+ }
179
+ }
136
180
  }
137
181
  function useArr$(signalNames) {
138
182
  const ctx = React3__namespace.useContext(ContextState);
@@ -254,12 +298,12 @@ function findContainerId(ctx, key) {
254
298
  }
255
299
 
256
300
  // src/components/PositionView.tsx
257
- var PositionViewState = typedMemo(function PositionView({
301
+ var PositionViewState = typedMemo(function PositionViewState2({
258
302
  id,
259
303
  horizontal,
260
304
  style,
261
305
  refView,
262
- ...rest
306
+ ...props
263
307
  }) {
264
308
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
265
309
  const base = {
@@ -267,7 +311,8 @@ var PositionViewState = typedMemo(function PositionView({
267
311
  };
268
312
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
269
313
  const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
270
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: combinedStyle, ...rest });
314
+ const { animatedScrollY, stickyOffset, onLayout, ...webProps } = props;
315
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, ...webProps, style: combinedStyle });
271
316
  });
272
317
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
273
318
  id,
@@ -312,17 +357,12 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
312
357
  }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
313
358
  return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
314
359
  });
315
- var PositionView2 = PositionViewState;
360
+ var PositionView = PositionViewState;
316
361
 
317
362
  // src/constants-platform.ts
318
363
  var IsNewArchitecture = true;
319
- var symbolFirst = Symbol();
320
364
  function useInit(cb) {
321
- const refValue = React3.useRef(symbolFirst);
322
- if (refValue.current === symbolFirst) {
323
- refValue.current = cb();
324
- }
325
- return refValue.current;
365
+ React3.useState(() => cb());
326
366
  }
327
367
 
328
368
  // src/state/ContextContainer.ts
@@ -470,10 +510,9 @@ function createResizeObserver(element, callback) {
470
510
  }
471
511
  callbacks.add(callback);
472
512
  return () => {
473
- const callbacks2 = callbackMap.get(element);
474
- if (callbacks2) {
475
- callbacks2.delete(callback);
476
- if (callbacks2.size === 0) {
513
+ if (callbacks) {
514
+ callbacks.delete(callback);
515
+ if (callbacks.size === 0) {
477
516
  callbackMap.delete(element);
478
517
  observer.unobserve(element);
479
518
  }
@@ -508,10 +547,10 @@ function useOnLayoutSync({
508
547
  return createResizeObserver(element, (entry) => {
509
548
  var _a4;
510
549
  const target = entry.target instanceof HTMLElement ? entry.target : void 0;
511
- const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
512
- if (rect2.width !== prevRect.width || rect2.height !== prevRect.height) {
513
- prevRect = rect2;
514
- emit(toLayout(rect2), false);
550
+ const rectObserved = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
551
+ if (rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height) {
552
+ prevRect = rectObserved;
553
+ emit(toLayout(rectObserved), false);
515
554
  }
516
555
  });
517
556
  }, deps || []);
@@ -639,7 +678,7 @@ var Container = typedMemo(function Container2({
639
678
  },
640
679
  [itemKey, layoutRenderCount]
641
680
  );
642
- const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
681
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
643
682
  return /* @__PURE__ */ React3__namespace.createElement(
644
683
  PositionComponent,
645
684
  {
@@ -832,7 +871,8 @@ var Containers = typedMemo(function Containers2({
832
871
  return /* @__PURE__ */ React3__namespace.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
833
872
  });
834
873
  function DevNumbers() {
835
- return IS_DEV && React3__namespace.memo(function DevNumbers2() {
874
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
875
+ React3__namespace.memo(function DevNumbers2() {
836
876
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3__namespace.createElement(
837
877
  "div",
838
878
  {
@@ -880,7 +920,6 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
880
920
  }, ref) {
881
921
  const scrollRef = React3.useRef(null);
882
922
  const contentRef = React3.useRef(null);
883
- const momentumTimeout = React3.useRef(null);
884
923
  React3.useImperativeHandle(ref, () => {
885
924
  const api = {
886
925
  getBoundingClientRect: () => {
@@ -946,16 +985,6 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
946
985
  }
947
986
  };
948
987
  onScroll2(scrollEvent);
949
- if (onMomentumScrollEnd) {
950
- if (momentumTimeout.current != null) clearTimeout(momentumTimeout.current);
951
- momentumTimeout.current = setTimeout(() => {
952
- onMomentumScrollEnd({
953
- nativeEvent: {
954
- contentOffset: scrollEvent.nativeEvent.contentOffset
955
- }
956
- });
957
- }, 100);
958
- }
959
988
  },
960
989
  [onScroll2, onMomentumScrollEnd]
961
990
  );
@@ -1017,7 +1046,8 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1017
1046
  minWidth: horizontal ? "100%" : void 0,
1018
1047
  ...StyleSheet.flatten(contentContainerStyle)
1019
1048
  };
1020
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3__namespace.createElement("div", { ref: contentRef, style: contentStyle }, children));
1049
+ const { contentInset, scrollEventThrottle, ScrollComponent, ...webProps } = props;
1050
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3__namespace.createElement("div", { ref: contentRef, style: contentStyle }, children));
1021
1051
  });
1022
1052
  function Padding() {
1023
1053
  const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
@@ -1058,7 +1088,7 @@ function ScrollAdjust() {
1058
1088
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1059
1089
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1060
1090
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1061
- const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
1091
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1062
1092
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1063
1093
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1064
1094
  if (scrollDelta !== 0) {
@@ -1066,16 +1096,16 @@ function ScrollAdjust() {
1066
1096
  const prevScroll = el.scrollTop;
1067
1097
  const nextScroll = prevScroll + scrollDelta;
1068
1098
  const totalSize = el.scrollHeight;
1069
- if (scrollDelta > 0 && !ctx.internalState.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1099
+ if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1070
1100
  const child = el.firstElementChild;
1071
1101
  const prevPaddingBottom = child.style.paddingBottom;
1072
1102
  const pad = (nextScroll + el.clientHeight - totalSize) * 2;
1073
1103
  child.style.paddingBottom = `${pad}px`;
1074
1104
  void el.offsetHeight;
1075
1105
  scrollView.scrollBy(0, scrollDelta);
1076
- setTimeout(() => {
1106
+ requestAnimationFrame(() => {
1077
1107
  child.style.paddingBottom = prevPaddingBottom;
1078
- }, 100);
1108
+ });
1079
1109
  } else {
1080
1110
  scrollView.scrollBy(0, scrollDelta);
1081
1111
  }
@@ -1085,7 +1115,7 @@ function ScrollAdjust() {
1085
1115
  }
1086
1116
  lastScrollOffsetRef.current = scrollOffset;
1087
1117
  }
1088
- }, []);
1118
+ }, [ctx]);
1089
1119
  useValueListener$("scrollAdjust", callback);
1090
1120
  useValueListener$("scrollAdjustUserOffset", callback);
1091
1121
  return null;
@@ -1143,13 +1173,6 @@ var ListComponent = typedMemo(function ListComponent2({
1143
1173
  () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1144
1174
  [renderScrollComponent]
1145
1175
  ) : ListComponentScrollView;
1146
- React3__namespace.useEffect(() => {
1147
- if (canRender) {
1148
- setTimeout(() => {
1149
- scrollAdjustHandler.setMounted();
1150
- }, 0);
1151
- }
1152
- }, [canRender]);
1153
1176
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1154
1177
  return /* @__PURE__ */ React3__namespace.createElement(
1155
1178
  SnapOrScroll,
@@ -1213,10 +1236,11 @@ function getId(state, index) {
1213
1236
  }
1214
1237
 
1215
1238
  // src/core/calculateOffsetForIndex.ts
1216
- function calculateOffsetForIndex(ctx, state, index) {
1239
+ function calculateOffsetForIndex(ctx, index) {
1240
+ const state = ctx.state;
1217
1241
  let position = 0;
1218
1242
  if (index !== void 0) {
1219
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
1243
+ position = state.positions.get(getId(state, index)) || 0;
1220
1244
  const paddingTop = peek$(ctx, "stylePaddingTop");
1221
1245
  if (paddingTop) {
1222
1246
  position += paddingTop;
@@ -1230,7 +1254,8 @@ function calculateOffsetForIndex(ctx, state, index) {
1230
1254
  }
1231
1255
 
1232
1256
  // src/utils/setPaddingTop.ts
1233
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1257
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1258
+ const state = ctx.state;
1234
1259
  if (stylePaddingTop !== void 0) {
1235
1260
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1236
1261
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -1249,7 +1274,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1249
1274
  }
1250
1275
 
1251
1276
  // src/utils/updateAlignItemsPaddingTop.ts
1252
- function updateAlignItemsPaddingTop(ctx, state) {
1277
+ function updateAlignItemsPaddingTop(ctx) {
1278
+ const state = ctx.state;
1253
1279
  const {
1254
1280
  scrollLength,
1255
1281
  props: { alignItemsAtEnd, data }
@@ -1260,12 +1286,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
1260
1286
  const contentSize = getContentSize(ctx);
1261
1287
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1262
1288
  }
1263
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1289
+ setPaddingTop(ctx, { alignItemsPaddingTop });
1264
1290
  }
1265
1291
  }
1266
1292
 
1267
1293
  // src/core/addTotalSize.ts
1268
- function addTotalSize(ctx, state, key, add) {
1294
+ function addTotalSize(ctx, key, add) {
1295
+ const state = ctx.state;
1269
1296
  const { alignItemsAtEnd } = state.props;
1270
1297
  const prevTotalSize = state.totalSize;
1271
1298
  let totalSize = state.totalSize;
@@ -1284,31 +1311,34 @@ function addTotalSize(ctx, state, key, add) {
1284
1311
  state.totalSize = totalSize;
1285
1312
  set$(ctx, "totalSize", totalSize);
1286
1313
  if (alignItemsAtEnd) {
1287
- updateAlignItemsPaddingTop(ctx, state);
1314
+ updateAlignItemsPaddingTop(ctx);
1288
1315
  }
1289
1316
  }
1290
1317
  }
1291
1318
  }
1292
1319
 
1293
1320
  // src/core/setSize.ts
1294
- function setSize(ctx, state, itemKey, size) {
1321
+ function setSize(ctx, itemKey, size) {
1322
+ const state = ctx.state;
1295
1323
  const { sizes } = state;
1296
1324
  const previousSize = sizes.get(itemKey);
1297
1325
  const diff = previousSize !== void 0 ? size - previousSize : size;
1298
1326
  if (diff !== 0) {
1299
- addTotalSize(ctx, state, itemKey, diff);
1327
+ addTotalSize(ctx, itemKey, diff);
1300
1328
  }
1301
1329
  sizes.set(itemKey, size);
1302
1330
  }
1303
1331
 
1304
1332
  // src/utils/getItemSize.ts
1305
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1333
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1306
1334
  var _a3, _b;
1335
+ const state = ctx.state;
1307
1336
  const {
1308
1337
  sizesKnown,
1309
1338
  sizes,
1310
1339
  averageSizes,
1311
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1340
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1341
+ scrollingTo
1312
1342
  } = state;
1313
1343
  const sizeKnown = sizesKnown.get(key);
1314
1344
  if (sizeKnown !== void 0) {
@@ -1316,7 +1346,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1316
1346
  }
1317
1347
  let size;
1318
1348
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1319
- const scrollingTo = peek$(ctx, "scrollingTo");
1320
1349
  if (preferCachedSize) {
1321
1350
  const cachedSize = sizes.get(key);
1322
1351
  if (cachedSize !== void 0) {
@@ -1344,81 +1373,169 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1344
1373
  if (size === void 0) {
1345
1374
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1346
1375
  }
1347
- setSize(ctx, state, key, size);
1376
+ setSize(ctx, key, size);
1348
1377
  return size;
1349
1378
  }
1350
1379
 
1351
1380
  // src/core/calculateOffsetWithOffsetPosition.ts
1352
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1381
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1382
+ const state = ctx.state;
1353
1383
  const { index, viewOffset, viewPosition } = params;
1354
1384
  let offset = offsetParam;
1355
1385
  if (viewOffset) {
1356
1386
  offset -= viewOffset;
1357
1387
  }
1358
1388
  if (viewPosition !== void 0 && index !== void 0) {
1359
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1389
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1390
+ const trailingInset = getContentInsetEnd(state);
1391
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1360
1392
  }
1361
1393
  return offset;
1362
1394
  }
1363
1395
 
1396
+ // src/core/clampScrollOffset.ts
1397
+ function clampScrollOffset(ctx, offset) {
1398
+ const state = ctx.state;
1399
+ const contentSize = getContentSize(ctx);
1400
+ let clampedOffset = offset;
1401
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1402
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1403
+ clampedOffset = Math.min(offset, maxOffset);
1404
+ }
1405
+ clampedOffset = Math.max(0, clampedOffset);
1406
+ return clampedOffset;
1407
+ }
1408
+
1409
+ // src/utils/setInitialRenderState.ts
1410
+ function setInitialRenderState(ctx, {
1411
+ didLayout,
1412
+ didInitialScroll
1413
+ }) {
1414
+ const { state } = ctx;
1415
+ if (didLayout) {
1416
+ state.didContainersLayout = true;
1417
+ }
1418
+ if (didInitialScroll) {
1419
+ state.didFinishInitialScroll = true;
1420
+ }
1421
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1422
+ set$(ctx, "readyToRender", true);
1423
+ }
1424
+ }
1425
+
1364
1426
  // src/core/finishScrollTo.ts
1365
- function finishScrollTo(ctx, state) {
1427
+ function finishScrollTo(ctx) {
1366
1428
  var _a3, _b;
1367
- if (state) {
1429
+ const state = ctx.state;
1430
+ if (state == null ? void 0 : state.scrollingTo) {
1368
1431
  state.scrollHistory.length = 0;
1369
1432
  state.initialScroll = void 0;
1370
1433
  state.initialAnchor = void 0;
1371
- set$(ctx, "scrollingTo", void 0);
1434
+ state.scrollingTo = void 0;
1372
1435
  if (state.pendingTotalSize !== void 0) {
1373
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1436
+ addTotalSize(ctx, null, state.pendingTotalSize);
1374
1437
  }
1375
1438
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1376
1439
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1377
1440
  }
1441
+ {
1442
+ state.scrollAdjustHandler.commitPendingAdjust();
1443
+ }
1444
+ setInitialRenderState(ctx, { didInitialScroll: true });
1445
+ }
1446
+ }
1447
+
1448
+ // src/core/doScrollTo.ts
1449
+ var SCROLL_END_IDLE_MS = 80;
1450
+ var SCROLL_END_MAX_MS = 1500;
1451
+ var SMOOTH_SCROLL_DURATION_MS = 320;
1452
+ function doScrollTo(ctx, params) {
1453
+ const state = ctx.state;
1454
+ const { animated, horizontal, offset } = params;
1455
+ const scroller = state.refScroller.current;
1456
+ const node = typeof (scroller == null ? void 0 : scroller.getScrollableNode) === "function" ? scroller.getScrollableNode() : scroller;
1457
+ if (node) {
1458
+ const left = horizontal ? offset : 0;
1459
+ const top = horizontal ? 0 : offset;
1460
+ node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1461
+ if (animated) {
1462
+ listenForScrollEnd(ctx, node);
1463
+ } else {
1464
+ state.scroll = offset;
1465
+ setTimeout(() => {
1466
+ finishScrollTo(ctx);
1467
+ }, 100);
1468
+ }
1469
+ }
1470
+ }
1471
+ function listenForScrollEnd(ctx, node) {
1472
+ const supportsScrollEnd = "onscrollend" in node;
1473
+ let idleTimeout;
1474
+ let maxTimeout;
1475
+ let settled = false;
1476
+ const targetToken = ctx.state.scrollingTo;
1477
+ const finish = () => {
1478
+ if (settled) return;
1479
+ settled = true;
1480
+ cleanup();
1481
+ if (targetToken === ctx.state.scrollingTo) {
1482
+ finishScrollTo(ctx);
1483
+ }
1484
+ };
1485
+ const onScroll2 = () => {
1486
+ if (idleTimeout) {
1487
+ clearTimeout(idleTimeout);
1488
+ }
1489
+ idleTimeout = setTimeout(finish, SCROLL_END_IDLE_MS);
1490
+ };
1491
+ const cleanup = () => {
1492
+ if (supportsScrollEnd) {
1493
+ node.removeEventListener("scrollend", finish);
1494
+ } else {
1495
+ node.removeEventListener("scroll", onScroll2);
1496
+ }
1497
+ if (idleTimeout) {
1498
+ clearTimeout(idleTimeout);
1499
+ }
1500
+ if (maxTimeout) {
1501
+ clearTimeout(maxTimeout);
1502
+ }
1503
+ };
1504
+ if (supportsScrollEnd) {
1505
+ node.addEventListener("scrollend", finish, { once: true });
1506
+ } else {
1507
+ node.addEventListener("scroll", onScroll2);
1508
+ idleTimeout = setTimeout(finish, SMOOTH_SCROLL_DURATION_MS);
1509
+ maxTimeout = setTimeout(finish, SCROLL_END_MAX_MS);
1378
1510
  }
1511
+ return cleanup;
1379
1512
  }
1380
1513
 
1381
1514
  // src/core/scrollTo.ts
1382
- function scrollTo(ctx, state, params) {
1383
- var _a3;
1384
- const { noScrollingTo, ...scrollTarget } = params;
1515
+ function scrollTo(ctx, params) {
1516
+ const state = ctx.state;
1517
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1385
1518
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1386
1519
  const {
1387
- refScroller,
1388
1520
  props: { horizontal }
1389
1521
  } = state;
1390
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1391
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1392
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1393
- offset = Math.min(offset, maxOffset);
1522
+ if (state.animFrameCheckFinishedScroll) {
1523
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1524
+ }
1525
+ if (state.timeoutCheckFinishedScrollFallback) {
1526
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1394
1527
  }
1528
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1529
+ offset = clampScrollOffset(ctx, offset);
1395
1530
  state.scrollHistory.length = 0;
1396
1531
  if (!noScrollingTo) {
1397
- set$(ctx, "scrollingTo", scrollTarget);
1532
+ state.scrollingTo = scrollTarget;
1398
1533
  }
1399
1534
  state.scrollPending = offset;
1400
- if (!isInitialScroll || Platform.OS === "android") {
1401
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1402
- animated: !!animated,
1403
- x: horizontal ? offset : 0,
1404
- y: horizontal ? 0 : offset
1405
- });
1406
- }
1407
- if (!animated) {
1535
+ if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1536
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1537
+ } else {
1408
1538
  state.scroll = offset;
1409
- {
1410
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1411
- if (value && peek$(ctx, "scrollingTo")) {
1412
- finishScrollTo(ctx, state);
1413
- unlisten();
1414
- }
1415
- });
1416
- }
1417
- if (isInitialScroll) {
1418
- setTimeout(() => {
1419
- state.initialScroll = void 0;
1420
- }, 500);
1421
- }
1422
1539
  }
1423
1540
  }
1424
1541
 
@@ -1427,6 +1544,12 @@ var HYSTERESIS_MULTIPLIER = 1.3;
1427
1544
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1428
1545
  const absDistance = Math.abs(distance);
1429
1546
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1547
+ if (wasReached === null) {
1548
+ if (!within && distance >= 0) {
1549
+ return false;
1550
+ }
1551
+ return null;
1552
+ }
1430
1553
  const updateSnapshot = () => {
1431
1554
  setSnapshot == null ? void 0 : setSnapshot({
1432
1555
  atThreshold,
@@ -1459,8 +1582,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1459
1582
  };
1460
1583
 
1461
1584
  // src/utils/checkAtBottom.ts
1462
- function checkAtBottom(ctx, state) {
1585
+ function checkAtBottom(ctx) {
1463
1586
  var _a3;
1587
+ const state = ctx.state;
1464
1588
  if (!state) {
1465
1589
  return;
1466
1590
  }
@@ -1533,15 +1657,15 @@ function checkAtTop(state) {
1533
1657
  }
1534
1658
 
1535
1659
  // src/core/updateScroll.ts
1536
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1660
+ function updateScroll(ctx, newScroll, forceUpdate) {
1537
1661
  var _a3;
1538
- const scrollingTo = peek$(ctx, "scrollingTo");
1662
+ const state = ctx.state;
1663
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1539
1664
  state.hasScrolled = true;
1540
1665
  state.lastBatchingAction = Date.now();
1541
1666
  const currentTime = Date.now();
1542
- const adjust = state.scrollAdjustHandler.getAdjust();
1543
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1544
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1667
+ const adjust = scrollAdjustHandler.getAdjust();
1668
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1545
1669
  if (adjustChanged) {
1546
1670
  state.scrollHistory.length = 0;
1547
1671
  }
@@ -1566,17 +1690,21 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1566
1690
  return;
1567
1691
  }
1568
1692
  }
1569
- if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1693
+ const lastCalculated = state.scrollLastCalculate;
1694
+ const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1695
+ if (shouldUpdate) {
1696
+ state.scrollLastCalculate = state.scroll;
1570
1697
  state.ignoreScrollFromMVCPIgnored = false;
1571
1698
  (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1572
- checkAtBottom(ctx, state);
1699
+ checkAtBottom(ctx);
1573
1700
  checkAtTop(state);
1574
1701
  state.dataChangeNeedsScrollUpdate = false;
1575
1702
  }
1576
1703
  }
1577
1704
 
1578
1705
  // src/utils/requestAdjust.ts
1579
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1706
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1707
+ const state = ctx.state;
1580
1708
  if (Math.abs(positionDiff) > 0.1) {
1581
1709
  const doit = () => {
1582
1710
  {
@@ -1588,8 +1716,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1588
1716
  };
1589
1717
  state.scroll += positionDiff;
1590
1718
  state.scrollForNextCalculateItemsInView = void 0;
1591
- const didLayout = peek$(ctx, "containersDidLayout");
1592
- if (didLayout) {
1719
+ const readyToRender = peek$(ctx, "readyToRender");
1720
+ if (readyToRender) {
1593
1721
  doit();
1594
1722
  } else {
1595
1723
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -1598,73 +1726,23 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1598
1726
  }
1599
1727
  }
1600
1728
 
1601
- // src/core/ensureInitialAnchor.ts
1602
- var INITIAL_ANCHOR_TOLERANCE = 0.5;
1603
- var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1604
- var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1605
- function ensureInitialAnchor(ctx, state) {
1606
- var _a3, _b, _c, _d, _e;
1607
- const anchor = state.initialAnchor;
1608
- const item = state.props.data[anchor.index];
1609
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1610
- if (!containersDidLayout) {
1611
- return;
1612
- }
1613
- const id = getId(state, anchor.index);
1614
- if (state.positions.get(id) === void 0) {
1615
- return;
1616
- }
1617
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1618
- if (size === void 0) {
1619
- return;
1620
- }
1621
- const availableSpace = Math.max(0, state.scrollLength - size);
1622
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1623
- const contentSize = getContentSize(ctx);
1624
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1625
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1626
- const delta = clampedDesiredOffset - state.scroll;
1627
- if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1628
- const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1629
- if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1630
- state.initialAnchor = void 0;
1631
- } else {
1632
- anchor.settledTicks = settledTicks;
1633
- }
1634
- return;
1635
- }
1636
- if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1637
- state.initialAnchor = void 0;
1638
- return;
1639
- }
1640
- const lastDelta = anchor.lastDelta;
1641
- if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1642
- state.initialAnchor = void 0;
1643
- return;
1644
- }
1645
- Object.assign(anchor, {
1646
- attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1647
- lastDelta: delta,
1648
- settledTicks: 0
1649
- });
1650
- requestAdjust(ctx, state, delta);
1651
- }
1652
-
1653
1729
  // src/core/mvcp.ts
1654
- function prepareMVCP(ctx, state, dataChanged) {
1730
+ function prepareMVCP(ctx, dataChanged) {
1731
+ const state = ctx.state;
1655
1732
  const { idsInView, positions, props } = state;
1656
1733
  const { maintainVisibleContentPosition } = props;
1657
- const scrollingTo = peek$(ctx, "scrollingTo");
1734
+ const scrollingTo = state.scrollingTo;
1658
1735
  let prevPosition;
1659
1736
  let targetId;
1660
1737
  const idsInViewWithPositions = [];
1661
1738
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1739
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1662
1740
  const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1663
1741
  const indexByKey = state.indexByKey;
1664
1742
  if (shouldMVCP) {
1665
1743
  if (scrollTarget !== void 0) {
1666
1744
  targetId = getId(state, scrollTarget);
1667
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1745
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1668
1746
  if (dataChanged) {
1669
1747
  for (let i = 0; i < idsInView.length; i++) {
1670
1748
  const id = idsInView[i];
@@ -1681,7 +1759,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1681
1759
  prevPosition = positions.get(targetId);
1682
1760
  }
1683
1761
  return () => {
1684
- let positionDiff;
1762
+ let positionDiff = 0;
1685
1763
  if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1686
1764
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1687
1765
  const { id, position } = idsInViewWithPositions[i];
@@ -1707,16 +1785,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1707
1785
  positionDiff = diff;
1708
1786
  }
1709
1787
  }
1710
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1711
- requestAdjust(ctx, state, positionDiff);
1788
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1789
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1790
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1791
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1792
+ const diff = newSize - prevSize;
1793
+ if (diff !== 0) {
1794
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1795
+ scrollingTo.itemSize = newSize;
1796
+ }
1797
+ }
1798
+ }
1799
+ if (Math.abs(positionDiff) > 0.1) {
1800
+ requestAdjust(ctx, positionDiff);
1712
1801
  }
1713
1802
  };
1714
1803
  }
1715
1804
  }
1716
1805
 
1717
1806
  // src/core/prepareColumnStartState.ts
1718
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1807
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1719
1808
  var _a3;
1809
+ const state = ctx.state;
1720
1810
  const numColumns = peek$(ctx, "numColumns");
1721
1811
  let rowStartIndex = startIndex;
1722
1812
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1731,7 +1821,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1731
1821
  const prevId = state.idCache[prevIndex];
1732
1822
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1733
1823
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1734
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1824
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1735
1825
  currentRowTop = prevPosition + prevRowHeight;
1736
1826
  }
1737
1827
  return {
@@ -1754,7 +1844,8 @@ function findRowStartIndex(state, numColumns, index) {
1754
1844
  }
1755
1845
  return rowStart;
1756
1846
  }
1757
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1847
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1848
+ const state = ctx.state;
1758
1849
  if (endIndex < startIndex) {
1759
1850
  return 0;
1760
1851
  }
@@ -1768,7 +1859,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1768
1859
  continue;
1769
1860
  }
1770
1861
  const id = state.idCache[i];
1771
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1862
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1772
1863
  if (size > maxSize) {
1773
1864
  maxSize = size;
1774
1865
  }
@@ -1777,22 +1868,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1777
1868
  }
1778
1869
 
1779
1870
  // src/core/updateTotalSize.ts
1780
- function updateTotalSize(ctx, state) {
1871
+ function updateTotalSize(ctx) {
1872
+ const state = ctx.state;
1781
1873
  const {
1782
1874
  positions,
1783
1875
  props: { data }
1784
1876
  } = state;
1785
1877
  if (data.length === 0) {
1786
- addTotalSize(ctx, state, null, 0);
1878
+ addTotalSize(ctx, null, 0);
1787
1879
  } else {
1788
1880
  const lastId = getId(state, data.length - 1);
1789
1881
  if (lastId !== void 0) {
1790
1882
  const lastPosition = positions.get(lastId);
1791
1883
  if (lastPosition !== void 0) {
1792
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1884
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1793
1885
  if (lastSize !== void 0) {
1794
1886
  const totalSize = lastPosition + lastSize;
1795
- addTotalSize(ctx, state, null, totalSize);
1887
+ addTotalSize(ctx, null, totalSize);
1796
1888
  }
1797
1889
  }
1798
1890
  }
@@ -1838,7 +1930,8 @@ var getScrollVelocity = (state) => {
1838
1930
  };
1839
1931
 
1840
1932
  // src/utils/updateSnapToOffsets.ts
1841
- function updateSnapToOffsets(ctx, state) {
1933
+ function updateSnapToOffsets(ctx) {
1934
+ const state = ctx.state;
1842
1935
  const {
1843
1936
  positions,
1844
1937
  props: { snapToIndices }
@@ -1853,30 +1946,30 @@ function updateSnapToOffsets(ctx, state) {
1853
1946
  }
1854
1947
 
1855
1948
  // src/core/updateItemPositions.ts
1856
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1949
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1857
1950
  doMVCP: false,
1858
1951
  forceFullUpdate: false,
1859
1952
  scrollBottomBuffered: -1,
1860
1953
  startIndex: 0
1861
1954
  }) {
1862
1955
  var _a3, _b, _c, _d, _e;
1956
+ const state = ctx.state;
1863
1957
  const {
1864
1958
  columns,
1865
1959
  indexByKey,
1866
1960
  positions,
1867
1961
  idCache,
1868
1962
  sizesKnown,
1869
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1963
+ props: { data, getEstimatedItemSize, snapToIndices },
1964
+ scrollingTo
1870
1965
  } = state;
1871
- const data = state.props.data;
1872
1966
  const dataLength = data.length;
1873
1967
  const numColumns = peek$(ctx, "numColumns");
1874
- const scrollingTo = peek$(ctx, "scrollingTo");
1875
1968
  const hasColumns = numColumns > 1;
1876
1969
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1877
1970
  const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1878
1971
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1879
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1972
+ const useAverageSize = !getEstimatedItemSize;
1880
1973
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1881
1974
  let currentRowTop = 0;
1882
1975
  let column = 1;
@@ -1885,7 +1978,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1885
1978
  if (hasColumns) {
1886
1979
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1887
1980
  ctx,
1888
- state,
1889
1981
  startIndex,
1890
1982
  useAverageSize
1891
1983
  );
@@ -1895,7 +1987,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1895
1987
  const prevIndex = startIndex - 1;
1896
1988
  const prevId = getId(state, prevIndex);
1897
1989
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1898
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1990
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1899
1991
  currentRowTop = prevPosition + prevSize;
1900
1992
  }
1901
1993
  }
@@ -1912,7 +2004,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1912
2004
  breakAt = i + itemsPerRow + 10;
1913
2005
  }
1914
2006
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1915
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
2007
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1916
2008
  if (IS_DEV && needsIndexByKey) {
1917
2009
  if (indexByKeyForChecking.has(id)) {
1918
2010
  console.error(
@@ -1921,7 +2013,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1921
2013
  }
1922
2014
  indexByKeyForChecking.set(id, i);
1923
2015
  }
1924
- positions.set(id, currentRowTop);
2016
+ if (currentRowTop !== positions.get(id)) {
2017
+ positions.set(id, currentRowTop);
2018
+ notifyPosition$(ctx, id, currentRowTop);
2019
+ }
1925
2020
  if (needsIndexByKey) {
1926
2021
  indexByKey.set(id, i);
1927
2022
  }
@@ -1941,10 +2036,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1941
2036
  }
1942
2037
  }
1943
2038
  if (!didBreakEarly) {
1944
- updateTotalSize(ctx, state);
2039
+ updateTotalSize(ctx);
1945
2040
  }
1946
2041
  if (snapToIndices) {
1947
- updateSnapToOffsets(ctx, state);
2042
+ updateSnapToOffsets(ctx);
1948
2043
  }
1949
2044
  }
1950
2045
 
@@ -2022,7 +2117,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
2022
2117
  if (previousViewableItems) {
2023
2118
  for (const viewToken of previousViewableItems) {
2024
2119
  const containerId = findContainerId(ctx, viewToken.key);
2025
- if (!isViewable(
2120
+ if (!checkIsViewable(
2026
2121
  state,
2027
2122
  ctx,
2028
2123
  viewabilityConfig,
@@ -2043,7 +2138,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
2043
2138
  if (item) {
2044
2139
  const key = getId(state, i);
2045
2140
  const containerId = findContainerId(ctx, key);
2046
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2141
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2047
2142
  const viewToken = {
2048
2143
  containerId,
2049
2144
  index: i,
@@ -2103,11 +2198,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2103
2198
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
2104
2199
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
2105
2200
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
2106
- const isViewable2 = percent >= viewablePercentThreshold;
2201
+ const isViewable = percent >= viewablePercentThreshold;
2107
2202
  const value = {
2108
2203
  containerId,
2109
2204
  index,
2110
- isViewable: isViewable2,
2205
+ isViewable,
2111
2206
  item,
2112
2207
  key,
2113
2208
  percentOfScroller,
@@ -2126,8 +2221,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2126
2221
  }
2127
2222
  return value;
2128
2223
  }
2129
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2130
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2224
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2225
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2226
+ if (!value || value.key !== key) {
2227
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2228
+ }
2131
2229
  return value.isViewable;
2132
2230
  }
2133
2231
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -2155,8 +2253,9 @@ function checkAllSizesKnown(state) {
2155
2253
  }
2156
2254
 
2157
2255
  // src/utils/findAvailableContainers.ts
2158
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2256
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2159
2257
  const numContainers = peek$(ctx, "numContainers");
2258
+ const state = ctx.state;
2160
2259
  const { stickyContainerPool, containerItemTypes } = state;
2161
2260
  const result = [];
2162
2261
  const availableContainers = [];
@@ -2200,14 +2299,14 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
2200
2299
  continue;
2201
2300
  }
2202
2301
  const key = peek$(ctx, `containerItemKey${u}`);
2203
- let isOk = key === void 0;
2204
- if (!isOk && pendingRemovalSet.has(u)) {
2205
- pendingRemovalSet.delete(u);
2206
- pendingRemovalChanged = true;
2207
- const requiredType = neededTypes[typeIndex];
2208
- isOk = canReuseContainer(u, requiredType);
2209
- }
2210
- if (isOk) {
2302
+ const requiredType = neededTypes[typeIndex];
2303
+ const isPending = key !== void 0 && pendingRemovalSet.has(u);
2304
+ const canUse = key === void 0 || isPending && canReuseContainer(u, requiredType);
2305
+ if (canUse) {
2306
+ if (isPending) {
2307
+ pendingRemovalSet.delete(u);
2308
+ pendingRemovalChanged = true;
2309
+ }
2211
2310
  result.push(u);
2212
2311
  if (requiredItemTypes) {
2213
2312
  typeIndex++;
@@ -2276,21 +2375,26 @@ function comparatorByDistance(a, b) {
2276
2375
  }
2277
2376
 
2278
2377
  // src/core/scrollToIndex.ts
2279
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2280
- if (index >= state.props.data.length) {
2281
- index = state.props.data.length - 1;
2378
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2379
+ const state = ctx.state;
2380
+ const { data } = state.props;
2381
+ if (index >= data.length) {
2382
+ index = data.length - 1;
2282
2383
  } else if (index < 0) {
2283
2384
  index = 0;
2284
2385
  }
2285
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2286
- const isLast = index === state.props.data.length - 1;
2386
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2387
+ const isLast = index === data.length - 1;
2287
2388
  if (isLast && viewPosition === void 0) {
2288
2389
  viewPosition = 1;
2289
2390
  }
2290
2391
  state.scrollForNextCalculateItemsInView = void 0;
2291
- scrollTo(ctx, state, {
2392
+ const targetId = getId(state, index);
2393
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2394
+ scrollTo(ctx, {
2292
2395
  animated,
2293
2396
  index,
2397
+ itemSize,
2294
2398
  offset: firstIndexOffset,
2295
2399
  viewOffset,
2296
2400
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2298,16 +2402,17 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2298
2402
  }
2299
2403
 
2300
2404
  // src/utils/setDidLayout.ts
2301
- function setDidLayout(ctx, state) {
2405
+ function setDidLayout(ctx) {
2406
+ const state = ctx.state;
2302
2407
  const {
2303
2408
  loadStartTime,
2304
2409
  initialScroll,
2305
2410
  props: { onLoad }
2306
2411
  } = state;
2307
2412
  state.queuedInitialLayout = true;
2308
- checkAtBottom(ctx, state);
2413
+ checkAtBottom(ctx);
2309
2414
  const setIt = () => {
2310
- set$(ctx, "containersDidLayout", true);
2415
+ setInitialRenderState(ctx, { didLayout: true });
2311
2416
  if (onLoad) {
2312
2417
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2313
2418
  }
@@ -2332,15 +2437,17 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2332
2437
  }
2333
2438
  return -1;
2334
2439
  }
2335
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2440
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2441
+ const state = ctx.state;
2336
2442
  return new Set(
2337
2443
  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))
2338
2444
  );
2339
2445
  }
2340
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2446
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2341
2447
  var _a3;
2342
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2343
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2448
+ const state = ctx.state;
2449
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2450
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2344
2451
  for (let offset = 0; offset <= 1; offset++) {
2345
2452
  const idx = currentStickyIdx - offset;
2346
2453
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -2351,8 +2458,9 @@ function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, cu
2351
2458
  }
2352
2459
  }
2353
2460
  }
2354
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2461
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2355
2462
  var _a3, _b, _c;
2463
+ const state = ctx.state;
2356
2464
  for (const containerIndex of state.stickyContainerPool) {
2357
2465
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2358
2466
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
@@ -2376,7 +2484,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2376
2484
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2377
2485
  if (currentId) {
2378
2486
  const currentPos = state.positions.get(currentId);
2379
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2487
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2380
2488
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2381
2489
  }
2382
2490
  }
@@ -2385,7 +2493,8 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2385
2493
  }
2386
2494
  }
2387
2495
  }
2388
- function calculateItemsInView(ctx, state, params = {}) {
2496
+ function calculateItemsInView(ctx, params = {}) {
2497
+ const state = ctx.state;
2389
2498
  reactDom.unstable_batchedUpdates(() => {
2390
2499
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2391
2500
  const {
@@ -2409,9 +2518,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2409
2518
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2410
2519
  const prevNumContainers = peek$(ctx, "numContainers");
2411
2520
  if (!data || scrollLength === 0 || !prevNumContainers) {
2412
- if (state.initialAnchor) {
2413
- ensureInitialAnchor(ctx, state);
2414
- }
2415
2521
  return;
2416
2522
  }
2417
2523
  const totalSize = getContentSize(ctx);
@@ -2425,15 +2531,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2425
2531
  if (!queuedInitialLayout && initialScroll) {
2426
2532
  const updatedOffset = calculateOffsetWithOffsetPosition(
2427
2533
  ctx,
2428
- state,
2429
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2534
+ calculateOffsetForIndex(ctx, initialScroll.index),
2430
2535
  initialScroll
2431
2536
  );
2432
2537
  scrollState = updatedOffset;
2433
2538
  }
2434
2539
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2435
2540
  const scrollAdjustPad = scrollAdjustPending - topPad;
2436
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2541
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2437
2542
  if (scroll + scrollLength > totalSize) {
2438
2543
  scroll = Math.max(0, totalSize - scrollLength);
2439
2544
  }
@@ -2441,11 +2546,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2441
2546
  set$(ctx, "debugRawScroll", scrollState);
2442
2547
  set$(ctx, "debugComputedScroll", scroll);
2443
2548
  }
2444
- const previousStickyIndex = state.activeStickyIndex;
2549
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2445
2550
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2446
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2447
- state.activeStickyIndex = nextActiveStickyIndex;
2448
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2551
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2552
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2553
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2554
+ }
2449
2555
  let scrollBufferTop = scrollBuffer;
2450
2556
  let scrollBufferBottom = scrollBuffer;
2451
2557
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2458,23 +2564,20 @@ function calculateItemsInView(ctx, state, params = {}) {
2458
2564
  const scrollTopBuffered = scroll - scrollBufferTop;
2459
2565
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2460
2566
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2461
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2567
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2462
2568
  const { top, bottom } = scrollForNextCalculateItemsInView;
2463
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2464
- if (state.initialAnchor) {
2465
- ensureInitialAnchor(ctx, state);
2466
- }
2569
+ if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2467
2570
  return;
2468
2571
  }
2469
2572
  }
2470
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2573
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2471
2574
  if (dataChanged) {
2472
2575
  indexByKey.clear();
2473
2576
  idCache.length = 0;
2474
2577
  positions.clear();
2475
2578
  }
2476
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2477
- updateItemPositions(ctx, state, dataChanged, {
2579
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2580
+ updateItemPositions(ctx, dataChanged, {
2478
2581
  doMVCP,
2479
2582
  forceFullUpdate: !!forceFullItemPositions,
2480
2583
  scrollBottomBuffered,
@@ -2493,9 +2596,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2493
2596
  for (let i = loopStart; i >= 0; i--) {
2494
2597
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2495
2598
  const top = positions.get(id);
2496
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2599
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2497
2600
  const bottom = top + size;
2498
- if (bottom > scroll - scrollBuffer) {
2601
+ if (bottom > scroll - scrollBufferTop) {
2499
2602
  loopStart = i;
2500
2603
  } else {
2501
2604
  break;
@@ -2520,7 +2623,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2520
2623
  const dataLength = data.length;
2521
2624
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2522
2625
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2523
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2626
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2524
2627
  const top = positions.get(id);
2525
2628
  if (!foundEnd) {
2526
2629
  if (startNoBuffer === null && top + size > scroll) {
@@ -2532,7 +2635,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2532
2635
  if (startBuffered === null && top + size > scrollTopBuffered) {
2533
2636
  startBuffered = i;
2534
2637
  startBufferedId = id;
2535
- nextTop = top;
2638
+ if (scrollTopBuffered < 0) {
2639
+ nextTop = null;
2640
+ } else {
2641
+ nextTop = top;
2642
+ }
2536
2643
  }
2537
2644
  if (startNoBuffer !== null) {
2538
2645
  if (top <= scrollBottom) {
@@ -2540,7 +2647,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2540
2647
  }
2541
2648
  if (top <= scrollBottomBuffered) {
2542
2649
  endBuffered = i;
2543
- nextBottom = top + size;
2650
+ if (scrollBottomBuffered > totalSize) {
2651
+ nextBottom = null;
2652
+ } else {
2653
+ nextBottom = top + size;
2654
+ }
2544
2655
  } else {
2545
2656
  foundEnd = true;
2546
2657
  }
@@ -2567,7 +2678,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2567
2678
  top: nextTop
2568
2679
  } : void 0;
2569
2680
  }
2570
- const numContainers = peek$(ctx, "numContainers");
2681
+ let numContainers = prevNumContainers;
2571
2682
  const pendingRemoval = [];
2572
2683
  if (dataChanged) {
2573
2684
  for (let i = 0; i < numContainers; i++) {
@@ -2578,7 +2689,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2578
2689
  }
2579
2690
  }
2580
2691
  if (startBuffered !== null && endBuffered !== null) {
2581
- let numContainers2 = prevNumContainers;
2582
2692
  const needNewContainers = [];
2583
2693
  for (let i = startBuffered; i <= endBuffered; i++) {
2584
2694
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
@@ -2589,7 +2699,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2589
2699
  if (stickyIndicesArr.length > 0) {
2590
2700
  handleStickyActivation(
2591
2701
  ctx,
2592
- state,
2593
2702
  stickyIndicesSet,
2594
2703
  stickyIndicesArr,
2595
2704
  currentStickyIdx,
@@ -2597,9 +2706,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2597
2706
  startBuffered,
2598
2707
  endBuffered
2599
2708
  );
2600
- } else {
2601
- state.activeStickyIndex = void 0;
2602
- set$(ctx, "activeStickyIndex", void 0);
2709
+ } else if (previousStickyIndex !== -1) {
2710
+ set$(ctx, "activeStickyIndex", -1);
2603
2711
  }
2604
2712
  if (needNewContainers.length > 0) {
2605
2713
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2608,7 +2716,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2608
2716
  }) : void 0;
2609
2717
  const availableContainers = findAvailableContainers(
2610
2718
  ctx,
2611
- state,
2612
2719
  needNewContainers.length,
2613
2720
  startBuffered,
2614
2721
  endBuffered,
@@ -2630,29 +2737,30 @@ function calculateItemsInView(ctx, state, params = {}) {
2630
2737
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2631
2738
  }
2632
2739
  containerItemKeys.add(id);
2740
+ const containerSticky = `containerSticky${containerIndex}`;
2633
2741
  if (stickyIndicesSet.has(i)) {
2634
- set$(ctx, `containerSticky${containerIndex}`, true);
2742
+ set$(ctx, containerSticky, true);
2635
2743
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2636
2744
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2637
2745
  state.stickyContainerPool.add(containerIndex);
2638
- } else {
2639
- set$(ctx, `containerSticky${containerIndex}`, false);
2746
+ } else if (peek$(ctx, containerSticky)) {
2747
+ set$(ctx, containerSticky, false);
2640
2748
  state.stickyContainerPool.delete(containerIndex);
2641
2749
  }
2642
- if (containerIndex >= numContainers2) {
2643
- numContainers2 = containerIndex + 1;
2750
+ if (containerIndex >= numContainers) {
2751
+ numContainers = containerIndex + 1;
2644
2752
  }
2645
2753
  }
2646
- if (numContainers2 !== prevNumContainers) {
2647
- set$(ctx, "numContainers", numContainers2);
2648
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2649
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2754
+ if (numContainers !== prevNumContainers) {
2755
+ set$(ctx, "numContainers", numContainers);
2756
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2757
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2650
2758
  }
2651
2759
  }
2652
2760
  }
2653
2761
  }
2654
2762
  if (stickyIndicesArr.length > 0) {
2655
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2763
+ handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2656
2764
  }
2657
2765
  let didChangePositions = false;
2658
2766
  for (let i = 0; i < numContainers; i++) {
@@ -2704,7 +2812,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2704
2812
  }
2705
2813
  if (!queuedInitialLayout && endBuffered !== null) {
2706
2814
  if (checkAllSizesKnown(state)) {
2707
- setDidLayout(ctx, state);
2815
+ setDidLayout(ctx);
2708
2816
  }
2709
2817
  }
2710
2818
  if (viewabilityConfigCallbackPairs) {
@@ -2717,9 +2825,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2717
2825
  }
2718
2826
  }
2719
2827
  });
2720
- if (state.initialAnchor) {
2721
- ensureInitialAnchor(ctx, state);
2722
- }
2723
2828
  }
2724
2829
 
2725
2830
  // src/core/checkActualChange.ts
@@ -2742,20 +2847,69 @@ function checkActualChange(state, dataProp, previousData) {
2742
2847
  return false;
2743
2848
  }
2744
2849
 
2850
+ // src/core/checkFinishedScroll.ts
2851
+ function checkFinishedScroll(ctx) {
2852
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2853
+ }
2854
+ function checkFinishedScrollFrame(ctx) {
2855
+ const scrollingTo = ctx.state.scrollingTo;
2856
+ if (scrollingTo) {
2857
+ const { state } = ctx;
2858
+ state.animFrameCheckFinishedScroll = void 0;
2859
+ const scroll = state.scroll;
2860
+ const adjust = state.scrollAdjustHandler.getAdjust();
2861
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
2862
+ const maxOffset = clampScrollOffset(ctx, scroll);
2863
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
2864
+ const diff2 = Math.abs(diff1 - adjust);
2865
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
2866
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
2867
+ finishScrollTo(ctx);
2868
+ }
2869
+ }
2870
+ }
2871
+ function checkFinishedScrollFallback(ctx) {
2872
+ const state = ctx.state;
2873
+ const scrollingTo = state.scrollingTo;
2874
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
2875
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
2876
+ () => {
2877
+ let numChecks = 0;
2878
+ const checkHasScrolled = () => {
2879
+ state.timeoutCheckFinishedScrollFallback = void 0;
2880
+ const isStillScrollingTo = state.scrollingTo;
2881
+ if (isStillScrollingTo) {
2882
+ numChecks++;
2883
+ if (state.hasScrolled || numChecks > 5) {
2884
+ finishScrollTo(ctx);
2885
+ } else {
2886
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
2887
+ }
2888
+ }
2889
+ };
2890
+ checkHasScrolled();
2891
+ },
2892
+ slowTimeout ? 500 : 100
2893
+ );
2894
+ }
2895
+
2745
2896
  // src/core/doMaintainScrollAtEnd.ts
2746
- function doMaintainScrollAtEnd(ctx, state, animated) {
2897
+ function doMaintainScrollAtEnd(ctx, animated) {
2898
+ const state = ctx.state;
2747
2899
  const {
2900
+ didContainersLayout,
2901
+ isAtEnd,
2748
2902
  refScroller,
2749
2903
  props: { maintainScrollAtEnd }
2750
2904
  } = state;
2751
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2905
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2752
2906
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2753
2907
  if (paddingTop > 0) {
2754
2908
  state.scroll = 0;
2755
2909
  }
2756
2910
  requestAnimationFrame(() => {
2757
2911
  var _a3;
2758
- if (state == null ? void 0 : state.isAtEnd) {
2912
+ if (state.isAtEnd) {
2759
2913
  state.maintainingScrollAtEnd = true;
2760
2914
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2761
2915
  animated
@@ -2826,28 +2980,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2826
2980
  }
2827
2981
 
2828
2982
  // src/core/checkResetContainers.ts
2829
- function checkResetContainers(ctx, state, dataProp) {
2983
+ function checkResetContainers(ctx, dataProp) {
2984
+ const state = ctx.state;
2830
2985
  const { previousData } = state;
2831
2986
  if (previousData) {
2832
2987
  updateAveragesOnDataChange(state, previousData, dataProp);
2833
2988
  }
2834
2989
  const { maintainScrollAtEnd } = state.props;
2835
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2990
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2836
2991
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2837
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2992
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2838
2993
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2839
2994
  state.isEndReached = false;
2840
2995
  }
2841
2996
  if (!didMaintainScrollAtEnd) {
2842
2997
  checkAtTop(state);
2843
- checkAtBottom(ctx, state);
2998
+ checkAtBottom(ctx);
2844
2999
  }
2845
3000
  delete state.previousData;
2846
3001
  }
2847
3002
 
2848
3003
  // src/core/doInitialAllocateContainers.ts
2849
- function doInitialAllocateContainers(ctx, state) {
3004
+ function doInitialAllocateContainers(ctx) {
2850
3005
  var _a3, _b, _c;
3006
+ const state = ctx.state;
2851
3007
  const {
2852
3008
  scrollLength,
2853
3009
  props: {
@@ -2885,10 +3041,10 @@ function doInitialAllocateContainers(ctx, state) {
2885
3041
  if (state.lastLayout) {
2886
3042
  if (state.initialScroll) {
2887
3043
  requestAnimationFrame(() => {
2888
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
3044
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2889
3045
  });
2890
3046
  } else {
2891
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
3047
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2892
3048
  }
2893
3049
  }
2894
3050
  return true;
@@ -2896,7 +3052,8 @@ function doInitialAllocateContainers(ctx, state) {
2896
3052
  }
2897
3053
 
2898
3054
  // src/core/handleLayout.ts
2899
- function handleLayout(ctx, state, layout, setCanRender) {
3055
+ function handleLayout(ctx, layout, setCanRender) {
3056
+ const state = ctx.state;
2900
3057
  const { maintainScrollAtEnd } = state.props;
2901
3058
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2902
3059
  const previousLength = state.scrollLength;
@@ -2912,19 +3069,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2912
3069
  state.lastBatchingAction = Date.now();
2913
3070
  state.scrollForNextCalculateItemsInView = void 0;
2914
3071
  if (scrollLength > 0) {
2915
- doInitialAllocateContainers(ctx, state);
3072
+ doInitialAllocateContainers(ctx);
2916
3073
  }
2917
3074
  if (needsCalculate) {
2918
- calculateItemsInView(ctx, state, { doMVCP: true });
3075
+ calculateItemsInView(ctx, { doMVCP: true });
2919
3076
  }
2920
3077
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2921
3078
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2922
3079
  }
2923
3080
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2924
- doMaintainScrollAtEnd(ctx, state, false);
3081
+ doMaintainScrollAtEnd(ctx, false);
2925
3082
  }
2926
- updateAlignItemsPaddingTop(ctx, state);
2927
- checkAtBottom(ctx, state);
3083
+ updateAlignItemsPaddingTop(ctx);
3084
+ checkAtBottom(ctx);
2928
3085
  checkAtTop(state);
2929
3086
  if (state) {
2930
3087
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2940,8 +3097,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2940
3097
  }
2941
3098
 
2942
3099
  // src/core/onScroll.ts
2943
- function onScroll(ctx, state, event) {
3100
+ function onScroll(ctx, event) {
2944
3101
  var _a3, _b, _c;
3102
+ const state = ctx.state;
2945
3103
  const {
2946
3104
  scrollProcessingEnabled,
2947
3105
  props: { onScroll: onScrollProp }
@@ -2952,9 +3110,23 @@ function onScroll(ctx, state, event) {
2952
3110
  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) {
2953
3111
  return;
2954
3112
  }
2955
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3113
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2956
3114
  state.scrollPending = newScroll;
2957
- updateScroll(ctx, state, newScroll);
3115
+ if (state.scrollingTo) {
3116
+ const maxOffset = clampScrollOffset(ctx, newScroll);
3117
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3118
+ newScroll = maxOffset;
3119
+ scrollTo(ctx, {
3120
+ forceScroll: true,
3121
+ isInitialScroll: true,
3122
+ noScrollingTo: true,
3123
+ offset: newScroll
3124
+ });
3125
+ return;
3126
+ }
3127
+ }
3128
+ updateScroll(ctx, newScroll);
3129
+ checkFinishedScroll(ctx);
2958
3130
  onScrollProp == null ? void 0 : onScrollProp(event);
2959
3131
  }
2960
3132
 
@@ -2963,51 +3135,47 @@ var ScrollAdjustHandler = class {
2963
3135
  constructor(ctx) {
2964
3136
  this.appliedAdjust = 0;
2965
3137
  this.pendingAdjust = 0;
2966
- this.mounted = false;
2967
- this.context = ctx;
2968
- {
2969
- const commitPendingAdjust = () => {
2970
- const state = this.context.internalState;
2971
- const pending = this.pendingAdjust;
2972
- if (pending !== 0) {
2973
- this.pendingAdjust = 0;
2974
- this.appliedAdjust += pending;
2975
- state.scroll += pending;
2976
- state.scrollForNextCalculateItemsInView = void 0;
2977
- set$(this.context, "scrollAdjustPending", 0);
2978
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2979
- calculateItemsInView(this.context, this.context.internalState);
2980
- }
2981
- };
2982
- listen$(this.context, "scrollingTo", (value) => {
2983
- if (value === void 0) {
2984
- commitPendingAdjust();
2985
- }
2986
- });
2987
- }
3138
+ this.ctx = ctx;
2988
3139
  }
2989
3140
  requestAdjust(add) {
2990
- const scrollingTo = peek$(this.context, "scrollingTo");
3141
+ const scrollingTo = this.ctx.state.scrollingTo;
2991
3142
  if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2992
3143
  this.pendingAdjust += add;
2993
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
3144
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2994
3145
  } else {
2995
3146
  this.appliedAdjust += add;
2996
- set$(this.context, "scrollAdjust", this.appliedAdjust);
3147
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3148
+ }
3149
+ if (this.ctx.state.scrollingTo) {
3150
+ checkFinishedScroll(this.ctx);
2997
3151
  }
2998
- }
2999
- setMounted() {
3000
- this.mounted = true;
3001
3152
  }
3002
3153
  getAdjust() {
3003
3154
  return this.appliedAdjust;
3004
3155
  }
3156
+ commitPendingAdjust() {
3157
+ {
3158
+ const state = this.ctx.state;
3159
+ const pending = this.pendingAdjust;
3160
+ if (pending !== 0) {
3161
+ this.pendingAdjust = 0;
3162
+ this.appliedAdjust += pending;
3163
+ state.scroll += pending;
3164
+ state.scrollForNextCalculateItemsInView = void 0;
3165
+ set$(this.ctx, "scrollAdjustPending", 0);
3166
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3167
+ calculateItemsInView(this.ctx);
3168
+ }
3169
+ }
3170
+ }
3005
3171
  };
3006
3172
 
3007
3173
  // src/core/updateItemSize.ts
3008
- function updateItemSize(ctx, state, itemKey, sizeObj) {
3174
+ function updateItemSize(ctx, itemKey, sizeObj) {
3009
3175
  var _a3;
3176
+ const state = ctx.state;
3010
3177
  const {
3178
+ didContainersLayout,
3011
3179
  sizesKnown,
3012
3180
  props: {
3013
3181
  getFixedItemSize,
@@ -3035,13 +3203,12 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
3035
3203
  return;
3036
3204
  }
3037
3205
  }
3038
- const containersDidLayout = peek$(ctx, "containersDidLayout");
3039
- let needsRecalculate = !containersDidLayout;
3206
+ let needsRecalculate = !didContainersLayout;
3040
3207
  let shouldMaintainScrollAtEnd = false;
3041
3208
  let minIndexSizeChanged;
3042
3209
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
3043
3210
  const prevSizeKnown = state.sizesKnown.get(itemKey);
3044
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3211
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
3045
3212
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
3046
3213
  if (diff !== 0) {
3047
3214
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
@@ -3090,22 +3257,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
3090
3257
  if (!cur || maxOtherAxisSize > cur) {
3091
3258
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
3092
3259
  }
3093
- if (containersDidLayout || checkAllSizesKnown(state)) {
3260
+ if (didContainersLayout || checkAllSizesKnown(state)) {
3094
3261
  if (needsRecalculate) {
3095
3262
  state.scrollForNextCalculateItemsInView = void 0;
3096
- calculateItemsInView(ctx, state, { doMVCP: true });
3263
+ calculateItemsInView(ctx, { doMVCP: true });
3097
3264
  }
3098
3265
  if (shouldMaintainScrollAtEnd) {
3099
3266
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
3100
- doMaintainScrollAtEnd(ctx, state, false);
3267
+ doMaintainScrollAtEnd(ctx, false);
3101
3268
  }
3102
3269
  }
3103
3270
  }
3104
3271
  }
3105
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3272
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
3106
3273
  var _a3;
3274
+ const state = ctx.state;
3107
3275
  const {
3108
- sizes,
3109
3276
  indexByKey,
3110
3277
  sizesKnown,
3111
3278
  averageSizes,
@@ -3113,9 +3280,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3113
3280
  } = state;
3114
3281
  if (!data) return 0;
3115
3282
  const index = indexByKey.get(itemKey);
3116
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3283
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
3117
3284
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
3118
3285
  const size = Math.round(rawSize) ;
3286
+ const prevSizeKnown = sizesKnown.get(itemKey);
3119
3287
  sizesKnown.set(itemKey, size);
3120
3288
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
3121
3289
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -3123,11 +3291,15 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3123
3291
  if (!averages) {
3124
3292
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3125
3293
  }
3126
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3127
- averages.num++;
3294
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3295
+ averages.avg += (size - prevSizeKnown) / averages.num;
3296
+ } else {
3297
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3298
+ averages.num++;
3299
+ }
3128
3300
  }
3129
3301
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
3130
- setSize(ctx, state, itemKey, size);
3302
+ setSize(ctx, itemKey, size);
3131
3303
  return size - prevSize;
3132
3304
  }
3133
3305
  return 0;
@@ -3174,14 +3346,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
3174
3346
  }
3175
3347
 
3176
3348
  // src/utils/createImperativeHandle.ts
3177
- function createImperativeHandle(ctx, state) {
3349
+ function createImperativeHandle(ctx) {
3350
+ const state = ctx.state;
3178
3351
  const scrollIndexIntoView = (options) => {
3179
3352
  if (state) {
3180
3353
  const { index, ...rest } = options;
3181
3354
  const { startNoBuffer, endNoBuffer } = state;
3182
3355
  if (index < startNoBuffer || index > endNoBuffer) {
3183
3356
  const viewPosition = index < startNoBuffer ? 0 : 1;
3184
- scrollToIndex(ctx, state, {
3357
+ scrollToIndex(ctx, {
3185
3358
  ...rest,
3186
3359
  index,
3187
3360
  viewPosition
@@ -3196,7 +3369,7 @@ function createImperativeHandle(ctx, state) {
3196
3369
  getScrollableNode: () => refScroller.current.getScrollableNode(),
3197
3370
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3198
3371
  getState: () => ({
3199
- activeStickyIndex: state.activeStickyIndex,
3372
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3200
3373
  contentLength: state.totalSize,
3201
3374
  data: state.props.data,
3202
3375
  elementAtIndex: (index) => {
@@ -3207,6 +3380,8 @@ function createImperativeHandle(ctx, state) {
3207
3380
  endBuffered: state.endBuffered,
3208
3381
  isAtEnd: state.isAtEnd,
3209
3382
  isAtStart: state.isAtStart,
3383
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3384
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3210
3385
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
3211
3386
  positions: state.positions,
3212
3387
  scroll: state.scroll,
@@ -3231,23 +3406,23 @@ function createImperativeHandle(ctx, state) {
3231
3406
  if (index !== -1) {
3232
3407
  const paddingBottom = stylePaddingBottom || 0;
3233
3408
  const footerSize = peek$(ctx, "footerSize") || 0;
3234
- scrollToIndex(ctx, state, {
3409
+ scrollToIndex(ctx, {
3410
+ ...options,
3235
3411
  index,
3236
3412
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3237
- viewPosition: 1,
3238
- ...options
3413
+ viewPosition: 1
3239
3414
  });
3240
3415
  }
3241
3416
  },
3242
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3417
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
3243
3418
  scrollToItem: ({ item, ...props }) => {
3244
3419
  const data = state.props.data;
3245
3420
  const index = data.indexOf(item);
3246
3421
  if (index !== -1) {
3247
- scrollToIndex(ctx, state, { index, ...props });
3422
+ scrollToIndex(ctx, { index, ...props });
3248
3423
  }
3249
3424
  },
3250
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3425
+ scrollToOffset: (params) => scrollTo(ctx, params),
3251
3426
  setScrollProcessingEnabled: (enabled) => {
3252
3427
  state.scrollProcessingEnabled = enabled;
3253
3428
  },
@@ -3257,8 +3432,9 @@ function createImperativeHandle(ctx, state) {
3257
3432
  }
3258
3433
  };
3259
3434
  }
3260
- function getRenderedItem(ctx, state, key) {
3435
+ function getRenderedItem(ctx, key) {
3261
3436
  var _a3;
3437
+ const state = ctx.state;
3262
3438
  if (!state) {
3263
3439
  return null;
3264
3440
  }
@@ -3335,11 +3511,13 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3335
3511
  var DEFAULT_DRAW_DISTANCE = 250;
3336
3512
  var DEFAULT_ITEM_SIZE = 100;
3337
3513
  var LegendList = typedMemo(
3514
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3338
3515
  typedForwardRef(function LegendList2(props, forwardedRef) {
3339
3516
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3340
3517
  const isChildrenMode = children !== void 0 && dataProp === void 0;
3341
3518
  const processedProps = isChildrenMode ? {
3342
3519
  ...restProps,
3520
+ childrenMode: true,
3343
3521
  data: (isArray(children) ? children : React3__namespace.Children.toArray(children)).flat(1),
3344
3522
  renderItem: ({ item }) => item
3345
3523
  } : {
@@ -3356,10 +3534,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3356
3534
  alignItemsAtEnd = false,
3357
3535
  columnWrapperStyle,
3358
3536
  contentContainerStyle: contentContainerStyleProp,
3537
+ contentInset,
3359
3538
  data: dataProp = [],
3360
3539
  dataVersion,
3361
3540
  drawDistance = 250,
3362
- enableAverages = true,
3363
3541
  estimatedItemSize: estimatedItemSizeProp,
3364
3542
  estimatedListSize,
3365
3543
  extraData,
@@ -3401,6 +3579,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3401
3579
  snapToIndices,
3402
3580
  stickyHeaderIndices: stickyHeaderIndicesProp,
3403
3581
  stickyIndices: stickyIndicesDeprecated,
3582
+ // TODOV3: Remove from v3 release
3404
3583
  style: styleProp,
3405
3584
  suggestEstimatedItemSize,
3406
3585
  viewabilityConfig,
@@ -3408,6 +3587,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3408
3587
  waitForInitialLayout = true,
3409
3588
  ...rest
3410
3589
  } = props;
3590
+ const animatedPropsInternal = props.animatedPropsInternal;
3591
+ const { childrenMode } = rest;
3411
3592
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3412
3593
  const style = { ...StyleSheet.flatten(styleProp) };
3413
3594
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
@@ -3431,10 +3612,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3431
3612
  }
3432
3613
  const refState = React3.useRef();
3433
3614
  if (!refState.current) {
3434
- if (!ctx.internalState) {
3615
+ if (!ctx.state) {
3435
3616
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
3436
- ctx.internalState = {
3437
- activeStickyIndex: void 0,
3617
+ ctx.state = {
3618
+ activeStickyIndex: -1,
3438
3619
  averageSizes: {},
3439
3620
  columns: /* @__PURE__ */ new Map(),
3440
3621
  containerItemKeys: /* @__PURE__ */ new Set(),
@@ -3460,9 +3641,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3460
3641
  initialScroll: initialScrollProp,
3461
3642
  isAtEnd: false,
3462
3643
  isAtStart: false,
3463
- isEndReached: false,
3644
+ isEndReached: null,
3464
3645
  isFirst: true,
3465
- isStartReached: false,
3646
+ isStartReached: null,
3466
3647
  lastBatchingAction: Date.now(),
3467
3648
  lastLayout: void 0,
3468
3649
  loadStartTime: Date.now(),
@@ -3494,12 +3675,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3494
3675
  totalSize: 0,
3495
3676
  viewabilityConfigCallbackPairs: void 0
3496
3677
  };
3497
- const internalState = ctx.internalState;
3498
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3678
+ const internalState = ctx.state;
3679
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3499
3680
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3500
3681
  set$(ctx, "extraData", extraData);
3501
3682
  }
3502
- refState.current = ctx.internalState;
3683
+ refState.current = ctx.state;
3503
3684
  }
3504
3685
  const state = refState.current;
3505
3686
  const isFirstLocal = state.isFirst;
@@ -3513,9 +3694,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3513
3694
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3514
3695
  state.props = {
3515
3696
  alignItemsAtEnd,
3697
+ animatedProps: animatedPropsInternal,
3698
+ contentInset,
3516
3699
  data: dataProp,
3517
3700
  dataVersion,
3518
- enableAverages,
3519
3701
  estimatedItemSize,
3520
3702
  getEstimatedItemSize,
3521
3703
  getFixedItemSize,
@@ -3558,62 +3740,52 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3558
3740
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3559
3741
  set$(ctx, "numColumns", numColumnsProp);
3560
3742
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3561
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3743
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3562
3744
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3563
3745
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3564
3746
  if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3565
3747
  if (state.scroll < 0) {
3566
3748
  paddingDiff += state.scroll;
3567
3749
  }
3568
- requestAdjust(ctx, state, paddingDiff);
3750
+ requestAdjust(ctx, paddingDiff);
3569
3751
  }
3570
3752
  };
3571
3753
  if (isFirstLocal) {
3572
3754
  initializeStateVars();
3573
3755
  updateItemPositions(
3574
3756
  ctx,
3575
- state,
3576
3757
  /*dataChanged*/
3577
3758
  true
3578
3759
  );
3579
3760
  }
3580
3761
  const initialContentOffset = React3.useMemo(() => {
3581
- var _a4, _b2;
3582
- const { initialScroll } = refState.current;
3583
- if (!initialScroll) {
3762
+ let value;
3763
+ const { initialScroll, initialAnchor } = refState.current;
3764
+ if (initialScroll) {
3765
+ if (initialScroll.contentOffset !== void 0) {
3766
+ value = initialScroll.contentOffset;
3767
+ } else {
3768
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3769
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3770
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3771
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3772
+ refState.current.initialScroll = updatedInitialScroll;
3773
+ state.initialScroll = updatedInitialScroll;
3774
+ value = clampedOffset;
3775
+ }
3776
+ } else {
3584
3777
  refState.current.initialAnchor = void 0;
3585
- return 0;
3586
- }
3587
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3588
- refState.current.initialAnchor = {
3589
- attempts: 0,
3590
- index: initialScroll.index,
3591
- settledTicks: 0,
3592
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3593
- viewPosition: initialScroll.viewPosition
3594
- };
3778
+ value = 0;
3595
3779
  }
3596
- if (initialScroll.contentOffset !== void 0) {
3597
- return initialScroll.contentOffset;
3598
- }
3599
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3600
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3601
- let clampedOffset = resolvedOffset;
3602
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3603
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3604
- clampedOffset = Math.min(clampedOffset, maxOffset);
3605
- }
3606
- clampedOffset = Math.max(0, clampedOffset);
3607
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3608
- refState.current.initialScroll = updatedInitialScroll;
3609
- state.initialScroll = updatedInitialScroll;
3610
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3611
- return clampedOffset;
3780
+ if (!value) {
3781
+ state.didFinishInitialScroll = true;
3782
+ }
3783
+ return value;
3612
3784
  }, [renderNum]);
3613
3785
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3614
3786
  refState.current.lastBatchingAction = Date.now();
3615
3787
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3616
- IS_DEV && warnDevOnce(
3788
+ IS_DEV && !childrenMode && warnDevOnce(
3617
3789
  "keyExtractor",
3618
3790
  "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."
3619
3791
  );
@@ -3636,12 +3808,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3636
3808
  }
3637
3809
  }, []);
3638
3810
  const doInitialScroll = React3.useCallback(() => {
3639
- var _a4;
3640
3811
  const initialScroll = state.initialScroll;
3641
3812
  if (initialScroll) {
3642
- scrollTo(ctx, state, {
3813
+ scrollTo(ctx, {
3643
3814
  animated: false,
3644
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3815
+ index: initialScroll == null ? void 0 : initialScroll.index,
3645
3816
  isInitialScroll: true,
3646
3817
  offset: initialContentOffset,
3647
3818
  precomputedWithViewOffset: true
@@ -3650,7 +3821,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3650
3821
  }, [initialContentOffset]);
3651
3822
  const onLayoutChange = React3.useCallback((layout) => {
3652
3823
  doInitialScroll();
3653
- handleLayout(ctx, state, layout, setCanRender);
3824
+ handleLayout(ctx, layout, setCanRender);
3654
3825
  }, []);
3655
3826
  const { onLayout } = useOnLayoutSync({
3656
3827
  onLayoutChange,
@@ -3660,7 +3831,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3660
3831
  });
3661
3832
  React3.useLayoutEffect(() => {
3662
3833
  if (snapToIndices) {
3663
- updateSnapToOffsets(ctx, state);
3834
+ updateSnapToOffsets(ctx);
3664
3835
  }
3665
3836
  }, [snapToIndices]);
3666
3837
  React3.useLayoutEffect(() => {
@@ -3670,9 +3841,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3670
3841
  isFirst,
3671
3842
  props: { data }
3672
3843
  } = state;
3673
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3844
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3674
3845
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3675
- checkResetContainers(ctx, state, data);
3846
+ checkResetContainers(ctx, data);
3676
3847
  }
3677
3848
  state.didColumnsChange = false;
3678
3849
  state.didDataChange = false;
@@ -3697,15 +3868,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3697
3868
  state.viewabilityConfigCallbackPairs = viewability;
3698
3869
  state.enableScrollForNextCalculateItemsInView = !viewability;
3699
3870
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3700
- React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3871
+ React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3701
3872
  {
3702
3873
  React3.useEffect(doInitialScroll, []);
3703
3874
  }
3704
3875
  const fns = React3.useMemo(
3705
3876
  () => ({
3706
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3707
- onScroll: (event) => onScroll(ctx, state, event),
3708
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3877
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
3878
+ onMomentumScrollEnd: (event) => {
3879
+ checkFinishedScrollFallback(ctx);
3880
+ if (onMomentumScrollEnd) {
3881
+ onMomentumScrollEnd(event);
3882
+ }
3883
+ },
3884
+ onScroll: (event) => onScroll(ctx, event),
3885
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3709
3886
  }),
3710
3887
  []
3711
3888
  );
@@ -3717,6 +3894,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3717
3894
  alignItemsAtEnd,
3718
3895
  canRender,
3719
3896
  contentContainerStyle,
3897
+ contentInset,
3720
3898
  getRenderedItem: fns.getRenderedItem,
3721
3899
  horizontal,
3722
3900
  initialContentOffset,
@@ -3725,16 +3903,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3725
3903
  maintainVisibleContentPosition,
3726
3904
  onLayout,
3727
3905
  onLayoutHeader,
3728
- onMomentumScrollEnd: (event) => {
3729
- {
3730
- requestAnimationFrame(() => {
3731
- finishScrollTo(ctx, refState.current);
3732
- });
3733
- }
3734
- if (onMomentumScrollEnd) {
3735
- onMomentumScrollEnd(event);
3736
- }
3737
- },
3906
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3738
3907
  onScroll: onScrollHandler,
3739
3908
  recycleItems,
3740
3909
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControl, {
@@ -3749,7 +3918,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3749
3918
  ),
3750
3919
  refScrollView: combinedRef,
3751
3920
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3752
- scrollEventThrottle: 16 ,
3921
+ scrollEventThrottle: 0,
3753
3922
  snapToIndices,
3754
3923
  stickyHeaderIndices,
3755
3924
  style,