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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/section-list.mjs CHANGED
@@ -13,31 +13,65 @@ var View = forwardRef(function View2(props, ref) {
13
13
  });
14
14
  var Text = View;
15
15
 
16
+ // src/state/getContentInsetEnd.ts
17
+ function getContentInsetEnd(state) {
18
+ var _a3;
19
+ const { props } = state;
20
+ const horizontal = props.horizontal;
21
+ let contentInset = props.contentInset;
22
+ if (!contentInset) {
23
+ const animatedInset = (_a3 = props.animatedProps) == null ? void 0 : _a3.contentInset;
24
+ if (animatedInset) {
25
+ if ("get" in animatedInset) {
26
+ contentInset = animatedInset.get();
27
+ } else {
28
+ contentInset = animatedInset;
29
+ }
30
+ }
31
+ }
32
+ return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
33
+ }
34
+
35
+ // src/state/getContentSize.ts
36
+ function getContentSize(ctx) {
37
+ var _a3;
38
+ const { values, state } = ctx;
39
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
40
+ const stylePaddingBottom = state.props.stylePaddingBottom || 0;
41
+ const headerSize = values.get("headerSize") || 0;
42
+ const footerSize = values.get("footerSize") || 0;
43
+ const contentInsetBottom = getContentInsetEnd(state);
44
+ const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
45
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
46
+ }
47
+
16
48
  // src/platform/Animated.tsx
17
49
  var createAnimatedValue = (value) => value;
18
50
 
19
51
  // src/state/state.tsx
20
52
  var ContextState = React3.createContext(null);
53
+ var contextNum = 0;
21
54
  function StateProvider({ children }) {
22
55
  const [value] = React3.useState(() => ({
23
56
  animatedScrollY: createAnimatedValue(0),
24
57
  columnWrapperStyle: void 0,
25
- internalState: void 0,
58
+ contextNum: contextNum++,
26
59
  listeners: /* @__PURE__ */ new Map(),
27
60
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
28
61
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
29
62
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
30
63
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
31
64
  mapViewabilityValues: /* @__PURE__ */ new Map(),
65
+ positionListeners: /* @__PURE__ */ new Map(),
66
+ state: void 0,
32
67
  values: /* @__PURE__ */ new Map([
33
68
  ["alignItemsPaddingTop", 0],
34
69
  ["stylePaddingTop", 0],
35
70
  ["headerSize", 0],
36
71
  ["numContainers", 0],
37
- ["activeStickyIndex", void 0],
72
+ ["activeStickyIndex", -1],
38
73
  ["totalSize", 0],
39
- ["scrollAdjustPending", 0],
40
- ["scrollingTo", void 0]
74
+ ["scrollAdjustPending", 0]
41
75
  ]),
42
76
  viewRefs: /* @__PURE__ */ new Map()
43
77
  }));
@@ -105,14 +139,24 @@ function set$(ctx, signalName, value) {
105
139
  }
106
140
  }
107
141
  }
108
- function getContentSize(ctx) {
109
- var _a3, _b;
110
- const { values } = ctx;
111
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
112
- const headerSize = values.get("headerSize") || 0;
113
- const footerSize = values.get("footerSize") || 0;
114
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
115
- return headerSize + footerSize + totalSize + stylePaddingTop;
142
+ function listenPosition$(ctx, key, cb) {
143
+ const { positionListeners } = ctx;
144
+ let setListeners = positionListeners.get(key);
145
+ if (!setListeners) {
146
+ setListeners = /* @__PURE__ */ new Set();
147
+ positionListeners.set(key, setListeners);
148
+ }
149
+ setListeners.add(cb);
150
+ return () => setListeners.delete(cb);
151
+ }
152
+ function notifyPosition$(ctx, key, value) {
153
+ const { positionListeners } = ctx;
154
+ const setListeners = positionListeners.get(key);
155
+ if (setListeners) {
156
+ for (const listener of setListeners) {
157
+ listener(value);
158
+ }
159
+ }
116
160
  }
117
161
  function useArr$(signalNames) {
118
162
  const ctx = React3.useContext(ContextState);
@@ -234,12 +278,12 @@ function findContainerId(ctx, key) {
234
278
  }
235
279
 
236
280
  // src/components/PositionView.tsx
237
- var PositionViewState = typedMemo(function PositionView({
281
+ var PositionViewState = typedMemo(function PositionViewState2({
238
282
  id,
239
283
  horizontal,
240
284
  style,
241
285
  refView,
242
- ...rest
286
+ ...props
243
287
  }) {
244
288
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
245
289
  const base = {
@@ -247,7 +291,8 @@ var PositionViewState = typedMemo(function PositionView({
247
291
  };
248
292
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
249
293
  const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
250
- return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: combinedStyle, ...rest });
294
+ const { animatedScrollY, stickyOffset, onLayout, ...webProps } = props;
295
+ return /* @__PURE__ */ React3.createElement("div", { ref: refView, ...webProps, style: combinedStyle });
251
296
  });
252
297
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
253
298
  id,
@@ -292,7 +337,7 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
292
337
  }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
293
338
  return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
294
339
  });
295
- var PositionView2 = PositionViewState;
340
+ var PositionView = PositionViewState;
296
341
 
297
342
  // src/constants-platform.ts
298
343
  var IsNewArchitecture = true;
@@ -347,10 +392,9 @@ function createResizeObserver(element, callback) {
347
392
  }
348
393
  callbacks.add(callback);
349
394
  return () => {
350
- const callbacks2 = callbackMap.get(element);
351
- if (callbacks2) {
352
- callbacks2.delete(callback);
353
- if (callbacks2.size === 0) {
395
+ if (callbacks) {
396
+ callbacks.delete(callback);
397
+ if (callbacks.size === 0) {
354
398
  callbackMap.delete(element);
355
399
  observer.unobserve(element);
356
400
  }
@@ -385,10 +429,10 @@ function useOnLayoutSync({
385
429
  return createResizeObserver(element, (entry) => {
386
430
  var _a4;
387
431
  const target = entry.target instanceof HTMLElement ? entry.target : void 0;
388
- const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
389
- if (rect2.width !== prevRect.width || rect2.height !== prevRect.height) {
390
- prevRect = rect2;
391
- emit(toLayout(rect2), false);
432
+ const rectObserved = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
433
+ if (rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height) {
434
+ prevRect = rectObserved;
435
+ emit(toLayout(rectObserved), false);
392
436
  }
393
437
  });
394
438
  }, deps || []);
@@ -516,7 +560,7 @@ var Container = typedMemo(function Container2({
516
560
  },
517
561
  [itemKey, layoutRenderCount]
518
562
  );
519
- const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
563
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
520
564
  return /* @__PURE__ */ React3.createElement(
521
565
  PositionComponent,
522
566
  {
@@ -709,7 +753,8 @@ var Containers = typedMemo(function Containers2({
709
753
  return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
710
754
  });
711
755
  function DevNumbers() {
712
- return IS_DEV && React3.memo(function DevNumbers2() {
756
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
757
+ React3.memo(function DevNumbers2() {
713
758
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3.createElement(
714
759
  "div",
715
760
  {
@@ -757,7 +802,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
757
802
  }, ref) {
758
803
  const scrollRef = useRef(null);
759
804
  const contentRef = useRef(null);
760
- const momentumTimeout = useRef(null);
761
805
  useImperativeHandle(ref, () => {
762
806
  const api = {
763
807
  getBoundingClientRect: () => {
@@ -823,16 +867,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
823
867
  }
824
868
  };
825
869
  onScroll2(scrollEvent);
826
- if (onMomentumScrollEnd) {
827
- if (momentumTimeout.current != null) clearTimeout(momentumTimeout.current);
828
- momentumTimeout.current = setTimeout(() => {
829
- onMomentumScrollEnd({
830
- nativeEvent: {
831
- contentOffset: scrollEvent.nativeEvent.contentOffset
832
- }
833
- });
834
- }, 100);
835
- }
836
870
  },
837
871
  [onScroll2, onMomentumScrollEnd]
838
872
  );
@@ -894,7 +928,8 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
894
928
  minWidth: horizontal ? "100%" : void 0,
895
929
  ...StyleSheet.flatten(contentContainerStyle)
896
930
  };
897
- return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
931
+ const { contentInset, scrollEventThrottle, ScrollComponent, ...webProps } = props;
932
+ return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
898
933
  });
899
934
  function Padding() {
900
935
  const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
@@ -935,7 +970,7 @@ function ScrollAdjust() {
935
970
  const scrollAdjust = peek$(ctx, "scrollAdjust");
936
971
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
937
972
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
938
- const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
973
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
939
974
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
940
975
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
941
976
  if (scrollDelta !== 0) {
@@ -943,16 +978,16 @@ function ScrollAdjust() {
943
978
  const prevScroll = el.scrollTop;
944
979
  const nextScroll = prevScroll + scrollDelta;
945
980
  const totalSize = el.scrollHeight;
946
- if (scrollDelta > 0 && !ctx.internalState.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
981
+ if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
947
982
  const child = el.firstElementChild;
948
983
  const prevPaddingBottom = child.style.paddingBottom;
949
984
  const pad = (nextScroll + el.clientHeight - totalSize) * 2;
950
985
  child.style.paddingBottom = `${pad}px`;
951
986
  void el.offsetHeight;
952
987
  scrollView.scrollBy(0, scrollDelta);
953
- setTimeout(() => {
988
+ requestAnimationFrame(() => {
954
989
  child.style.paddingBottom = prevPaddingBottom;
955
- }, 100);
990
+ });
956
991
  } else {
957
992
  scrollView.scrollBy(0, scrollDelta);
958
993
  }
@@ -962,7 +997,7 @@ function ScrollAdjust() {
962
997
  }
963
998
  lastScrollOffsetRef.current = scrollOffset;
964
999
  }
965
- }, []);
1000
+ }, [ctx]);
966
1001
  useValueListener$("scrollAdjust", callback);
967
1002
  useValueListener$("scrollAdjustUserOffset", callback);
968
1003
  return null;
@@ -1020,13 +1055,6 @@ var ListComponent = typedMemo(function ListComponent2({
1020
1055
  () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1021
1056
  [renderScrollComponent]
1022
1057
  ) : ListComponentScrollView;
1023
- React3.useEffect(() => {
1024
- if (canRender) {
1025
- setTimeout(() => {
1026
- scrollAdjustHandler.setMounted();
1027
- }, 0);
1028
- }
1029
- }, [canRender]);
1030
1058
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1031
1059
  return /* @__PURE__ */ React3.createElement(
1032
1060
  SnapOrScroll,
@@ -1090,10 +1118,11 @@ function getId(state, index) {
1090
1118
  }
1091
1119
 
1092
1120
  // src/core/calculateOffsetForIndex.ts
1093
- function calculateOffsetForIndex(ctx, state, index) {
1121
+ function calculateOffsetForIndex(ctx, index) {
1122
+ const state = ctx.state;
1094
1123
  let position = 0;
1095
1124
  if (index !== void 0) {
1096
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
1125
+ position = state.positions.get(getId(state, index)) || 0;
1097
1126
  const paddingTop = peek$(ctx, "stylePaddingTop");
1098
1127
  if (paddingTop) {
1099
1128
  position += paddingTop;
@@ -1107,7 +1136,8 @@ function calculateOffsetForIndex(ctx, state, index) {
1107
1136
  }
1108
1137
 
1109
1138
  // src/utils/setPaddingTop.ts
1110
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1139
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1140
+ const state = ctx.state;
1111
1141
  if (stylePaddingTop !== void 0) {
1112
1142
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1113
1143
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -1126,7 +1156,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1126
1156
  }
1127
1157
 
1128
1158
  // src/utils/updateAlignItemsPaddingTop.ts
1129
- function updateAlignItemsPaddingTop(ctx, state) {
1159
+ function updateAlignItemsPaddingTop(ctx) {
1160
+ const state = ctx.state;
1130
1161
  const {
1131
1162
  scrollLength,
1132
1163
  props: { alignItemsAtEnd, data }
@@ -1137,12 +1168,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
1137
1168
  const contentSize = getContentSize(ctx);
1138
1169
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1139
1170
  }
1140
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1171
+ setPaddingTop(ctx, { alignItemsPaddingTop });
1141
1172
  }
1142
1173
  }
1143
1174
 
1144
1175
  // src/core/addTotalSize.ts
1145
- function addTotalSize(ctx, state, key, add) {
1176
+ function addTotalSize(ctx, key, add) {
1177
+ const state = ctx.state;
1146
1178
  const { alignItemsAtEnd } = state.props;
1147
1179
  const prevTotalSize = state.totalSize;
1148
1180
  let totalSize = state.totalSize;
@@ -1161,31 +1193,34 @@ function addTotalSize(ctx, state, key, add) {
1161
1193
  state.totalSize = totalSize;
1162
1194
  set$(ctx, "totalSize", totalSize);
1163
1195
  if (alignItemsAtEnd) {
1164
- updateAlignItemsPaddingTop(ctx, state);
1196
+ updateAlignItemsPaddingTop(ctx);
1165
1197
  }
1166
1198
  }
1167
1199
  }
1168
1200
  }
1169
1201
 
1170
1202
  // src/core/setSize.ts
1171
- function setSize(ctx, state, itemKey, size) {
1203
+ function setSize(ctx, itemKey, size) {
1204
+ const state = ctx.state;
1172
1205
  const { sizes } = state;
1173
1206
  const previousSize = sizes.get(itemKey);
1174
1207
  const diff = previousSize !== void 0 ? size - previousSize : size;
1175
1208
  if (diff !== 0) {
1176
- addTotalSize(ctx, state, itemKey, diff);
1209
+ addTotalSize(ctx, itemKey, diff);
1177
1210
  }
1178
1211
  sizes.set(itemKey, size);
1179
1212
  }
1180
1213
 
1181
1214
  // src/utils/getItemSize.ts
1182
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1215
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1183
1216
  var _a3, _b;
1217
+ const state = ctx.state;
1184
1218
  const {
1185
1219
  sizesKnown,
1186
1220
  sizes,
1187
1221
  averageSizes,
1188
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1222
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1223
+ scrollingTo
1189
1224
  } = state;
1190
1225
  const sizeKnown = sizesKnown.get(key);
1191
1226
  if (sizeKnown !== void 0) {
@@ -1193,7 +1228,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1193
1228
  }
1194
1229
  let size;
1195
1230
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1196
- const scrollingTo = peek$(ctx, "scrollingTo");
1197
1231
  if (preferCachedSize) {
1198
1232
  const cachedSize = sizes.get(key);
1199
1233
  if (cachedSize !== void 0) {
@@ -1221,81 +1255,169 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1221
1255
  if (size === void 0) {
1222
1256
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1223
1257
  }
1224
- setSize(ctx, state, key, size);
1258
+ setSize(ctx, key, size);
1225
1259
  return size;
1226
1260
  }
1227
1261
 
1228
1262
  // src/core/calculateOffsetWithOffsetPosition.ts
1229
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1263
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1264
+ const state = ctx.state;
1230
1265
  const { index, viewOffset, viewPosition } = params;
1231
1266
  let offset = offsetParam;
1232
1267
  if (viewOffset) {
1233
1268
  offset -= viewOffset;
1234
1269
  }
1235
1270
  if (viewPosition !== void 0 && index !== void 0) {
1236
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1271
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1272
+ const trailingInset = getContentInsetEnd(state);
1273
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1237
1274
  }
1238
1275
  return offset;
1239
1276
  }
1240
1277
 
1278
+ // src/core/clampScrollOffset.ts
1279
+ function clampScrollOffset(ctx, offset) {
1280
+ const state = ctx.state;
1281
+ const contentSize = getContentSize(ctx);
1282
+ let clampedOffset = offset;
1283
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1284
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1285
+ clampedOffset = Math.min(offset, maxOffset);
1286
+ }
1287
+ clampedOffset = Math.max(0, clampedOffset);
1288
+ return clampedOffset;
1289
+ }
1290
+
1291
+ // src/utils/setInitialRenderState.ts
1292
+ function setInitialRenderState(ctx, {
1293
+ didLayout,
1294
+ didInitialScroll
1295
+ }) {
1296
+ const { state } = ctx;
1297
+ if (didLayout) {
1298
+ state.didContainersLayout = true;
1299
+ }
1300
+ if (didInitialScroll) {
1301
+ state.didFinishInitialScroll = true;
1302
+ }
1303
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1304
+ set$(ctx, "readyToRender", true);
1305
+ }
1306
+ }
1307
+
1241
1308
  // src/core/finishScrollTo.ts
1242
- function finishScrollTo(ctx, state) {
1309
+ function finishScrollTo(ctx) {
1243
1310
  var _a3, _b;
1244
- if (state) {
1311
+ const state = ctx.state;
1312
+ if (state == null ? void 0 : state.scrollingTo) {
1245
1313
  state.scrollHistory.length = 0;
1246
1314
  state.initialScroll = void 0;
1247
1315
  state.initialAnchor = void 0;
1248
- set$(ctx, "scrollingTo", void 0);
1316
+ state.scrollingTo = void 0;
1249
1317
  if (state.pendingTotalSize !== void 0) {
1250
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1318
+ addTotalSize(ctx, null, state.pendingTotalSize);
1251
1319
  }
1252
1320
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1253
1321
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1254
1322
  }
1323
+ {
1324
+ state.scrollAdjustHandler.commitPendingAdjust();
1325
+ }
1326
+ setInitialRenderState(ctx, { didInitialScroll: true });
1327
+ }
1328
+ }
1329
+
1330
+ // src/core/doScrollTo.ts
1331
+ var SCROLL_END_IDLE_MS = 80;
1332
+ var SCROLL_END_MAX_MS = 1500;
1333
+ var SMOOTH_SCROLL_DURATION_MS = 320;
1334
+ function doScrollTo(ctx, params) {
1335
+ const state = ctx.state;
1336
+ const { animated, horizontal, offset } = params;
1337
+ const scroller = state.refScroller.current;
1338
+ const node = typeof (scroller == null ? void 0 : scroller.getScrollableNode) === "function" ? scroller.getScrollableNode() : scroller;
1339
+ if (node) {
1340
+ const left = horizontal ? offset : 0;
1341
+ const top = horizontal ? 0 : offset;
1342
+ node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1343
+ if (animated) {
1344
+ listenForScrollEnd(ctx, node);
1345
+ } else {
1346
+ state.scroll = offset;
1347
+ setTimeout(() => {
1348
+ finishScrollTo(ctx);
1349
+ }, 100);
1350
+ }
1351
+ }
1352
+ }
1353
+ function listenForScrollEnd(ctx, node) {
1354
+ const supportsScrollEnd = "onscrollend" in node;
1355
+ let idleTimeout;
1356
+ let maxTimeout;
1357
+ let settled = false;
1358
+ const targetToken = ctx.state.scrollingTo;
1359
+ const finish = () => {
1360
+ if (settled) return;
1361
+ settled = true;
1362
+ cleanup();
1363
+ if (targetToken === ctx.state.scrollingTo) {
1364
+ finishScrollTo(ctx);
1365
+ }
1366
+ };
1367
+ const onScroll2 = () => {
1368
+ if (idleTimeout) {
1369
+ clearTimeout(idleTimeout);
1370
+ }
1371
+ idleTimeout = setTimeout(finish, SCROLL_END_IDLE_MS);
1372
+ };
1373
+ const cleanup = () => {
1374
+ if (supportsScrollEnd) {
1375
+ node.removeEventListener("scrollend", finish);
1376
+ } else {
1377
+ node.removeEventListener("scroll", onScroll2);
1378
+ }
1379
+ if (idleTimeout) {
1380
+ clearTimeout(idleTimeout);
1381
+ }
1382
+ if (maxTimeout) {
1383
+ clearTimeout(maxTimeout);
1384
+ }
1385
+ };
1386
+ if (supportsScrollEnd) {
1387
+ node.addEventListener("scrollend", finish, { once: true });
1388
+ } else {
1389
+ node.addEventListener("scroll", onScroll2);
1390
+ idleTimeout = setTimeout(finish, SMOOTH_SCROLL_DURATION_MS);
1391
+ maxTimeout = setTimeout(finish, SCROLL_END_MAX_MS);
1255
1392
  }
1393
+ return cleanup;
1256
1394
  }
1257
1395
 
1258
1396
  // src/core/scrollTo.ts
1259
- function scrollTo(ctx, state, params) {
1260
- var _a3;
1261
- const { noScrollingTo, ...scrollTarget } = params;
1397
+ function scrollTo(ctx, params) {
1398
+ const state = ctx.state;
1399
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1262
1400
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1263
1401
  const {
1264
- refScroller,
1265
1402
  props: { horizontal }
1266
1403
  } = state;
1267
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1268
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1269
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1270
- offset = Math.min(offset, maxOffset);
1404
+ if (state.animFrameCheckFinishedScroll) {
1405
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1271
1406
  }
1407
+ if (state.timeoutCheckFinishedScrollFallback) {
1408
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1409
+ }
1410
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1411
+ offset = clampScrollOffset(ctx, offset);
1272
1412
  state.scrollHistory.length = 0;
1273
1413
  if (!noScrollingTo) {
1274
- set$(ctx, "scrollingTo", scrollTarget);
1414
+ state.scrollingTo = scrollTarget;
1275
1415
  }
1276
1416
  state.scrollPending = offset;
1277
- if (!isInitialScroll || Platform.OS === "android") {
1278
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1279
- animated: !!animated,
1280
- x: horizontal ? offset : 0,
1281
- y: horizontal ? 0 : offset
1282
- });
1283
- }
1284
- if (!animated) {
1417
+ if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1418
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1419
+ } else {
1285
1420
  state.scroll = offset;
1286
- {
1287
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1288
- if (value && peek$(ctx, "scrollingTo")) {
1289
- finishScrollTo(ctx, state);
1290
- unlisten();
1291
- }
1292
- });
1293
- }
1294
- if (isInitialScroll) {
1295
- setTimeout(() => {
1296
- state.initialScroll = void 0;
1297
- }, 500);
1298
- }
1299
1421
  }
1300
1422
  }
1301
1423
 
@@ -1304,6 +1426,12 @@ var HYSTERESIS_MULTIPLIER = 1.3;
1304
1426
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1305
1427
  const absDistance = Math.abs(distance);
1306
1428
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1429
+ if (wasReached === null) {
1430
+ if (!within && distance >= 0) {
1431
+ return false;
1432
+ }
1433
+ return null;
1434
+ }
1307
1435
  const updateSnapshot = () => {
1308
1436
  setSnapshot == null ? void 0 : setSnapshot({
1309
1437
  atThreshold,
@@ -1336,8 +1464,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1336
1464
  };
1337
1465
 
1338
1466
  // src/utils/checkAtBottom.ts
1339
- function checkAtBottom(ctx, state) {
1467
+ function checkAtBottom(ctx) {
1340
1468
  var _a3;
1469
+ const state = ctx.state;
1341
1470
  if (!state) {
1342
1471
  return;
1343
1472
  }
@@ -1410,15 +1539,15 @@ function checkAtTop(state) {
1410
1539
  }
1411
1540
 
1412
1541
  // src/core/updateScroll.ts
1413
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1542
+ function updateScroll(ctx, newScroll, forceUpdate) {
1414
1543
  var _a3;
1415
- const scrollingTo = peek$(ctx, "scrollingTo");
1544
+ const state = ctx.state;
1545
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1416
1546
  state.hasScrolled = true;
1417
1547
  state.lastBatchingAction = Date.now();
1418
1548
  const currentTime = Date.now();
1419
- const adjust = state.scrollAdjustHandler.getAdjust();
1420
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1421
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1549
+ const adjust = scrollAdjustHandler.getAdjust();
1550
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1422
1551
  if (adjustChanged) {
1423
1552
  state.scrollHistory.length = 0;
1424
1553
  }
@@ -1443,17 +1572,21 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1443
1572
  return;
1444
1573
  }
1445
1574
  }
1446
- if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1575
+ const lastCalculated = state.scrollLastCalculate;
1576
+ const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1577
+ if (shouldUpdate) {
1578
+ state.scrollLastCalculate = state.scroll;
1447
1579
  state.ignoreScrollFromMVCPIgnored = false;
1448
1580
  (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1449
- checkAtBottom(ctx, state);
1581
+ checkAtBottom(ctx);
1450
1582
  checkAtTop(state);
1451
1583
  state.dataChangeNeedsScrollUpdate = false;
1452
1584
  }
1453
1585
  }
1454
1586
 
1455
1587
  // src/utils/requestAdjust.ts
1456
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1588
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1589
+ const state = ctx.state;
1457
1590
  if (Math.abs(positionDiff) > 0.1) {
1458
1591
  const doit = () => {
1459
1592
  {
@@ -1465,8 +1598,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1465
1598
  };
1466
1599
  state.scroll += positionDiff;
1467
1600
  state.scrollForNextCalculateItemsInView = void 0;
1468
- const didLayout = peek$(ctx, "containersDidLayout");
1469
- if (didLayout) {
1601
+ const readyToRender = peek$(ctx, "readyToRender");
1602
+ if (readyToRender) {
1470
1603
  doit();
1471
1604
  } else {
1472
1605
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -1475,73 +1608,23 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1475
1608
  }
1476
1609
  }
1477
1610
 
1478
- // src/core/ensureInitialAnchor.ts
1479
- var INITIAL_ANCHOR_TOLERANCE = 0.5;
1480
- var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1481
- var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1482
- function ensureInitialAnchor(ctx, state) {
1483
- var _a3, _b, _c, _d, _e;
1484
- const anchor = state.initialAnchor;
1485
- const item = state.props.data[anchor.index];
1486
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1487
- if (!containersDidLayout) {
1488
- return;
1489
- }
1490
- const id = getId(state, anchor.index);
1491
- if (state.positions.get(id) === void 0) {
1492
- return;
1493
- }
1494
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1495
- if (size === void 0) {
1496
- return;
1497
- }
1498
- const availableSpace = Math.max(0, state.scrollLength - size);
1499
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1500
- const contentSize = getContentSize(ctx);
1501
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1502
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1503
- const delta = clampedDesiredOffset - state.scroll;
1504
- if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1505
- const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1506
- if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1507
- state.initialAnchor = void 0;
1508
- } else {
1509
- anchor.settledTicks = settledTicks;
1510
- }
1511
- return;
1512
- }
1513
- if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1514
- state.initialAnchor = void 0;
1515
- return;
1516
- }
1517
- const lastDelta = anchor.lastDelta;
1518
- if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1519
- state.initialAnchor = void 0;
1520
- return;
1521
- }
1522
- Object.assign(anchor, {
1523
- attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1524
- lastDelta: delta,
1525
- settledTicks: 0
1526
- });
1527
- requestAdjust(ctx, state, delta);
1528
- }
1529
-
1530
1611
  // src/core/mvcp.ts
1531
- function prepareMVCP(ctx, state, dataChanged) {
1612
+ function prepareMVCP(ctx, dataChanged) {
1613
+ const state = ctx.state;
1532
1614
  const { idsInView, positions, props } = state;
1533
1615
  const { maintainVisibleContentPosition } = props;
1534
- const scrollingTo = peek$(ctx, "scrollingTo");
1616
+ const scrollingTo = state.scrollingTo;
1535
1617
  let prevPosition;
1536
1618
  let targetId;
1537
1619
  const idsInViewWithPositions = [];
1538
1620
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1621
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1539
1622
  const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1540
1623
  const indexByKey = state.indexByKey;
1541
1624
  if (shouldMVCP) {
1542
1625
  if (scrollTarget !== void 0) {
1543
1626
  targetId = getId(state, scrollTarget);
1544
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1627
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1545
1628
  if (dataChanged) {
1546
1629
  for (let i = 0; i < idsInView.length; i++) {
1547
1630
  const id = idsInView[i];
@@ -1558,7 +1641,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1558
1641
  prevPosition = positions.get(targetId);
1559
1642
  }
1560
1643
  return () => {
1561
- let positionDiff;
1644
+ let positionDiff = 0;
1562
1645
  if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1563
1646
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1564
1647
  const { id, position } = idsInViewWithPositions[i];
@@ -1584,16 +1667,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1584
1667
  positionDiff = diff;
1585
1668
  }
1586
1669
  }
1587
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1588
- requestAdjust(ctx, state, positionDiff);
1670
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1671
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1672
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1673
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1674
+ const diff = newSize - prevSize;
1675
+ if (diff !== 0) {
1676
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1677
+ scrollingTo.itemSize = newSize;
1678
+ }
1679
+ }
1680
+ }
1681
+ if (Math.abs(positionDiff) > 0.1) {
1682
+ requestAdjust(ctx, positionDiff);
1589
1683
  }
1590
1684
  };
1591
1685
  }
1592
1686
  }
1593
1687
 
1594
1688
  // src/core/prepareColumnStartState.ts
1595
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1689
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1596
1690
  var _a3;
1691
+ const state = ctx.state;
1597
1692
  const numColumns = peek$(ctx, "numColumns");
1598
1693
  let rowStartIndex = startIndex;
1599
1694
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1608,7 +1703,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1608
1703
  const prevId = state.idCache[prevIndex];
1609
1704
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1610
1705
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1611
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1706
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1612
1707
  currentRowTop = prevPosition + prevRowHeight;
1613
1708
  }
1614
1709
  return {
@@ -1631,7 +1726,8 @@ function findRowStartIndex(state, numColumns, index) {
1631
1726
  }
1632
1727
  return rowStart;
1633
1728
  }
1634
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1729
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1730
+ const state = ctx.state;
1635
1731
  if (endIndex < startIndex) {
1636
1732
  return 0;
1637
1733
  }
@@ -1645,7 +1741,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1645
1741
  continue;
1646
1742
  }
1647
1743
  const id = state.idCache[i];
1648
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1744
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1649
1745
  if (size > maxSize) {
1650
1746
  maxSize = size;
1651
1747
  }
@@ -1654,22 +1750,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1654
1750
  }
1655
1751
 
1656
1752
  // src/core/updateTotalSize.ts
1657
- function updateTotalSize(ctx, state) {
1753
+ function updateTotalSize(ctx) {
1754
+ const state = ctx.state;
1658
1755
  const {
1659
1756
  positions,
1660
1757
  props: { data }
1661
1758
  } = state;
1662
1759
  if (data.length === 0) {
1663
- addTotalSize(ctx, state, null, 0);
1760
+ addTotalSize(ctx, null, 0);
1664
1761
  } else {
1665
1762
  const lastId = getId(state, data.length - 1);
1666
1763
  if (lastId !== void 0) {
1667
1764
  const lastPosition = positions.get(lastId);
1668
1765
  if (lastPosition !== void 0) {
1669
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1766
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1670
1767
  if (lastSize !== void 0) {
1671
1768
  const totalSize = lastPosition + lastSize;
1672
- addTotalSize(ctx, state, null, totalSize);
1769
+ addTotalSize(ctx, null, totalSize);
1673
1770
  }
1674
1771
  }
1675
1772
  }
@@ -1715,7 +1812,8 @@ var getScrollVelocity = (state) => {
1715
1812
  };
1716
1813
 
1717
1814
  // src/utils/updateSnapToOffsets.ts
1718
- function updateSnapToOffsets(ctx, state) {
1815
+ function updateSnapToOffsets(ctx) {
1816
+ const state = ctx.state;
1719
1817
  const {
1720
1818
  positions,
1721
1819
  props: { snapToIndices }
@@ -1730,30 +1828,30 @@ function updateSnapToOffsets(ctx, state) {
1730
1828
  }
1731
1829
 
1732
1830
  // src/core/updateItemPositions.ts
1733
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1831
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1734
1832
  doMVCP: false,
1735
1833
  forceFullUpdate: false,
1736
1834
  scrollBottomBuffered: -1,
1737
1835
  startIndex: 0
1738
1836
  }) {
1739
1837
  var _a3, _b, _c, _d, _e;
1838
+ const state = ctx.state;
1740
1839
  const {
1741
1840
  columns,
1742
1841
  indexByKey,
1743
1842
  positions,
1744
1843
  idCache,
1745
1844
  sizesKnown,
1746
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1845
+ props: { data, getEstimatedItemSize, snapToIndices },
1846
+ scrollingTo
1747
1847
  } = state;
1748
- const data = state.props.data;
1749
1848
  const dataLength = data.length;
1750
1849
  const numColumns = peek$(ctx, "numColumns");
1751
- const scrollingTo = peek$(ctx, "scrollingTo");
1752
1850
  const hasColumns = numColumns > 1;
1753
1851
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1754
1852
  const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1755
1853
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1756
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1854
+ const useAverageSize = !getEstimatedItemSize;
1757
1855
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1758
1856
  let currentRowTop = 0;
1759
1857
  let column = 1;
@@ -1762,7 +1860,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1762
1860
  if (hasColumns) {
1763
1861
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1764
1862
  ctx,
1765
- state,
1766
1863
  startIndex,
1767
1864
  useAverageSize
1768
1865
  );
@@ -1772,7 +1869,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1772
1869
  const prevIndex = startIndex - 1;
1773
1870
  const prevId = getId(state, prevIndex);
1774
1871
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1775
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1872
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1776
1873
  currentRowTop = prevPosition + prevSize;
1777
1874
  }
1778
1875
  }
@@ -1789,7 +1886,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1789
1886
  breakAt = i + itemsPerRow + 10;
1790
1887
  }
1791
1888
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1792
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1889
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1793
1890
  if (IS_DEV && needsIndexByKey) {
1794
1891
  if (indexByKeyForChecking.has(id)) {
1795
1892
  console.error(
@@ -1798,7 +1895,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1798
1895
  }
1799
1896
  indexByKeyForChecking.set(id, i);
1800
1897
  }
1801
- positions.set(id, currentRowTop);
1898
+ if (currentRowTop !== positions.get(id)) {
1899
+ positions.set(id, currentRowTop);
1900
+ notifyPosition$(ctx, id, currentRowTop);
1901
+ }
1802
1902
  if (needsIndexByKey) {
1803
1903
  indexByKey.set(id, i);
1804
1904
  }
@@ -1818,10 +1918,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1818
1918
  }
1819
1919
  }
1820
1920
  if (!didBreakEarly) {
1821
- updateTotalSize(ctx, state);
1921
+ updateTotalSize(ctx);
1822
1922
  }
1823
1923
  if (snapToIndices) {
1824
- updateSnapToOffsets(ctx, state);
1924
+ updateSnapToOffsets(ctx);
1825
1925
  }
1826
1926
  }
1827
1927
 
@@ -1899,7 +1999,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1899
1999
  if (previousViewableItems) {
1900
2000
  for (const viewToken of previousViewableItems) {
1901
2001
  const containerId = findContainerId(ctx, viewToken.key);
1902
- if (!isViewable(
2002
+ if (!checkIsViewable(
1903
2003
  state,
1904
2004
  ctx,
1905
2005
  viewabilityConfig,
@@ -1920,7 +2020,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1920
2020
  if (item) {
1921
2021
  const key = getId(state, i);
1922
2022
  const containerId = findContainerId(ctx, key);
1923
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2023
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1924
2024
  const viewToken = {
1925
2025
  containerId,
1926
2026
  index: i,
@@ -1980,11 +2080,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1980
2080
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
1981
2081
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
1982
2082
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
1983
- const isViewable2 = percent >= viewablePercentThreshold;
2083
+ const isViewable = percent >= viewablePercentThreshold;
1984
2084
  const value = {
1985
2085
  containerId,
1986
2086
  index,
1987
- isViewable: isViewable2,
2087
+ isViewable,
1988
2088
  item,
1989
2089
  key,
1990
2090
  percentOfScroller,
@@ -2003,8 +2103,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2003
2103
  }
2004
2104
  return value;
2005
2105
  }
2006
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2007
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2106
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2107
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2108
+ if (!value || value.key !== key) {
2109
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2110
+ }
2008
2111
  return value.isViewable;
2009
2112
  }
2010
2113
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -2032,8 +2135,9 @@ function checkAllSizesKnown(state) {
2032
2135
  }
2033
2136
 
2034
2137
  // src/utils/findAvailableContainers.ts
2035
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2138
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2036
2139
  const numContainers = peek$(ctx, "numContainers");
2140
+ const state = ctx.state;
2037
2141
  const { stickyContainerPool, containerItemTypes } = state;
2038
2142
  const result = [];
2039
2143
  const availableContainers = [];
@@ -2077,14 +2181,14 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
2077
2181
  continue;
2078
2182
  }
2079
2183
  const key = peek$(ctx, `containerItemKey${u}`);
2080
- let isOk = key === void 0;
2081
- if (!isOk && pendingRemovalSet.has(u)) {
2082
- pendingRemovalSet.delete(u);
2083
- pendingRemovalChanged = true;
2084
- const requiredType = neededTypes[typeIndex];
2085
- isOk = canReuseContainer(u, requiredType);
2086
- }
2087
- if (isOk) {
2184
+ const requiredType = neededTypes[typeIndex];
2185
+ const isPending = key !== void 0 && pendingRemovalSet.has(u);
2186
+ const canUse = key === void 0 || isPending && canReuseContainer(u, requiredType);
2187
+ if (canUse) {
2188
+ if (isPending) {
2189
+ pendingRemovalSet.delete(u);
2190
+ pendingRemovalChanged = true;
2191
+ }
2088
2192
  result.push(u);
2089
2193
  if (requiredItemTypes) {
2090
2194
  typeIndex++;
@@ -2153,21 +2257,26 @@ function comparatorByDistance(a, b) {
2153
2257
  }
2154
2258
 
2155
2259
  // src/core/scrollToIndex.ts
2156
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2157
- if (index >= state.props.data.length) {
2158
- index = state.props.data.length - 1;
2260
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2261
+ const state = ctx.state;
2262
+ const { data } = state.props;
2263
+ if (index >= data.length) {
2264
+ index = data.length - 1;
2159
2265
  } else if (index < 0) {
2160
2266
  index = 0;
2161
2267
  }
2162
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2163
- const isLast = index === state.props.data.length - 1;
2268
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2269
+ const isLast = index === data.length - 1;
2164
2270
  if (isLast && viewPosition === void 0) {
2165
2271
  viewPosition = 1;
2166
2272
  }
2167
2273
  state.scrollForNextCalculateItemsInView = void 0;
2168
- scrollTo(ctx, state, {
2274
+ const targetId = getId(state, index);
2275
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2276
+ scrollTo(ctx, {
2169
2277
  animated,
2170
2278
  index,
2279
+ itemSize,
2171
2280
  offset: firstIndexOffset,
2172
2281
  viewOffset,
2173
2282
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2175,16 +2284,17 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2175
2284
  }
2176
2285
 
2177
2286
  // src/utils/setDidLayout.ts
2178
- function setDidLayout(ctx, state) {
2287
+ function setDidLayout(ctx) {
2288
+ const state = ctx.state;
2179
2289
  const {
2180
2290
  loadStartTime,
2181
2291
  initialScroll,
2182
2292
  props: { onLoad }
2183
2293
  } = state;
2184
2294
  state.queuedInitialLayout = true;
2185
- checkAtBottom(ctx, state);
2295
+ checkAtBottom(ctx);
2186
2296
  const setIt = () => {
2187
- set$(ctx, "containersDidLayout", true);
2297
+ setInitialRenderState(ctx, { didLayout: true });
2188
2298
  if (onLoad) {
2189
2299
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2190
2300
  }
@@ -2209,15 +2319,17 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2209
2319
  }
2210
2320
  return -1;
2211
2321
  }
2212
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2322
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2323
+ const state = ctx.state;
2213
2324
  return new Set(
2214
2325
  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))
2215
2326
  );
2216
2327
  }
2217
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2328
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2218
2329
  var _a3;
2219
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2220
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2330
+ const state = ctx.state;
2331
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2332
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2221
2333
  for (let offset = 0; offset <= 1; offset++) {
2222
2334
  const idx = currentStickyIdx - offset;
2223
2335
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -2228,8 +2340,9 @@ function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, cu
2228
2340
  }
2229
2341
  }
2230
2342
  }
2231
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2343
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2232
2344
  var _a3, _b, _c;
2345
+ const state = ctx.state;
2233
2346
  for (const containerIndex of state.stickyContainerPool) {
2234
2347
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2235
2348
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
@@ -2253,7 +2366,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2253
2366
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2254
2367
  if (currentId) {
2255
2368
  const currentPos = state.positions.get(currentId);
2256
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2369
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2257
2370
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2258
2371
  }
2259
2372
  }
@@ -2262,7 +2375,8 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2262
2375
  }
2263
2376
  }
2264
2377
  }
2265
- function calculateItemsInView(ctx, state, params = {}) {
2378
+ function calculateItemsInView(ctx, params = {}) {
2379
+ const state = ctx.state;
2266
2380
  unstable_batchedUpdates(() => {
2267
2381
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2268
2382
  const {
@@ -2286,9 +2400,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2286
2400
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2287
2401
  const prevNumContainers = peek$(ctx, "numContainers");
2288
2402
  if (!data || scrollLength === 0 || !prevNumContainers) {
2289
- if (state.initialAnchor) {
2290
- ensureInitialAnchor(ctx, state);
2291
- }
2292
2403
  return;
2293
2404
  }
2294
2405
  const totalSize = getContentSize(ctx);
@@ -2302,15 +2413,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2302
2413
  if (!queuedInitialLayout && initialScroll) {
2303
2414
  const updatedOffset = calculateOffsetWithOffsetPosition(
2304
2415
  ctx,
2305
- state,
2306
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2416
+ calculateOffsetForIndex(ctx, initialScroll.index),
2307
2417
  initialScroll
2308
2418
  );
2309
2419
  scrollState = updatedOffset;
2310
2420
  }
2311
2421
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2312
2422
  const scrollAdjustPad = scrollAdjustPending - topPad;
2313
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2423
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2314
2424
  if (scroll + scrollLength > totalSize) {
2315
2425
  scroll = Math.max(0, totalSize - scrollLength);
2316
2426
  }
@@ -2318,11 +2428,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2318
2428
  set$(ctx, "debugRawScroll", scrollState);
2319
2429
  set$(ctx, "debugComputedScroll", scroll);
2320
2430
  }
2321
- const previousStickyIndex = state.activeStickyIndex;
2431
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2322
2432
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2323
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2324
- state.activeStickyIndex = nextActiveStickyIndex;
2325
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2433
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2434
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2435
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2436
+ }
2326
2437
  let scrollBufferTop = scrollBuffer;
2327
2438
  let scrollBufferBottom = scrollBuffer;
2328
2439
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2335,23 +2446,20 @@ function calculateItemsInView(ctx, state, params = {}) {
2335
2446
  const scrollTopBuffered = scroll - scrollBufferTop;
2336
2447
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2337
2448
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2338
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2449
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2339
2450
  const { top, bottom } = scrollForNextCalculateItemsInView;
2340
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2341
- if (state.initialAnchor) {
2342
- ensureInitialAnchor(ctx, state);
2343
- }
2451
+ if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2344
2452
  return;
2345
2453
  }
2346
2454
  }
2347
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2455
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2348
2456
  if (dataChanged) {
2349
2457
  indexByKey.clear();
2350
2458
  idCache.length = 0;
2351
2459
  positions.clear();
2352
2460
  }
2353
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2354
- updateItemPositions(ctx, state, dataChanged, {
2461
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2462
+ updateItemPositions(ctx, dataChanged, {
2355
2463
  doMVCP,
2356
2464
  forceFullUpdate: !!forceFullItemPositions,
2357
2465
  scrollBottomBuffered,
@@ -2370,9 +2478,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2370
2478
  for (let i = loopStart; i >= 0; i--) {
2371
2479
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2372
2480
  const top = positions.get(id);
2373
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2481
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2374
2482
  const bottom = top + size;
2375
- if (bottom > scroll - scrollBuffer) {
2483
+ if (bottom > scroll - scrollBufferTop) {
2376
2484
  loopStart = i;
2377
2485
  } else {
2378
2486
  break;
@@ -2397,7 +2505,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2397
2505
  const dataLength = data.length;
2398
2506
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2399
2507
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2400
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2508
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2401
2509
  const top = positions.get(id);
2402
2510
  if (!foundEnd) {
2403
2511
  if (startNoBuffer === null && top + size > scroll) {
@@ -2409,7 +2517,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2409
2517
  if (startBuffered === null && top + size > scrollTopBuffered) {
2410
2518
  startBuffered = i;
2411
2519
  startBufferedId = id;
2412
- nextTop = top;
2520
+ if (scrollTopBuffered < 0) {
2521
+ nextTop = null;
2522
+ } else {
2523
+ nextTop = top;
2524
+ }
2413
2525
  }
2414
2526
  if (startNoBuffer !== null) {
2415
2527
  if (top <= scrollBottom) {
@@ -2417,7 +2529,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2417
2529
  }
2418
2530
  if (top <= scrollBottomBuffered) {
2419
2531
  endBuffered = i;
2420
- nextBottom = top + size;
2532
+ if (scrollBottomBuffered > totalSize) {
2533
+ nextBottom = null;
2534
+ } else {
2535
+ nextBottom = top + size;
2536
+ }
2421
2537
  } else {
2422
2538
  foundEnd = true;
2423
2539
  }
@@ -2444,7 +2560,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2444
2560
  top: nextTop
2445
2561
  } : void 0;
2446
2562
  }
2447
- const numContainers = peek$(ctx, "numContainers");
2563
+ let numContainers = prevNumContainers;
2448
2564
  const pendingRemoval = [];
2449
2565
  if (dataChanged) {
2450
2566
  for (let i = 0; i < numContainers; i++) {
@@ -2455,7 +2571,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2455
2571
  }
2456
2572
  }
2457
2573
  if (startBuffered !== null && endBuffered !== null) {
2458
- let numContainers2 = prevNumContainers;
2459
2574
  const needNewContainers = [];
2460
2575
  for (let i = startBuffered; i <= endBuffered; i++) {
2461
2576
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
@@ -2466,7 +2581,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2466
2581
  if (stickyIndicesArr.length > 0) {
2467
2582
  handleStickyActivation(
2468
2583
  ctx,
2469
- state,
2470
2584
  stickyIndicesSet,
2471
2585
  stickyIndicesArr,
2472
2586
  currentStickyIdx,
@@ -2474,9 +2588,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2474
2588
  startBuffered,
2475
2589
  endBuffered
2476
2590
  );
2477
- } else {
2478
- state.activeStickyIndex = void 0;
2479
- set$(ctx, "activeStickyIndex", void 0);
2591
+ } else if (previousStickyIndex !== -1) {
2592
+ set$(ctx, "activeStickyIndex", -1);
2480
2593
  }
2481
2594
  if (needNewContainers.length > 0) {
2482
2595
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2485,7 +2598,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2485
2598
  }) : void 0;
2486
2599
  const availableContainers = findAvailableContainers(
2487
2600
  ctx,
2488
- state,
2489
2601
  needNewContainers.length,
2490
2602
  startBuffered,
2491
2603
  endBuffered,
@@ -2507,29 +2619,30 @@ function calculateItemsInView(ctx, state, params = {}) {
2507
2619
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2508
2620
  }
2509
2621
  containerItemKeys.add(id);
2622
+ const containerSticky = `containerSticky${containerIndex}`;
2510
2623
  if (stickyIndicesSet.has(i)) {
2511
- set$(ctx, `containerSticky${containerIndex}`, true);
2624
+ set$(ctx, containerSticky, true);
2512
2625
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2513
2626
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2514
2627
  state.stickyContainerPool.add(containerIndex);
2515
- } else {
2516
- set$(ctx, `containerSticky${containerIndex}`, false);
2628
+ } else if (peek$(ctx, containerSticky)) {
2629
+ set$(ctx, containerSticky, false);
2517
2630
  state.stickyContainerPool.delete(containerIndex);
2518
2631
  }
2519
- if (containerIndex >= numContainers2) {
2520
- numContainers2 = containerIndex + 1;
2632
+ if (containerIndex >= numContainers) {
2633
+ numContainers = containerIndex + 1;
2521
2634
  }
2522
2635
  }
2523
- if (numContainers2 !== prevNumContainers) {
2524
- set$(ctx, "numContainers", numContainers2);
2525
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2526
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2636
+ if (numContainers !== prevNumContainers) {
2637
+ set$(ctx, "numContainers", numContainers);
2638
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2639
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2527
2640
  }
2528
2641
  }
2529
2642
  }
2530
2643
  }
2531
2644
  if (stickyIndicesArr.length > 0) {
2532
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2645
+ handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2533
2646
  }
2534
2647
  let didChangePositions = false;
2535
2648
  for (let i = 0; i < numContainers; i++) {
@@ -2581,7 +2694,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2581
2694
  }
2582
2695
  if (!queuedInitialLayout && endBuffered !== null) {
2583
2696
  if (checkAllSizesKnown(state)) {
2584
- setDidLayout(ctx, state);
2697
+ setDidLayout(ctx);
2585
2698
  }
2586
2699
  }
2587
2700
  if (viewabilityConfigCallbackPairs) {
@@ -2594,9 +2707,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2594
2707
  }
2595
2708
  }
2596
2709
  });
2597
- if (state.initialAnchor) {
2598
- ensureInitialAnchor(ctx, state);
2599
- }
2600
2710
  }
2601
2711
 
2602
2712
  // src/core/checkActualChange.ts
@@ -2619,20 +2729,69 @@ function checkActualChange(state, dataProp, previousData) {
2619
2729
  return false;
2620
2730
  }
2621
2731
 
2732
+ // src/core/checkFinishedScroll.ts
2733
+ function checkFinishedScroll(ctx) {
2734
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2735
+ }
2736
+ function checkFinishedScrollFrame(ctx) {
2737
+ const scrollingTo = ctx.state.scrollingTo;
2738
+ if (scrollingTo) {
2739
+ const { state } = ctx;
2740
+ state.animFrameCheckFinishedScroll = void 0;
2741
+ const scroll = state.scroll;
2742
+ const adjust = state.scrollAdjustHandler.getAdjust();
2743
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
2744
+ const maxOffset = clampScrollOffset(ctx, scroll);
2745
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
2746
+ const diff2 = Math.abs(diff1 - adjust);
2747
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
2748
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
2749
+ finishScrollTo(ctx);
2750
+ }
2751
+ }
2752
+ }
2753
+ function checkFinishedScrollFallback(ctx) {
2754
+ const state = ctx.state;
2755
+ const scrollingTo = state.scrollingTo;
2756
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
2757
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
2758
+ () => {
2759
+ let numChecks = 0;
2760
+ const checkHasScrolled = () => {
2761
+ state.timeoutCheckFinishedScrollFallback = void 0;
2762
+ const isStillScrollingTo = state.scrollingTo;
2763
+ if (isStillScrollingTo) {
2764
+ numChecks++;
2765
+ if (state.hasScrolled || numChecks > 5) {
2766
+ finishScrollTo(ctx);
2767
+ } else {
2768
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
2769
+ }
2770
+ }
2771
+ };
2772
+ checkHasScrolled();
2773
+ },
2774
+ slowTimeout ? 500 : 100
2775
+ );
2776
+ }
2777
+
2622
2778
  // src/core/doMaintainScrollAtEnd.ts
2623
- function doMaintainScrollAtEnd(ctx, state, animated) {
2779
+ function doMaintainScrollAtEnd(ctx, animated) {
2780
+ const state = ctx.state;
2624
2781
  const {
2782
+ didContainersLayout,
2783
+ isAtEnd,
2625
2784
  refScroller,
2626
2785
  props: { maintainScrollAtEnd }
2627
2786
  } = state;
2628
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2787
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2629
2788
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2630
2789
  if (paddingTop > 0) {
2631
2790
  state.scroll = 0;
2632
2791
  }
2633
2792
  requestAnimationFrame(() => {
2634
2793
  var _a3;
2635
- if (state == null ? void 0 : state.isAtEnd) {
2794
+ if (state.isAtEnd) {
2636
2795
  state.maintainingScrollAtEnd = true;
2637
2796
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2638
2797
  animated
@@ -2703,28 +2862,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2703
2862
  }
2704
2863
 
2705
2864
  // src/core/checkResetContainers.ts
2706
- function checkResetContainers(ctx, state, dataProp) {
2865
+ function checkResetContainers(ctx, dataProp) {
2866
+ const state = ctx.state;
2707
2867
  const { previousData } = state;
2708
2868
  if (previousData) {
2709
2869
  updateAveragesOnDataChange(state, previousData, dataProp);
2710
2870
  }
2711
2871
  const { maintainScrollAtEnd } = state.props;
2712
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2872
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2713
2873
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2714
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2874
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2715
2875
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2716
2876
  state.isEndReached = false;
2717
2877
  }
2718
2878
  if (!didMaintainScrollAtEnd) {
2719
2879
  checkAtTop(state);
2720
- checkAtBottom(ctx, state);
2880
+ checkAtBottom(ctx);
2721
2881
  }
2722
2882
  delete state.previousData;
2723
2883
  }
2724
2884
 
2725
2885
  // src/core/doInitialAllocateContainers.ts
2726
- function doInitialAllocateContainers(ctx, state) {
2886
+ function doInitialAllocateContainers(ctx) {
2727
2887
  var _a3, _b, _c;
2888
+ const state = ctx.state;
2728
2889
  const {
2729
2890
  scrollLength,
2730
2891
  props: {
@@ -2762,10 +2923,10 @@ function doInitialAllocateContainers(ctx, state) {
2762
2923
  if (state.lastLayout) {
2763
2924
  if (state.initialScroll) {
2764
2925
  requestAnimationFrame(() => {
2765
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2926
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2766
2927
  });
2767
2928
  } else {
2768
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2929
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2769
2930
  }
2770
2931
  }
2771
2932
  return true;
@@ -2773,7 +2934,8 @@ function doInitialAllocateContainers(ctx, state) {
2773
2934
  }
2774
2935
 
2775
2936
  // src/core/handleLayout.ts
2776
- function handleLayout(ctx, state, layout, setCanRender) {
2937
+ function handleLayout(ctx, layout, setCanRender) {
2938
+ const state = ctx.state;
2777
2939
  const { maintainScrollAtEnd } = state.props;
2778
2940
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2779
2941
  const previousLength = state.scrollLength;
@@ -2789,19 +2951,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2789
2951
  state.lastBatchingAction = Date.now();
2790
2952
  state.scrollForNextCalculateItemsInView = void 0;
2791
2953
  if (scrollLength > 0) {
2792
- doInitialAllocateContainers(ctx, state);
2954
+ doInitialAllocateContainers(ctx);
2793
2955
  }
2794
2956
  if (needsCalculate) {
2795
- calculateItemsInView(ctx, state, { doMVCP: true });
2957
+ calculateItemsInView(ctx, { doMVCP: true });
2796
2958
  }
2797
2959
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2798
2960
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2799
2961
  }
2800
2962
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2801
- doMaintainScrollAtEnd(ctx, state, false);
2963
+ doMaintainScrollAtEnd(ctx, false);
2802
2964
  }
2803
- updateAlignItemsPaddingTop(ctx, state);
2804
- checkAtBottom(ctx, state);
2965
+ updateAlignItemsPaddingTop(ctx);
2966
+ checkAtBottom(ctx);
2805
2967
  checkAtTop(state);
2806
2968
  if (state) {
2807
2969
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2817,8 +2979,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2817
2979
  }
2818
2980
 
2819
2981
  // src/core/onScroll.ts
2820
- function onScroll(ctx, state, event) {
2982
+ function onScroll(ctx, event) {
2821
2983
  var _a3, _b, _c;
2984
+ const state = ctx.state;
2822
2985
  const {
2823
2986
  scrollProcessingEnabled,
2824
2987
  props: { onScroll: onScrollProp }
@@ -2829,9 +2992,23 @@ function onScroll(ctx, state, event) {
2829
2992
  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) {
2830
2993
  return;
2831
2994
  }
2832
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2995
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2833
2996
  state.scrollPending = newScroll;
2834
- updateScroll(ctx, state, newScroll);
2997
+ if (state.scrollingTo) {
2998
+ const maxOffset = clampScrollOffset(ctx, newScroll);
2999
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3000
+ newScroll = maxOffset;
3001
+ scrollTo(ctx, {
3002
+ forceScroll: true,
3003
+ isInitialScroll: true,
3004
+ noScrollingTo: true,
3005
+ offset: newScroll
3006
+ });
3007
+ return;
3008
+ }
3009
+ }
3010
+ updateScroll(ctx, newScroll);
3011
+ checkFinishedScroll(ctx);
2835
3012
  onScrollProp == null ? void 0 : onScrollProp(event);
2836
3013
  }
2837
3014
 
@@ -2840,51 +3017,47 @@ var ScrollAdjustHandler = class {
2840
3017
  constructor(ctx) {
2841
3018
  this.appliedAdjust = 0;
2842
3019
  this.pendingAdjust = 0;
2843
- this.mounted = false;
2844
- this.context = ctx;
2845
- {
2846
- const commitPendingAdjust = () => {
2847
- const state = this.context.internalState;
2848
- const pending = this.pendingAdjust;
2849
- if (pending !== 0) {
2850
- this.pendingAdjust = 0;
2851
- this.appliedAdjust += pending;
2852
- state.scroll += pending;
2853
- state.scrollForNextCalculateItemsInView = void 0;
2854
- set$(this.context, "scrollAdjustPending", 0);
2855
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2856
- calculateItemsInView(this.context, this.context.internalState);
2857
- }
2858
- };
2859
- listen$(this.context, "scrollingTo", (value) => {
2860
- if (value === void 0) {
2861
- commitPendingAdjust();
2862
- }
2863
- });
2864
- }
3020
+ this.ctx = ctx;
2865
3021
  }
2866
3022
  requestAdjust(add) {
2867
- const scrollingTo = peek$(this.context, "scrollingTo");
3023
+ const scrollingTo = this.ctx.state.scrollingTo;
2868
3024
  if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2869
3025
  this.pendingAdjust += add;
2870
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
3026
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2871
3027
  } else {
2872
3028
  this.appliedAdjust += add;
2873
- set$(this.context, "scrollAdjust", this.appliedAdjust);
3029
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3030
+ }
3031
+ if (this.ctx.state.scrollingTo) {
3032
+ checkFinishedScroll(this.ctx);
2874
3033
  }
2875
- }
2876
- setMounted() {
2877
- this.mounted = true;
2878
3034
  }
2879
3035
  getAdjust() {
2880
3036
  return this.appliedAdjust;
2881
3037
  }
3038
+ commitPendingAdjust() {
3039
+ {
3040
+ const state = this.ctx.state;
3041
+ const pending = this.pendingAdjust;
3042
+ if (pending !== 0) {
3043
+ this.pendingAdjust = 0;
3044
+ this.appliedAdjust += pending;
3045
+ state.scroll += pending;
3046
+ state.scrollForNextCalculateItemsInView = void 0;
3047
+ set$(this.ctx, "scrollAdjustPending", 0);
3048
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3049
+ calculateItemsInView(this.ctx);
3050
+ }
3051
+ }
3052
+ }
2882
3053
  };
2883
3054
 
2884
3055
  // src/core/updateItemSize.ts
2885
- function updateItemSize(ctx, state, itemKey, sizeObj) {
3056
+ function updateItemSize(ctx, itemKey, sizeObj) {
2886
3057
  var _a3;
3058
+ const state = ctx.state;
2887
3059
  const {
3060
+ didContainersLayout,
2888
3061
  sizesKnown,
2889
3062
  props: {
2890
3063
  getFixedItemSize,
@@ -2912,13 +3085,12 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2912
3085
  return;
2913
3086
  }
2914
3087
  }
2915
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2916
- let needsRecalculate = !containersDidLayout;
3088
+ let needsRecalculate = !didContainersLayout;
2917
3089
  let shouldMaintainScrollAtEnd = false;
2918
3090
  let minIndexSizeChanged;
2919
3091
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2920
3092
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2921
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3093
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
2922
3094
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2923
3095
  if (diff !== 0) {
2924
3096
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
@@ -2967,22 +3139,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2967
3139
  if (!cur || maxOtherAxisSize > cur) {
2968
3140
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
2969
3141
  }
2970
- if (containersDidLayout || checkAllSizesKnown(state)) {
3142
+ if (didContainersLayout || checkAllSizesKnown(state)) {
2971
3143
  if (needsRecalculate) {
2972
3144
  state.scrollForNextCalculateItemsInView = void 0;
2973
- calculateItemsInView(ctx, state, { doMVCP: true });
3145
+ calculateItemsInView(ctx, { doMVCP: true });
2974
3146
  }
2975
3147
  if (shouldMaintainScrollAtEnd) {
2976
3148
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2977
- doMaintainScrollAtEnd(ctx, state, false);
3149
+ doMaintainScrollAtEnd(ctx, false);
2978
3150
  }
2979
3151
  }
2980
3152
  }
2981
3153
  }
2982
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3154
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
2983
3155
  var _a3;
3156
+ const state = ctx.state;
2984
3157
  const {
2985
- sizes,
2986
3158
  indexByKey,
2987
3159
  sizesKnown,
2988
3160
  averageSizes,
@@ -2990,9 +3162,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2990
3162
  } = state;
2991
3163
  if (!data) return 0;
2992
3164
  const index = indexByKey.get(itemKey);
2993
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3165
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
2994
3166
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2995
3167
  const size = Math.round(rawSize) ;
3168
+ const prevSizeKnown = sizesKnown.get(itemKey);
2996
3169
  sizesKnown.set(itemKey, size);
2997
3170
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2998
3171
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -3000,11 +3173,15 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3000
3173
  if (!averages) {
3001
3174
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3002
3175
  }
3003
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3004
- averages.num++;
3176
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3177
+ averages.avg += (size - prevSizeKnown) / averages.num;
3178
+ } else {
3179
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3180
+ averages.num++;
3181
+ }
3005
3182
  }
3006
3183
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
3007
- setSize(ctx, state, itemKey, size);
3184
+ setSize(ctx, itemKey, size);
3008
3185
  return size - prevSize;
3009
3186
  }
3010
3187
  return 0;
@@ -3051,14 +3228,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
3051
3228
  }
3052
3229
 
3053
3230
  // src/utils/createImperativeHandle.ts
3054
- function createImperativeHandle(ctx, state) {
3231
+ function createImperativeHandle(ctx) {
3232
+ const state = ctx.state;
3055
3233
  const scrollIndexIntoView = (options) => {
3056
3234
  if (state) {
3057
3235
  const { index, ...rest } = options;
3058
3236
  const { startNoBuffer, endNoBuffer } = state;
3059
3237
  if (index < startNoBuffer || index > endNoBuffer) {
3060
3238
  const viewPosition = index < startNoBuffer ? 0 : 1;
3061
- scrollToIndex(ctx, state, {
3239
+ scrollToIndex(ctx, {
3062
3240
  ...rest,
3063
3241
  index,
3064
3242
  viewPosition
@@ -3073,7 +3251,7 @@ function createImperativeHandle(ctx, state) {
3073
3251
  getScrollableNode: () => refScroller.current.getScrollableNode(),
3074
3252
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3075
3253
  getState: () => ({
3076
- activeStickyIndex: state.activeStickyIndex,
3254
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3077
3255
  contentLength: state.totalSize,
3078
3256
  data: state.props.data,
3079
3257
  elementAtIndex: (index) => {
@@ -3084,6 +3262,8 @@ function createImperativeHandle(ctx, state) {
3084
3262
  endBuffered: state.endBuffered,
3085
3263
  isAtEnd: state.isAtEnd,
3086
3264
  isAtStart: state.isAtStart,
3265
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3266
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3087
3267
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
3088
3268
  positions: state.positions,
3089
3269
  scroll: state.scroll,
@@ -3108,23 +3288,23 @@ function createImperativeHandle(ctx, state) {
3108
3288
  if (index !== -1) {
3109
3289
  const paddingBottom = stylePaddingBottom || 0;
3110
3290
  const footerSize = peek$(ctx, "footerSize") || 0;
3111
- scrollToIndex(ctx, state, {
3291
+ scrollToIndex(ctx, {
3292
+ ...options,
3112
3293
  index,
3113
3294
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3114
- viewPosition: 1,
3115
- ...options
3295
+ viewPosition: 1
3116
3296
  });
3117
3297
  }
3118
3298
  },
3119
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3299
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
3120
3300
  scrollToItem: ({ item, ...props }) => {
3121
3301
  const data = state.props.data;
3122
3302
  const index = data.indexOf(item);
3123
3303
  if (index !== -1) {
3124
- scrollToIndex(ctx, state, { index, ...props });
3304
+ scrollToIndex(ctx, { index, ...props });
3125
3305
  }
3126
3306
  },
3127
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3307
+ scrollToOffset: (params) => scrollTo(ctx, params),
3128
3308
  setScrollProcessingEnabled: (enabled) => {
3129
3309
  state.scrollProcessingEnabled = enabled;
3130
3310
  },
@@ -3134,8 +3314,9 @@ function createImperativeHandle(ctx, state) {
3134
3314
  }
3135
3315
  };
3136
3316
  }
3137
- function getRenderedItem(ctx, state, key) {
3317
+ function getRenderedItem(ctx, key) {
3138
3318
  var _a3;
3319
+ const state = ctx.state;
3139
3320
  if (!state) {
3140
3321
  return null;
3141
3322
  }
@@ -3212,11 +3393,13 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3212
3393
  var DEFAULT_DRAW_DISTANCE = 250;
3213
3394
  var DEFAULT_ITEM_SIZE = 100;
3214
3395
  var LegendList = typedMemo(
3396
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3215
3397
  typedForwardRef(function LegendList2(props, forwardedRef) {
3216
3398
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3217
3399
  const isChildrenMode = children !== void 0 && dataProp === void 0;
3218
3400
  const processedProps = isChildrenMode ? {
3219
3401
  ...restProps,
3402
+ childrenMode: true,
3220
3403
  data: (isArray(children) ? children : React3.Children.toArray(children)).flat(1),
3221
3404
  renderItem: ({ item }) => item
3222
3405
  } : {
@@ -3233,10 +3416,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3233
3416
  alignItemsAtEnd = false,
3234
3417
  columnWrapperStyle,
3235
3418
  contentContainerStyle: contentContainerStyleProp,
3419
+ contentInset,
3236
3420
  data: dataProp = [],
3237
3421
  dataVersion,
3238
3422
  drawDistance = 250,
3239
- enableAverages = true,
3240
3423
  estimatedItemSize: estimatedItemSizeProp,
3241
3424
  estimatedListSize,
3242
3425
  extraData,
@@ -3278,6 +3461,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3278
3461
  snapToIndices,
3279
3462
  stickyHeaderIndices: stickyHeaderIndicesProp,
3280
3463
  stickyIndices: stickyIndicesDeprecated,
3464
+ // TODOV3: Remove from v3 release
3281
3465
  style: styleProp,
3282
3466
  suggestEstimatedItemSize,
3283
3467
  viewabilityConfig,
@@ -3285,6 +3469,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3285
3469
  waitForInitialLayout = true,
3286
3470
  ...rest
3287
3471
  } = props;
3472
+ const animatedPropsInternal = props.animatedPropsInternal;
3473
+ const { childrenMode } = rest;
3288
3474
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3289
3475
  const style = { ...StyleSheet.flatten(styleProp) };
3290
3476
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
@@ -3308,10 +3494,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3308
3494
  }
3309
3495
  const refState = useRef();
3310
3496
  if (!refState.current) {
3311
- if (!ctx.internalState) {
3497
+ if (!ctx.state) {
3312
3498
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
3313
- ctx.internalState = {
3314
- activeStickyIndex: void 0,
3499
+ ctx.state = {
3500
+ activeStickyIndex: -1,
3315
3501
  averageSizes: {},
3316
3502
  columns: /* @__PURE__ */ new Map(),
3317
3503
  containerItemKeys: /* @__PURE__ */ new Set(),
@@ -3337,9 +3523,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3337
3523
  initialScroll: initialScrollProp,
3338
3524
  isAtEnd: false,
3339
3525
  isAtStart: false,
3340
- isEndReached: false,
3526
+ isEndReached: null,
3341
3527
  isFirst: true,
3342
- isStartReached: false,
3528
+ isStartReached: null,
3343
3529
  lastBatchingAction: Date.now(),
3344
3530
  lastLayout: void 0,
3345
3531
  loadStartTime: Date.now(),
@@ -3371,12 +3557,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3371
3557
  totalSize: 0,
3372
3558
  viewabilityConfigCallbackPairs: void 0
3373
3559
  };
3374
- const internalState = ctx.internalState;
3375
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3560
+ const internalState = ctx.state;
3561
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3376
3562
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3377
3563
  set$(ctx, "extraData", extraData);
3378
3564
  }
3379
- refState.current = ctx.internalState;
3565
+ refState.current = ctx.state;
3380
3566
  }
3381
3567
  const state = refState.current;
3382
3568
  const isFirstLocal = state.isFirst;
@@ -3390,9 +3576,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3390
3576
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3391
3577
  state.props = {
3392
3578
  alignItemsAtEnd,
3579
+ animatedProps: animatedPropsInternal,
3580
+ contentInset,
3393
3581
  data: dataProp,
3394
3582
  dataVersion,
3395
- enableAverages,
3396
3583
  estimatedItemSize,
3397
3584
  getEstimatedItemSize,
3398
3585
  getFixedItemSize,
@@ -3435,62 +3622,52 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3435
3622
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3436
3623
  set$(ctx, "numColumns", numColumnsProp);
3437
3624
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3438
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3625
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3439
3626
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3440
3627
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3441
3628
  if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3442
3629
  if (state.scroll < 0) {
3443
3630
  paddingDiff += state.scroll;
3444
3631
  }
3445
- requestAdjust(ctx, state, paddingDiff);
3632
+ requestAdjust(ctx, paddingDiff);
3446
3633
  }
3447
3634
  };
3448
3635
  if (isFirstLocal) {
3449
3636
  initializeStateVars();
3450
3637
  updateItemPositions(
3451
3638
  ctx,
3452
- state,
3453
3639
  /*dataChanged*/
3454
3640
  true
3455
3641
  );
3456
3642
  }
3457
3643
  const initialContentOffset = useMemo(() => {
3458
- var _a4, _b2;
3459
- const { initialScroll } = refState.current;
3460
- if (!initialScroll) {
3644
+ let value;
3645
+ const { initialScroll, initialAnchor } = refState.current;
3646
+ if (initialScroll) {
3647
+ if (initialScroll.contentOffset !== void 0) {
3648
+ value = initialScroll.contentOffset;
3649
+ } else {
3650
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3651
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3652
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3653
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3654
+ refState.current.initialScroll = updatedInitialScroll;
3655
+ state.initialScroll = updatedInitialScroll;
3656
+ value = clampedOffset;
3657
+ }
3658
+ } else {
3461
3659
  refState.current.initialAnchor = void 0;
3462
- return 0;
3463
- }
3464
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3465
- refState.current.initialAnchor = {
3466
- attempts: 0,
3467
- index: initialScroll.index,
3468
- settledTicks: 0,
3469
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3470
- viewPosition: initialScroll.viewPosition
3471
- };
3660
+ value = 0;
3661
+ }
3662
+ if (!value) {
3663
+ state.didFinishInitialScroll = true;
3472
3664
  }
3473
- if (initialScroll.contentOffset !== void 0) {
3474
- return initialScroll.contentOffset;
3475
- }
3476
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3477
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3478
- let clampedOffset = resolvedOffset;
3479
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3480
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3481
- clampedOffset = Math.min(clampedOffset, maxOffset);
3482
- }
3483
- clampedOffset = Math.max(0, clampedOffset);
3484
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3485
- refState.current.initialScroll = updatedInitialScroll;
3486
- state.initialScroll = updatedInitialScroll;
3487
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3488
- return clampedOffset;
3665
+ return value;
3489
3666
  }, [renderNum]);
3490
3667
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3491
3668
  refState.current.lastBatchingAction = Date.now();
3492
3669
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3493
- IS_DEV && warnDevOnce(
3670
+ IS_DEV && !childrenMode && warnDevOnce(
3494
3671
  "keyExtractor",
3495
3672
  "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."
3496
3673
  );
@@ -3513,12 +3690,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3513
3690
  }
3514
3691
  }, []);
3515
3692
  const doInitialScroll = useCallback(() => {
3516
- var _a4;
3517
3693
  const initialScroll = state.initialScroll;
3518
3694
  if (initialScroll) {
3519
- scrollTo(ctx, state, {
3695
+ scrollTo(ctx, {
3520
3696
  animated: false,
3521
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3697
+ index: initialScroll == null ? void 0 : initialScroll.index,
3522
3698
  isInitialScroll: true,
3523
3699
  offset: initialContentOffset,
3524
3700
  precomputedWithViewOffset: true
@@ -3527,7 +3703,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3527
3703
  }, [initialContentOffset]);
3528
3704
  const onLayoutChange = useCallback((layout) => {
3529
3705
  doInitialScroll();
3530
- handleLayout(ctx, state, layout, setCanRender);
3706
+ handleLayout(ctx, layout, setCanRender);
3531
3707
  }, []);
3532
3708
  const { onLayout } = useOnLayoutSync({
3533
3709
  onLayoutChange,
@@ -3537,7 +3713,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3537
3713
  });
3538
3714
  useLayoutEffect(() => {
3539
3715
  if (snapToIndices) {
3540
- updateSnapToOffsets(ctx, state);
3716
+ updateSnapToOffsets(ctx);
3541
3717
  }
3542
3718
  }, [snapToIndices]);
3543
3719
  useLayoutEffect(() => {
@@ -3547,9 +3723,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3547
3723
  isFirst,
3548
3724
  props: { data }
3549
3725
  } = state;
3550
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3726
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3551
3727
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3552
- checkResetContainers(ctx, state, data);
3728
+ checkResetContainers(ctx, data);
3553
3729
  }
3554
3730
  state.didColumnsChange = false;
3555
3731
  state.didDataChange = false;
@@ -3574,15 +3750,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3574
3750
  state.viewabilityConfigCallbackPairs = viewability;
3575
3751
  state.enableScrollForNextCalculateItemsInView = !viewability;
3576
3752
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3577
- useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3753
+ useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3578
3754
  {
3579
3755
  useEffect(doInitialScroll, []);
3580
3756
  }
3581
3757
  const fns = useMemo(
3582
3758
  () => ({
3583
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3584
- onScroll: (event) => onScroll(ctx, state, event),
3585
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3759
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
3760
+ onMomentumScrollEnd: (event) => {
3761
+ checkFinishedScrollFallback(ctx);
3762
+ if (onMomentumScrollEnd) {
3763
+ onMomentumScrollEnd(event);
3764
+ }
3765
+ },
3766
+ onScroll: (event) => onScroll(ctx, event),
3767
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3586
3768
  }),
3587
3769
  []
3588
3770
  );
@@ -3594,6 +3776,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3594
3776
  alignItemsAtEnd,
3595
3777
  canRender,
3596
3778
  contentContainerStyle,
3779
+ contentInset,
3597
3780
  getRenderedItem: fns.getRenderedItem,
3598
3781
  horizontal,
3599
3782
  initialContentOffset,
@@ -3602,16 +3785,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3602
3785
  maintainVisibleContentPosition,
3603
3786
  onLayout,
3604
3787
  onLayoutHeader,
3605
- onMomentumScrollEnd: (event) => {
3606
- {
3607
- requestAnimationFrame(() => {
3608
- finishScrollTo(ctx, refState.current);
3609
- });
3610
- }
3611
- if (onMomentumScrollEnd) {
3612
- onMomentumScrollEnd(event);
3613
- }
3614
- },
3788
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3615
3789
  onScroll: onScrollHandler,
3616
3790
  recycleItems,
3617
3791
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
@@ -3626,7 +3800,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3626
3800
  ),
3627
3801
  refScrollView: combinedRef,
3628
3802
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3629
- scrollEventThrottle: 16 ,
3803
+ scrollEventThrottle: 0,
3630
3804
  snapToIndices,
3631
3805
  stickyHeaderIndices,
3632
3806
  style,
@@ -3672,8 +3846,8 @@ function buildSectionListData({
3672
3846
  if (hasHeader) {
3673
3847
  const headerIndex = data.length;
3674
3848
  data.push({
3675
- kind: "header",
3676
3849
  key: `${sectionKey}:header`,
3850
+ kind: "header",
3677
3851
  section,
3678
3852
  sectionIndex
3679
3853
  });
@@ -3687,31 +3861,31 @@ function buildSectionListData({
3687
3861
  const itemKeyExtractor = (_b = section.keyExtractor) != null ? _b : keyExtractor;
3688
3862
  const itemKey = itemKeyExtractor(item, itemIndex);
3689
3863
  data.push({
3690
- kind: "item",
3691
- key: `${sectionKey}:item:${itemKey}`,
3692
- section,
3693
- sectionIndex,
3864
+ absoluteItemIndex: absoluteItemIndex++,
3694
3865
  item,
3695
3866
  itemIndex,
3696
- absoluteItemIndex: absoluteItemIndex++
3867
+ key: `${sectionKey}:item:${itemKey}`,
3868
+ kind: "item",
3869
+ section,
3870
+ sectionIndex
3697
3871
  });
3698
3872
  meta.items.push(data.length - 1);
3699
3873
  if (hasItemSeparator && itemIndex < items.length - 1) {
3700
3874
  data.push({
3701
- kind: "item-separator",
3702
3875
  key: `${sectionKey}:separator:${itemIndex}`,
3703
- section,
3704
- sectionIndex,
3876
+ kind: "item-separator",
3705
3877
  leadingItem: item,
3706
3878
  leadingItemIndex: itemIndex,
3879
+ section,
3880
+ sectionIndex,
3707
3881
  trailingItem: items[itemIndex + 1]
3708
3882
  });
3709
3883
  }
3710
3884
  }
3711
3885
  if (hasFooter) {
3712
3886
  data.push({
3713
- kind: "footer",
3714
3887
  key: `${sectionKey}:footer`,
3888
+ kind: "footer",
3715
3889
  section,
3716
3890
  sectionIndex
3717
3891
  });
@@ -3720,8 +3894,8 @@ function buildSectionListData({
3720
3894
  const isLastSection = sectionIndex === sections.length - 1;
3721
3895
  if (hasSectionSeparator && !isLastSection) {
3722
3896
  data.push({
3723
- kind: "section-separator",
3724
3897
  key: `${sectionKey}:section-separator`,
3898
+ kind: "section-separator",
3725
3899
  leadingSection: section,
3726
3900
  leadingSectionIndex: sectionIndex,
3727
3901
  trailingSection: sections[sectionIndex + 1]