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

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