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

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,15 +139,24 @@ function set$(ctx, signalName, value) {
105
139
  }
106
140
  }
107
141
  }
108
- function getContentSize(ctx) {
109
- var _a3, _b;
110
- const { values, internalState } = ctx;
111
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
112
- const stylePaddingBottom = (internalState == null ? void 0 : internalState.props.stylePaddingBottom) || 0;
113
- const headerSize = values.get("headerSize") || 0;
114
- const footerSize = values.get("footerSize") || 0;
115
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
116
- return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom;
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
+ }
117
160
  }
118
161
  function useArr$(signalNames) {
119
162
  const ctx = React3.useContext(ContextState);
@@ -235,12 +278,12 @@ function findContainerId(ctx, key) {
235
278
  }
236
279
 
237
280
  // src/components/PositionView.tsx
238
- var PositionViewState = typedMemo(function PositionView({
281
+ var PositionViewState = typedMemo(function PositionViewState2({
239
282
  id,
240
283
  horizontal,
241
284
  style,
242
285
  refView,
243
- ...rest
286
+ ...props
244
287
  }) {
245
288
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
246
289
  const base = {
@@ -248,7 +291,8 @@ var PositionViewState = typedMemo(function PositionView({
248
291
  };
249
292
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
250
293
  const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
251
- 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 });
252
296
  });
253
297
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
254
298
  id,
@@ -293,16 +337,27 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
293
337
  }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
294
338
  return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
295
339
  });
296
- var PositionView2 = PositionViewState;
340
+ var PositionView = PositionViewState;
297
341
 
298
342
  // src/constants-platform.ts
299
343
  var IsNewArchitecture = true;
300
344
 
301
345
  // src/state/ContextContainer.ts
302
346
  var ContextContainer = createContext(null);
347
+ function useContextContainer() {
348
+ return useContext(ContextContainer);
349
+ }
303
350
  function useIsLastItem() {
304
- const { itemKey } = useContext(ContextContainer);
305
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
351
+ const containerContext = useContextContainer();
352
+ const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
353
+ if (containerContext) {
354
+ const { itemKey } = containerContext;
355
+ if (!isNullOrUndefined(itemKey)) {
356
+ return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
357
+ }
358
+ }
359
+ return false;
360
+ });
306
361
  return isLast;
307
362
  }
308
363
 
@@ -348,10 +403,9 @@ function createResizeObserver(element, callback) {
348
403
  }
349
404
  callbacks.add(callback);
350
405
  return () => {
351
- const callbacks2 = callbackMap.get(element);
352
- if (callbacks2) {
353
- callbacks2.delete(callback);
354
- if (callbacks2.size === 0) {
406
+ if (callbacks) {
407
+ callbacks.delete(callback);
408
+ if (callbacks.size === 0) {
355
409
  callbackMap.delete(element);
356
410
  observer.unobserve(element);
357
411
  }
@@ -386,10 +440,10 @@ function useOnLayoutSync({
386
440
  return createResizeObserver(element, (entry) => {
387
441
  var _a4;
388
442
  const target = entry.target instanceof HTMLElement ? entry.target : void 0;
389
- const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
390
- if (rect2.width !== prevRect.width || rect2.height !== prevRect.height) {
391
- prevRect = rect2;
392
- emit(toLayout(rect2), false);
443
+ const rectObserved = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
444
+ if (rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height) {
445
+ prevRect = rectObserved;
446
+ emit(toLayout(rectObserved), false);
393
447
  }
394
448
  });
395
449
  }, deps || []);
@@ -517,7 +571,7 @@ var Container = typedMemo(function Container2({
517
571
  },
518
572
  [itemKey, layoutRenderCount]
519
573
  );
520
- const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
574
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
521
575
  return /* @__PURE__ */ React3.createElement(
522
576
  PositionComponent,
523
577
  {
@@ -710,7 +764,8 @@ var Containers = typedMemo(function Containers2({
710
764
  return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
711
765
  });
712
766
  function DevNumbers() {
713
- return IS_DEV && React3.memo(function DevNumbers2() {
767
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
768
+ React3.memo(function DevNumbers2() {
714
769
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3.createElement(
715
770
  "div",
716
771
  {
@@ -758,7 +813,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
758
813
  }, ref) {
759
814
  const scrollRef = useRef(null);
760
815
  const contentRef = useRef(null);
761
- const momentumTimeout = useRef(null);
762
816
  useImperativeHandle(ref, () => {
763
817
  const api = {
764
818
  getBoundingClientRect: () => {
@@ -824,16 +878,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
824
878
  }
825
879
  };
826
880
  onScroll2(scrollEvent);
827
- if (onMomentumScrollEnd) {
828
- if (momentumTimeout.current != null) clearTimeout(momentumTimeout.current);
829
- momentumTimeout.current = setTimeout(() => {
830
- onMomentumScrollEnd({
831
- nativeEvent: {
832
- contentOffset: scrollEvent.nativeEvent.contentOffset
833
- }
834
- });
835
- }, 100);
836
- }
837
881
  },
838
882
  [onScroll2, onMomentumScrollEnd]
839
883
  );
@@ -895,7 +939,8 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
895
939
  minWidth: horizontal ? "100%" : void 0,
896
940
  ...StyleSheet.flatten(contentContainerStyle)
897
941
  };
898
- return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
942
+ const { contentInset, scrollEventThrottle, ScrollComponent, ...webProps } = props;
943
+ return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
899
944
  });
900
945
  function Padding() {
901
946
  const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
@@ -936,7 +981,7 @@ function ScrollAdjust() {
936
981
  const scrollAdjust = peek$(ctx, "scrollAdjust");
937
982
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
938
983
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
939
- const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
984
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
940
985
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
941
986
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
942
987
  if (scrollDelta !== 0) {
@@ -944,26 +989,23 @@ function ScrollAdjust() {
944
989
  const prevScroll = el.scrollTop;
945
990
  const nextScroll = prevScroll + scrollDelta;
946
991
  const totalSize = el.scrollHeight;
947
- if (scrollDelta > 0 && !ctx.internalState.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
992
+ if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
948
993
  const child = el.firstElementChild;
949
994
  const prevPaddingBottom = child.style.paddingBottom;
950
995
  const pad = (nextScroll + el.clientHeight - totalSize) * 2;
951
996
  child.style.paddingBottom = `${pad}px`;
952
997
  void el.offsetHeight;
953
998
  scrollView.scrollBy(0, scrollDelta);
954
- setTimeout(() => {
999
+ requestAnimationFrame(() => {
955
1000
  child.style.paddingBottom = prevPaddingBottom;
956
- }, 100);
1001
+ });
957
1002
  } else {
958
1003
  scrollView.scrollBy(0, scrollDelta);
959
1004
  }
960
- if (IS_DEV) {
961
- console.log("ScrollAdjust (web scrollBy)", scrollDelta, "total offset:", scrollOffset);
962
- }
963
1005
  }
964
1006
  lastScrollOffsetRef.current = scrollOffset;
965
1007
  }
966
- }, []);
1008
+ }, [ctx]);
967
1009
  useValueListener$("scrollAdjust", callback);
968
1010
  useValueListener$("scrollAdjustUserOffset", callback);
969
1011
  return null;
@@ -1021,13 +1063,6 @@ var ListComponent = typedMemo(function ListComponent2({
1021
1063
  () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1022
1064
  [renderScrollComponent]
1023
1065
  ) : ListComponentScrollView;
1024
- React3.useEffect(() => {
1025
- if (canRender) {
1026
- setTimeout(() => {
1027
- scrollAdjustHandler.setMounted();
1028
- }, 0);
1029
- }
1030
- }, [canRender]);
1031
1066
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1032
1067
  return /* @__PURE__ */ React3.createElement(
1033
1068
  SnapOrScroll,
@@ -1091,10 +1126,11 @@ function getId(state, index) {
1091
1126
  }
1092
1127
 
1093
1128
  // src/core/calculateOffsetForIndex.ts
1094
- function calculateOffsetForIndex(ctx, state, index) {
1129
+ function calculateOffsetForIndex(ctx, index) {
1130
+ const state = ctx.state;
1095
1131
  let position = 0;
1096
1132
  if (index !== void 0) {
1097
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
1133
+ position = state.positions.get(getId(state, index)) || 0;
1098
1134
  const paddingTop = peek$(ctx, "stylePaddingTop");
1099
1135
  if (paddingTop) {
1100
1136
  position += paddingTop;
@@ -1108,7 +1144,8 @@ function calculateOffsetForIndex(ctx, state, index) {
1108
1144
  }
1109
1145
 
1110
1146
  // src/utils/setPaddingTop.ts
1111
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1147
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1148
+ const state = ctx.state;
1112
1149
  if (stylePaddingTop !== void 0) {
1113
1150
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1114
1151
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -1127,7 +1164,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1127
1164
  }
1128
1165
 
1129
1166
  // src/utils/updateAlignItemsPaddingTop.ts
1130
- function updateAlignItemsPaddingTop(ctx, state) {
1167
+ function updateAlignItemsPaddingTop(ctx) {
1168
+ const state = ctx.state;
1131
1169
  const {
1132
1170
  scrollLength,
1133
1171
  props: { alignItemsAtEnd, data }
@@ -1138,12 +1176,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
1138
1176
  const contentSize = getContentSize(ctx);
1139
1177
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1140
1178
  }
1141
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1179
+ setPaddingTop(ctx, { alignItemsPaddingTop });
1142
1180
  }
1143
1181
  }
1144
1182
 
1145
1183
  // src/core/addTotalSize.ts
1146
- function addTotalSize(ctx, state, key, add) {
1184
+ function addTotalSize(ctx, key, add) {
1185
+ const state = ctx.state;
1147
1186
  const { alignItemsAtEnd } = state.props;
1148
1187
  const prevTotalSize = state.totalSize;
1149
1188
  let totalSize = state.totalSize;
@@ -1162,31 +1201,34 @@ function addTotalSize(ctx, state, key, add) {
1162
1201
  state.totalSize = totalSize;
1163
1202
  set$(ctx, "totalSize", totalSize);
1164
1203
  if (alignItemsAtEnd) {
1165
- updateAlignItemsPaddingTop(ctx, state);
1204
+ updateAlignItemsPaddingTop(ctx);
1166
1205
  }
1167
1206
  }
1168
1207
  }
1169
1208
  }
1170
1209
 
1171
1210
  // src/core/setSize.ts
1172
- function setSize(ctx, state, itemKey, size) {
1211
+ function setSize(ctx, itemKey, size) {
1212
+ const state = ctx.state;
1173
1213
  const { sizes } = state;
1174
1214
  const previousSize = sizes.get(itemKey);
1175
1215
  const diff = previousSize !== void 0 ? size - previousSize : size;
1176
1216
  if (diff !== 0) {
1177
- addTotalSize(ctx, state, itemKey, diff);
1217
+ addTotalSize(ctx, itemKey, diff);
1178
1218
  }
1179
1219
  sizes.set(itemKey, size);
1180
1220
  }
1181
1221
 
1182
1222
  // src/utils/getItemSize.ts
1183
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1223
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1184
1224
  var _a3, _b;
1225
+ const state = ctx.state;
1185
1226
  const {
1186
1227
  sizesKnown,
1187
1228
  sizes,
1188
1229
  averageSizes,
1189
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1230
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1231
+ scrollingTo
1190
1232
  } = state;
1191
1233
  const sizeKnown = sizesKnown.get(key);
1192
1234
  if (sizeKnown !== void 0) {
@@ -1194,7 +1236,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1194
1236
  }
1195
1237
  let size;
1196
1238
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1197
- const scrollingTo = peek$(ctx, "scrollingTo");
1198
1239
  if (preferCachedSize) {
1199
1240
  const cachedSize = sizes.get(key);
1200
1241
  if (cachedSize !== void 0) {
@@ -1222,81 +1263,169 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1222
1263
  if (size === void 0) {
1223
1264
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1224
1265
  }
1225
- setSize(ctx, state, key, size);
1266
+ setSize(ctx, key, size);
1226
1267
  return size;
1227
1268
  }
1228
1269
 
1229
1270
  // src/core/calculateOffsetWithOffsetPosition.ts
1230
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1271
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1272
+ const state = ctx.state;
1231
1273
  const { index, viewOffset, viewPosition } = params;
1232
1274
  let offset = offsetParam;
1233
1275
  if (viewOffset) {
1234
1276
  offset -= viewOffset;
1235
1277
  }
1236
1278
  if (viewPosition !== void 0 && index !== void 0) {
1237
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1279
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1280
+ const trailingInset = getContentInsetEnd(state);
1281
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1238
1282
  }
1239
1283
  return offset;
1240
1284
  }
1241
1285
 
1286
+ // src/core/clampScrollOffset.ts
1287
+ function clampScrollOffset(ctx, offset) {
1288
+ const state = ctx.state;
1289
+ const contentSize = getContentSize(ctx);
1290
+ let clampedOffset = offset;
1291
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1292
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1293
+ clampedOffset = Math.min(offset, maxOffset);
1294
+ }
1295
+ clampedOffset = Math.max(0, clampedOffset);
1296
+ return clampedOffset;
1297
+ }
1298
+
1299
+ // src/utils/setInitialRenderState.ts
1300
+ function setInitialRenderState(ctx, {
1301
+ didLayout,
1302
+ didInitialScroll
1303
+ }) {
1304
+ const { state } = ctx;
1305
+ if (didLayout) {
1306
+ state.didContainersLayout = true;
1307
+ }
1308
+ if (didInitialScroll) {
1309
+ state.didFinishInitialScroll = true;
1310
+ }
1311
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1312
+ set$(ctx, "readyToRender", true);
1313
+ }
1314
+ }
1315
+
1242
1316
  // src/core/finishScrollTo.ts
1243
- function finishScrollTo(ctx, state) {
1317
+ function finishScrollTo(ctx) {
1244
1318
  var _a3, _b;
1245
- if (state) {
1319
+ const state = ctx.state;
1320
+ if (state == null ? void 0 : state.scrollingTo) {
1246
1321
  state.scrollHistory.length = 0;
1247
1322
  state.initialScroll = void 0;
1248
1323
  state.initialAnchor = void 0;
1249
- set$(ctx, "scrollingTo", void 0);
1324
+ state.scrollingTo = void 0;
1250
1325
  if (state.pendingTotalSize !== void 0) {
1251
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1326
+ addTotalSize(ctx, null, state.pendingTotalSize);
1252
1327
  }
1253
1328
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1254
1329
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1255
1330
  }
1331
+ {
1332
+ state.scrollAdjustHandler.commitPendingAdjust();
1333
+ }
1334
+ setInitialRenderState(ctx, { didInitialScroll: true });
1335
+ }
1336
+ }
1337
+
1338
+ // src/core/doScrollTo.ts
1339
+ var SCROLL_END_IDLE_MS = 80;
1340
+ var SCROLL_END_MAX_MS = 1500;
1341
+ var SMOOTH_SCROLL_DURATION_MS = 320;
1342
+ function doScrollTo(ctx, params) {
1343
+ const state = ctx.state;
1344
+ const { animated, horizontal, offset } = params;
1345
+ const scroller = state.refScroller.current;
1346
+ const node = typeof (scroller == null ? void 0 : scroller.getScrollableNode) === "function" ? scroller.getScrollableNode() : scroller;
1347
+ if (node) {
1348
+ const left = horizontal ? offset : 0;
1349
+ const top = horizontal ? 0 : offset;
1350
+ node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1351
+ if (animated) {
1352
+ listenForScrollEnd(ctx, node);
1353
+ } else {
1354
+ state.scroll = offset;
1355
+ setTimeout(() => {
1356
+ finishScrollTo(ctx);
1357
+ }, 100);
1358
+ }
1256
1359
  }
1257
1360
  }
1361
+ function listenForScrollEnd(ctx, node) {
1362
+ const supportsScrollEnd = "onscrollend" in node;
1363
+ let idleTimeout;
1364
+ let maxTimeout;
1365
+ let settled = false;
1366
+ const targetToken = ctx.state.scrollingTo;
1367
+ const finish = () => {
1368
+ if (settled) return;
1369
+ settled = true;
1370
+ cleanup();
1371
+ if (targetToken === ctx.state.scrollingTo) {
1372
+ finishScrollTo(ctx);
1373
+ }
1374
+ };
1375
+ const onScroll2 = () => {
1376
+ if (idleTimeout) {
1377
+ clearTimeout(idleTimeout);
1378
+ }
1379
+ idleTimeout = setTimeout(finish, SCROLL_END_IDLE_MS);
1380
+ };
1381
+ const cleanup = () => {
1382
+ if (supportsScrollEnd) {
1383
+ node.removeEventListener("scrollend", finish);
1384
+ } else {
1385
+ node.removeEventListener("scroll", onScroll2);
1386
+ }
1387
+ if (idleTimeout) {
1388
+ clearTimeout(idleTimeout);
1389
+ }
1390
+ if (maxTimeout) {
1391
+ clearTimeout(maxTimeout);
1392
+ }
1393
+ };
1394
+ if (supportsScrollEnd) {
1395
+ node.addEventListener("scrollend", finish, { once: true });
1396
+ } else {
1397
+ node.addEventListener("scroll", onScroll2);
1398
+ idleTimeout = setTimeout(finish, SMOOTH_SCROLL_DURATION_MS);
1399
+ maxTimeout = setTimeout(finish, SCROLL_END_MAX_MS);
1400
+ }
1401
+ return cleanup;
1402
+ }
1258
1403
 
1259
1404
  // src/core/scrollTo.ts
1260
- function scrollTo(ctx, state, params) {
1261
- var _a3;
1262
- const { noScrollingTo, ...scrollTarget } = params;
1405
+ function scrollTo(ctx, params) {
1406
+ const state = ctx.state;
1407
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1263
1408
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1264
1409
  const {
1265
- refScroller,
1266
1410
  props: { horizontal }
1267
1411
  } = state;
1268
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1269
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1270
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1271
- offset = Math.min(offset, maxOffset);
1412
+ if (state.animFrameCheckFinishedScroll) {
1413
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1272
1414
  }
1415
+ if (state.timeoutCheckFinishedScrollFallback) {
1416
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1417
+ }
1418
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1419
+ offset = clampScrollOffset(ctx, offset);
1273
1420
  state.scrollHistory.length = 0;
1274
1421
  if (!noScrollingTo) {
1275
- set$(ctx, "scrollingTo", scrollTarget);
1422
+ state.scrollingTo = scrollTarget;
1276
1423
  }
1277
1424
  state.scrollPending = offset;
1278
- if (!isInitialScroll || Platform.OS === "android") {
1279
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1280
- animated: !!animated,
1281
- x: horizontal ? offset : 0,
1282
- y: horizontal ? 0 : offset
1283
- });
1284
- }
1285
- if (!animated) {
1425
+ if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1426
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1427
+ } else {
1286
1428
  state.scroll = offset;
1287
- {
1288
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1289
- if (value && peek$(ctx, "scrollingTo")) {
1290
- finishScrollTo(ctx, state);
1291
- unlisten();
1292
- }
1293
- });
1294
- }
1295
- if (isInitialScroll) {
1296
- setTimeout(() => {
1297
- state.initialScroll = void 0;
1298
- }, 500);
1299
- }
1300
1429
  }
1301
1430
  }
1302
1431
 
@@ -1305,6 +1434,12 @@ var HYSTERESIS_MULTIPLIER = 1.3;
1305
1434
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1306
1435
  const absDistance = Math.abs(distance);
1307
1436
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1437
+ if (wasReached === null) {
1438
+ if (!within && distance >= 0) {
1439
+ return false;
1440
+ }
1441
+ return null;
1442
+ }
1308
1443
  const updateSnapshot = () => {
1309
1444
  setSnapshot == null ? void 0 : setSnapshot({
1310
1445
  atThreshold,
@@ -1337,8 +1472,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1337
1472
  };
1338
1473
 
1339
1474
  // src/utils/checkAtBottom.ts
1340
- function checkAtBottom(ctx, state) {
1475
+ function checkAtBottom(ctx) {
1341
1476
  var _a3;
1477
+ const state = ctx.state;
1342
1478
  if (!state) {
1343
1479
  return;
1344
1480
  }
@@ -1411,15 +1547,15 @@ function checkAtTop(state) {
1411
1547
  }
1412
1548
 
1413
1549
  // src/core/updateScroll.ts
1414
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1550
+ function updateScroll(ctx, newScroll, forceUpdate) {
1415
1551
  var _a3;
1416
- const scrollingTo = peek$(ctx, "scrollingTo");
1552
+ const state = ctx.state;
1553
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1417
1554
  state.hasScrolled = true;
1418
1555
  state.lastBatchingAction = Date.now();
1419
1556
  const currentTime = Date.now();
1420
- const adjust = state.scrollAdjustHandler.getAdjust();
1421
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1422
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1557
+ const adjust = scrollAdjustHandler.getAdjust();
1558
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1423
1559
  if (adjustChanged) {
1424
1560
  state.scrollHistory.length = 0;
1425
1561
  }
@@ -1444,17 +1580,21 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1444
1580
  return;
1445
1581
  }
1446
1582
  }
1447
- if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1583
+ const lastCalculated = state.scrollLastCalculate;
1584
+ const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1585
+ if (shouldUpdate) {
1586
+ state.scrollLastCalculate = state.scroll;
1448
1587
  state.ignoreScrollFromMVCPIgnored = false;
1449
1588
  (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1450
- checkAtBottom(ctx, state);
1589
+ checkAtBottom(ctx);
1451
1590
  checkAtTop(state);
1452
1591
  state.dataChangeNeedsScrollUpdate = false;
1453
1592
  }
1454
1593
  }
1455
1594
 
1456
1595
  // src/utils/requestAdjust.ts
1457
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1596
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1597
+ const state = ctx.state;
1458
1598
  if (Math.abs(positionDiff) > 0.1) {
1459
1599
  const doit = () => {
1460
1600
  {
@@ -1466,8 +1606,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1466
1606
  };
1467
1607
  state.scroll += positionDiff;
1468
1608
  state.scrollForNextCalculateItemsInView = void 0;
1469
- const didLayout = peek$(ctx, "containersDidLayout");
1470
- if (didLayout) {
1609
+ const readyToRender = peek$(ctx, "readyToRender");
1610
+ if (readyToRender) {
1471
1611
  doit();
1472
1612
  } else {
1473
1613
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -1476,73 +1616,23 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1476
1616
  }
1477
1617
  }
1478
1618
 
1479
- // src/core/ensureInitialAnchor.ts
1480
- var INITIAL_ANCHOR_TOLERANCE = 0.5;
1481
- var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1482
- var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1483
- function ensureInitialAnchor(ctx, state) {
1484
- var _a3, _b, _c, _d, _e;
1485
- const anchor = state.initialAnchor;
1486
- const item = state.props.data[anchor.index];
1487
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1488
- if (!containersDidLayout) {
1489
- return;
1490
- }
1491
- const id = getId(state, anchor.index);
1492
- if (state.positions.get(id) === void 0) {
1493
- return;
1494
- }
1495
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1496
- if (size === void 0) {
1497
- return;
1498
- }
1499
- const availableSpace = Math.max(0, state.scrollLength - size);
1500
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1501
- const contentSize = getContentSize(ctx);
1502
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1503
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1504
- const delta = clampedDesiredOffset - state.scroll;
1505
- if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1506
- const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1507
- if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1508
- state.initialAnchor = void 0;
1509
- } else {
1510
- anchor.settledTicks = settledTicks;
1511
- }
1512
- return;
1513
- }
1514
- if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1515
- state.initialAnchor = void 0;
1516
- return;
1517
- }
1518
- const lastDelta = anchor.lastDelta;
1519
- if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1520
- state.initialAnchor = void 0;
1521
- return;
1522
- }
1523
- Object.assign(anchor, {
1524
- attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1525
- lastDelta: delta,
1526
- settledTicks: 0
1527
- });
1528
- requestAdjust(ctx, state, delta);
1529
- }
1530
-
1531
1619
  // src/core/mvcp.ts
1532
- function prepareMVCP(ctx, state, dataChanged) {
1620
+ function prepareMVCP(ctx, dataChanged) {
1621
+ const state = ctx.state;
1533
1622
  const { idsInView, positions, props } = state;
1534
1623
  const { maintainVisibleContentPosition } = props;
1535
- const scrollingTo = peek$(ctx, "scrollingTo");
1624
+ const scrollingTo = state.scrollingTo;
1536
1625
  let prevPosition;
1537
1626
  let targetId;
1538
1627
  const idsInViewWithPositions = [];
1539
1628
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1629
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1540
1630
  const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1541
1631
  const indexByKey = state.indexByKey;
1542
1632
  if (shouldMVCP) {
1543
1633
  if (scrollTarget !== void 0) {
1544
1634
  targetId = getId(state, scrollTarget);
1545
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1635
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1546
1636
  if (dataChanged) {
1547
1637
  for (let i = 0; i < idsInView.length; i++) {
1548
1638
  const id = idsInView[i];
@@ -1559,7 +1649,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1559
1649
  prevPosition = positions.get(targetId);
1560
1650
  }
1561
1651
  return () => {
1562
- let positionDiff;
1652
+ let positionDiff = 0;
1563
1653
  if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1564
1654
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1565
1655
  const { id, position } = idsInViewWithPositions[i];
@@ -1585,16 +1675,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1585
1675
  positionDiff = diff;
1586
1676
  }
1587
1677
  }
1588
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1589
- requestAdjust(ctx, state, positionDiff);
1678
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1679
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1680
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1681
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1682
+ const diff = newSize - prevSize;
1683
+ if (diff !== 0) {
1684
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1685
+ scrollingTo.itemSize = newSize;
1686
+ }
1687
+ }
1688
+ }
1689
+ if (Math.abs(positionDiff) > 0.1) {
1690
+ requestAdjust(ctx, positionDiff);
1590
1691
  }
1591
1692
  };
1592
1693
  }
1593
1694
  }
1594
1695
 
1595
1696
  // src/core/prepareColumnStartState.ts
1596
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1697
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1597
1698
  var _a3;
1699
+ const state = ctx.state;
1598
1700
  const numColumns = peek$(ctx, "numColumns");
1599
1701
  let rowStartIndex = startIndex;
1600
1702
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1609,7 +1711,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1609
1711
  const prevId = state.idCache[prevIndex];
1610
1712
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1611
1713
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1612
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1714
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1613
1715
  currentRowTop = prevPosition + prevRowHeight;
1614
1716
  }
1615
1717
  return {
@@ -1632,7 +1734,8 @@ function findRowStartIndex(state, numColumns, index) {
1632
1734
  }
1633
1735
  return rowStart;
1634
1736
  }
1635
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1737
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1738
+ const state = ctx.state;
1636
1739
  if (endIndex < startIndex) {
1637
1740
  return 0;
1638
1741
  }
@@ -1646,7 +1749,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1646
1749
  continue;
1647
1750
  }
1648
1751
  const id = state.idCache[i];
1649
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1752
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1650
1753
  if (size > maxSize) {
1651
1754
  maxSize = size;
1652
1755
  }
@@ -1655,22 +1758,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1655
1758
  }
1656
1759
 
1657
1760
  // src/core/updateTotalSize.ts
1658
- function updateTotalSize(ctx, state) {
1761
+ function updateTotalSize(ctx) {
1762
+ const state = ctx.state;
1659
1763
  const {
1660
1764
  positions,
1661
1765
  props: { data }
1662
1766
  } = state;
1663
1767
  if (data.length === 0) {
1664
- addTotalSize(ctx, state, null, 0);
1768
+ addTotalSize(ctx, null, 0);
1665
1769
  } else {
1666
1770
  const lastId = getId(state, data.length - 1);
1667
1771
  if (lastId !== void 0) {
1668
1772
  const lastPosition = positions.get(lastId);
1669
1773
  if (lastPosition !== void 0) {
1670
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1774
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1671
1775
  if (lastSize !== void 0) {
1672
1776
  const totalSize = lastPosition + lastSize;
1673
- addTotalSize(ctx, state, null, totalSize);
1777
+ addTotalSize(ctx, null, totalSize);
1674
1778
  }
1675
1779
  }
1676
1780
  }
@@ -1716,7 +1820,8 @@ var getScrollVelocity = (state) => {
1716
1820
  };
1717
1821
 
1718
1822
  // src/utils/updateSnapToOffsets.ts
1719
- function updateSnapToOffsets(ctx, state) {
1823
+ function updateSnapToOffsets(ctx) {
1824
+ const state = ctx.state;
1720
1825
  const {
1721
1826
  positions,
1722
1827
  props: { snapToIndices }
@@ -1731,30 +1836,30 @@ function updateSnapToOffsets(ctx, state) {
1731
1836
  }
1732
1837
 
1733
1838
  // src/core/updateItemPositions.ts
1734
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1839
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1735
1840
  doMVCP: false,
1736
1841
  forceFullUpdate: false,
1737
1842
  scrollBottomBuffered: -1,
1738
1843
  startIndex: 0
1739
1844
  }) {
1740
1845
  var _a3, _b, _c, _d, _e;
1846
+ const state = ctx.state;
1741
1847
  const {
1742
1848
  columns,
1743
1849
  indexByKey,
1744
1850
  positions,
1745
1851
  idCache,
1746
1852
  sizesKnown,
1747
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1853
+ props: { data, getEstimatedItemSize, snapToIndices },
1854
+ scrollingTo
1748
1855
  } = state;
1749
- const data = state.props.data;
1750
1856
  const dataLength = data.length;
1751
1857
  const numColumns = peek$(ctx, "numColumns");
1752
- const scrollingTo = peek$(ctx, "scrollingTo");
1753
1858
  const hasColumns = numColumns > 1;
1754
1859
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1755
1860
  const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1756
1861
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1757
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1862
+ const useAverageSize = !getEstimatedItemSize;
1758
1863
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1759
1864
  let currentRowTop = 0;
1760
1865
  let column = 1;
@@ -1763,7 +1868,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1763
1868
  if (hasColumns) {
1764
1869
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1765
1870
  ctx,
1766
- state,
1767
1871
  startIndex,
1768
1872
  useAverageSize
1769
1873
  );
@@ -1773,7 +1877,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1773
1877
  const prevIndex = startIndex - 1;
1774
1878
  const prevId = getId(state, prevIndex);
1775
1879
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1776
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1880
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1777
1881
  currentRowTop = prevPosition + prevSize;
1778
1882
  }
1779
1883
  }
@@ -1790,7 +1894,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1790
1894
  breakAt = i + itemsPerRow + 10;
1791
1895
  }
1792
1896
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1793
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1897
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1794
1898
  if (IS_DEV && needsIndexByKey) {
1795
1899
  if (indexByKeyForChecking.has(id)) {
1796
1900
  console.error(
@@ -1799,7 +1903,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1799
1903
  }
1800
1904
  indexByKeyForChecking.set(id, i);
1801
1905
  }
1802
- positions.set(id, currentRowTop);
1906
+ if (currentRowTop !== positions.get(id)) {
1907
+ positions.set(id, currentRowTop);
1908
+ notifyPosition$(ctx, id, currentRowTop);
1909
+ }
1803
1910
  if (needsIndexByKey) {
1804
1911
  indexByKey.set(id, i);
1805
1912
  }
@@ -1819,10 +1926,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1819
1926
  }
1820
1927
  }
1821
1928
  if (!didBreakEarly) {
1822
- updateTotalSize(ctx, state);
1929
+ updateTotalSize(ctx);
1823
1930
  }
1824
1931
  if (snapToIndices) {
1825
- updateSnapToOffsets(ctx, state);
1932
+ updateSnapToOffsets(ctx);
1826
1933
  }
1827
1934
  }
1828
1935
 
@@ -1900,7 +2007,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1900
2007
  if (previousViewableItems) {
1901
2008
  for (const viewToken of previousViewableItems) {
1902
2009
  const containerId = findContainerId(ctx, viewToken.key);
1903
- if (!isViewable(
2010
+ if (!checkIsViewable(
1904
2011
  state,
1905
2012
  ctx,
1906
2013
  viewabilityConfig,
@@ -1921,7 +2028,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1921
2028
  if (item) {
1922
2029
  const key = getId(state, i);
1923
2030
  const containerId = findContainerId(ctx, key);
1924
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2031
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
1925
2032
  const viewToken = {
1926
2033
  containerId,
1927
2034
  index: i,
@@ -1981,11 +2088,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1981
2088
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
1982
2089
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
1983
2090
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
1984
- const isViewable2 = percent >= viewablePercentThreshold;
2091
+ const isViewable = percent >= viewablePercentThreshold;
1985
2092
  const value = {
1986
2093
  containerId,
1987
2094
  index,
1988
- isViewable: isViewable2,
2095
+ isViewable,
1989
2096
  item,
1990
2097
  key,
1991
2098
  percentOfScroller,
@@ -2004,8 +2111,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2004
2111
  }
2005
2112
  return value;
2006
2113
  }
2007
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2008
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2114
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2115
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2116
+ if (!value || value.key !== key) {
2117
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2118
+ }
2009
2119
  return value.isViewable;
2010
2120
  }
2011
2121
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -2033,8 +2143,9 @@ function checkAllSizesKnown(state) {
2033
2143
  }
2034
2144
 
2035
2145
  // src/utils/findAvailableContainers.ts
2036
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2146
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2037
2147
  const numContainers = peek$(ctx, "numContainers");
2148
+ const state = ctx.state;
2038
2149
  const { stickyContainerPool, containerItemTypes } = state;
2039
2150
  const result = [];
2040
2151
  const availableContainers = [];
@@ -2078,14 +2189,14 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
2078
2189
  continue;
2079
2190
  }
2080
2191
  const key = peek$(ctx, `containerItemKey${u}`);
2081
- let isOk = key === void 0;
2082
- if (!isOk && pendingRemovalSet.has(u)) {
2083
- pendingRemovalSet.delete(u);
2084
- pendingRemovalChanged = true;
2085
- const requiredType = neededTypes[typeIndex];
2086
- isOk = canReuseContainer(u, requiredType);
2087
- }
2088
- if (isOk) {
2192
+ const requiredType = neededTypes[typeIndex];
2193
+ const isPending = key !== void 0 && pendingRemovalSet.has(u);
2194
+ const canUse = key === void 0 || isPending && canReuseContainer(u, requiredType);
2195
+ if (canUse) {
2196
+ if (isPending) {
2197
+ pendingRemovalSet.delete(u);
2198
+ pendingRemovalChanged = true;
2199
+ }
2089
2200
  result.push(u);
2090
2201
  if (requiredItemTypes) {
2091
2202
  typeIndex++;
@@ -2154,21 +2265,26 @@ function comparatorByDistance(a, b) {
2154
2265
  }
2155
2266
 
2156
2267
  // src/core/scrollToIndex.ts
2157
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2158
- if (index >= state.props.data.length) {
2159
- index = state.props.data.length - 1;
2268
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2269
+ const state = ctx.state;
2270
+ const { data } = state.props;
2271
+ if (index >= data.length) {
2272
+ index = data.length - 1;
2160
2273
  } else if (index < 0) {
2161
2274
  index = 0;
2162
2275
  }
2163
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2164
- const isLast = index === state.props.data.length - 1;
2276
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2277
+ const isLast = index === data.length - 1;
2165
2278
  if (isLast && viewPosition === void 0) {
2166
2279
  viewPosition = 1;
2167
2280
  }
2168
2281
  state.scrollForNextCalculateItemsInView = void 0;
2169
- scrollTo(ctx, state, {
2282
+ const targetId = getId(state, index);
2283
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2284
+ scrollTo(ctx, {
2170
2285
  animated,
2171
2286
  index,
2287
+ itemSize,
2172
2288
  offset: firstIndexOffset,
2173
2289
  viewOffset,
2174
2290
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2176,16 +2292,17 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2176
2292
  }
2177
2293
 
2178
2294
  // src/utils/setDidLayout.ts
2179
- function setDidLayout(ctx, state) {
2295
+ function setDidLayout(ctx) {
2296
+ const state = ctx.state;
2180
2297
  const {
2181
2298
  loadStartTime,
2182
2299
  initialScroll,
2183
2300
  props: { onLoad }
2184
2301
  } = state;
2185
2302
  state.queuedInitialLayout = true;
2186
- checkAtBottom(ctx, state);
2303
+ checkAtBottom(ctx);
2187
2304
  const setIt = () => {
2188
- set$(ctx, "containersDidLayout", true);
2305
+ setInitialRenderState(ctx, { didLayout: true });
2189
2306
  if (onLoad) {
2190
2307
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2191
2308
  }
@@ -2210,15 +2327,17 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2210
2327
  }
2211
2328
  return -1;
2212
2329
  }
2213
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2330
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2331
+ const state = ctx.state;
2214
2332
  return new Set(
2215
2333
  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))
2216
2334
  );
2217
2335
  }
2218
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2336
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2219
2337
  var _a3;
2220
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2221
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2338
+ const state = ctx.state;
2339
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2340
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2222
2341
  for (let offset = 0; offset <= 1; offset++) {
2223
2342
  const idx = currentStickyIdx - offset;
2224
2343
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -2229,8 +2348,9 @@ function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, cu
2229
2348
  }
2230
2349
  }
2231
2350
  }
2232
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2351
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2233
2352
  var _a3, _b, _c;
2353
+ const state = ctx.state;
2234
2354
  for (const containerIndex of state.stickyContainerPool) {
2235
2355
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2236
2356
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
@@ -2254,7 +2374,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2254
2374
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2255
2375
  if (currentId) {
2256
2376
  const currentPos = state.positions.get(currentId);
2257
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2377
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2258
2378
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2259
2379
  }
2260
2380
  }
@@ -2263,7 +2383,8 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2263
2383
  }
2264
2384
  }
2265
2385
  }
2266
- function calculateItemsInView(ctx, state, params = {}) {
2386
+ function calculateItemsInView(ctx, params = {}) {
2387
+ const state = ctx.state;
2267
2388
  unstable_batchedUpdates(() => {
2268
2389
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2269
2390
  const {
@@ -2287,9 +2408,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2287
2408
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2288
2409
  const prevNumContainers = peek$(ctx, "numContainers");
2289
2410
  if (!data || scrollLength === 0 || !prevNumContainers) {
2290
- if (state.initialAnchor) {
2291
- ensureInitialAnchor(ctx, state);
2292
- }
2293
2411
  return;
2294
2412
  }
2295
2413
  const totalSize = getContentSize(ctx);
@@ -2303,15 +2421,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2303
2421
  if (!queuedInitialLayout && initialScroll) {
2304
2422
  const updatedOffset = calculateOffsetWithOffsetPosition(
2305
2423
  ctx,
2306
- state,
2307
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2424
+ calculateOffsetForIndex(ctx, initialScroll.index),
2308
2425
  initialScroll
2309
2426
  );
2310
2427
  scrollState = updatedOffset;
2311
2428
  }
2312
2429
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2313
2430
  const scrollAdjustPad = scrollAdjustPending - topPad;
2314
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2431
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2315
2432
  if (scroll + scrollLength > totalSize) {
2316
2433
  scroll = Math.max(0, totalSize - scrollLength);
2317
2434
  }
@@ -2319,11 +2436,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2319
2436
  set$(ctx, "debugRawScroll", scrollState);
2320
2437
  set$(ctx, "debugComputedScroll", scroll);
2321
2438
  }
2322
- const previousStickyIndex = state.activeStickyIndex;
2439
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2323
2440
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2324
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2325
- state.activeStickyIndex = nextActiveStickyIndex;
2326
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2441
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2442
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2443
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2444
+ }
2327
2445
  let scrollBufferTop = scrollBuffer;
2328
2446
  let scrollBufferBottom = scrollBuffer;
2329
2447
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2336,23 +2454,20 @@ function calculateItemsInView(ctx, state, params = {}) {
2336
2454
  const scrollTopBuffered = scroll - scrollBufferTop;
2337
2455
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2338
2456
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2339
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2457
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2340
2458
  const { top, bottom } = scrollForNextCalculateItemsInView;
2341
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2342
- if (state.initialAnchor) {
2343
- ensureInitialAnchor(ctx, state);
2344
- }
2459
+ if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2345
2460
  return;
2346
2461
  }
2347
2462
  }
2348
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2463
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2349
2464
  if (dataChanged) {
2350
2465
  indexByKey.clear();
2351
2466
  idCache.length = 0;
2352
2467
  positions.clear();
2353
2468
  }
2354
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2355
- updateItemPositions(ctx, state, dataChanged, {
2469
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2470
+ updateItemPositions(ctx, dataChanged, {
2356
2471
  doMVCP,
2357
2472
  forceFullUpdate: !!forceFullItemPositions,
2358
2473
  scrollBottomBuffered,
@@ -2371,9 +2486,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2371
2486
  for (let i = loopStart; i >= 0; i--) {
2372
2487
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2373
2488
  const top = positions.get(id);
2374
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2489
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2375
2490
  const bottom = top + size;
2376
- if (bottom > scroll - scrollBuffer) {
2491
+ if (bottom > scroll - scrollBufferTop) {
2377
2492
  loopStart = i;
2378
2493
  } else {
2379
2494
  break;
@@ -2398,7 +2513,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2398
2513
  const dataLength = data.length;
2399
2514
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2400
2515
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2401
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2516
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2402
2517
  const top = positions.get(id);
2403
2518
  if (!foundEnd) {
2404
2519
  if (startNoBuffer === null && top + size > scroll) {
@@ -2410,7 +2525,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2410
2525
  if (startBuffered === null && top + size > scrollTopBuffered) {
2411
2526
  startBuffered = i;
2412
2527
  startBufferedId = id;
2413
- nextTop = top;
2528
+ if (scrollTopBuffered < 0) {
2529
+ nextTop = null;
2530
+ } else {
2531
+ nextTop = top;
2532
+ }
2414
2533
  }
2415
2534
  if (startNoBuffer !== null) {
2416
2535
  if (top <= scrollBottom) {
@@ -2418,7 +2537,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2418
2537
  }
2419
2538
  if (top <= scrollBottomBuffered) {
2420
2539
  endBuffered = i;
2421
- nextBottom = top + size;
2540
+ if (scrollBottomBuffered > totalSize) {
2541
+ nextBottom = null;
2542
+ } else {
2543
+ nextBottom = top + size;
2544
+ }
2422
2545
  } else {
2423
2546
  foundEnd = true;
2424
2547
  }
@@ -2445,7 +2568,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2445
2568
  top: nextTop
2446
2569
  } : void 0;
2447
2570
  }
2448
- const numContainers = peek$(ctx, "numContainers");
2571
+ let numContainers = prevNumContainers;
2449
2572
  const pendingRemoval = [];
2450
2573
  if (dataChanged) {
2451
2574
  for (let i = 0; i < numContainers; i++) {
@@ -2456,7 +2579,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2456
2579
  }
2457
2580
  }
2458
2581
  if (startBuffered !== null && endBuffered !== null) {
2459
- let numContainers2 = prevNumContainers;
2460
2582
  const needNewContainers = [];
2461
2583
  for (let i = startBuffered; i <= endBuffered; i++) {
2462
2584
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
@@ -2467,7 +2589,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2467
2589
  if (stickyIndicesArr.length > 0) {
2468
2590
  handleStickyActivation(
2469
2591
  ctx,
2470
- state,
2471
2592
  stickyIndicesSet,
2472
2593
  stickyIndicesArr,
2473
2594
  currentStickyIdx,
@@ -2475,9 +2596,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2475
2596
  startBuffered,
2476
2597
  endBuffered
2477
2598
  );
2478
- } else {
2479
- state.activeStickyIndex = void 0;
2480
- set$(ctx, "activeStickyIndex", void 0);
2599
+ } else if (previousStickyIndex !== -1) {
2600
+ set$(ctx, "activeStickyIndex", -1);
2481
2601
  }
2482
2602
  if (needNewContainers.length > 0) {
2483
2603
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2486,7 +2606,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2486
2606
  }) : void 0;
2487
2607
  const availableContainers = findAvailableContainers(
2488
2608
  ctx,
2489
- state,
2490
2609
  needNewContainers.length,
2491
2610
  startBuffered,
2492
2611
  endBuffered,
@@ -2508,29 +2627,30 @@ function calculateItemsInView(ctx, state, params = {}) {
2508
2627
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2509
2628
  }
2510
2629
  containerItemKeys.add(id);
2630
+ const containerSticky = `containerSticky${containerIndex}`;
2511
2631
  if (stickyIndicesSet.has(i)) {
2512
- set$(ctx, `containerSticky${containerIndex}`, true);
2632
+ set$(ctx, containerSticky, true);
2513
2633
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2514
2634
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2515
2635
  state.stickyContainerPool.add(containerIndex);
2516
- } else {
2517
- set$(ctx, `containerSticky${containerIndex}`, false);
2636
+ } else if (peek$(ctx, containerSticky)) {
2637
+ set$(ctx, containerSticky, false);
2518
2638
  state.stickyContainerPool.delete(containerIndex);
2519
2639
  }
2520
- if (containerIndex >= numContainers2) {
2521
- numContainers2 = containerIndex + 1;
2640
+ if (containerIndex >= numContainers) {
2641
+ numContainers = containerIndex + 1;
2522
2642
  }
2523
2643
  }
2524
- if (numContainers2 !== prevNumContainers) {
2525
- set$(ctx, "numContainers", numContainers2);
2526
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2527
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2644
+ if (numContainers !== prevNumContainers) {
2645
+ set$(ctx, "numContainers", numContainers);
2646
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2647
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2528
2648
  }
2529
2649
  }
2530
2650
  }
2531
2651
  }
2532
2652
  if (stickyIndicesArr.length > 0) {
2533
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2653
+ handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2534
2654
  }
2535
2655
  let didChangePositions = false;
2536
2656
  for (let i = 0; i < numContainers; i++) {
@@ -2582,7 +2702,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2582
2702
  }
2583
2703
  if (!queuedInitialLayout && endBuffered !== null) {
2584
2704
  if (checkAllSizesKnown(state)) {
2585
- setDidLayout(ctx, state);
2705
+ setDidLayout(ctx);
2586
2706
  }
2587
2707
  }
2588
2708
  if (viewabilityConfigCallbackPairs) {
@@ -2595,9 +2715,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2595
2715
  }
2596
2716
  }
2597
2717
  });
2598
- if (state.initialAnchor) {
2599
- ensureInitialAnchor(ctx, state);
2600
- }
2601
2718
  }
2602
2719
 
2603
2720
  // src/core/checkActualChange.ts
@@ -2620,20 +2737,69 @@ function checkActualChange(state, dataProp, previousData) {
2620
2737
  return false;
2621
2738
  }
2622
2739
 
2740
+ // src/core/checkFinishedScroll.ts
2741
+ function checkFinishedScroll(ctx) {
2742
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2743
+ }
2744
+ function checkFinishedScrollFrame(ctx) {
2745
+ const scrollingTo = ctx.state.scrollingTo;
2746
+ if (scrollingTo) {
2747
+ const { state } = ctx;
2748
+ state.animFrameCheckFinishedScroll = void 0;
2749
+ const scroll = state.scroll;
2750
+ const adjust = state.scrollAdjustHandler.getAdjust();
2751
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
2752
+ const maxOffset = clampScrollOffset(ctx, scroll);
2753
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
2754
+ const diff2 = Math.abs(diff1 - adjust);
2755
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
2756
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
2757
+ finishScrollTo(ctx);
2758
+ }
2759
+ }
2760
+ }
2761
+ function checkFinishedScrollFallback(ctx) {
2762
+ const state = ctx.state;
2763
+ const scrollingTo = state.scrollingTo;
2764
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
2765
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
2766
+ () => {
2767
+ let numChecks = 0;
2768
+ const checkHasScrolled = () => {
2769
+ state.timeoutCheckFinishedScrollFallback = void 0;
2770
+ const isStillScrollingTo = state.scrollingTo;
2771
+ if (isStillScrollingTo) {
2772
+ numChecks++;
2773
+ if (state.hasScrolled || numChecks > 5) {
2774
+ finishScrollTo(ctx);
2775
+ } else {
2776
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
2777
+ }
2778
+ }
2779
+ };
2780
+ checkHasScrolled();
2781
+ },
2782
+ slowTimeout ? 500 : 100
2783
+ );
2784
+ }
2785
+
2623
2786
  // src/core/doMaintainScrollAtEnd.ts
2624
- function doMaintainScrollAtEnd(ctx, state, animated) {
2787
+ function doMaintainScrollAtEnd(ctx, animated) {
2788
+ const state = ctx.state;
2625
2789
  const {
2790
+ didContainersLayout,
2791
+ isAtEnd,
2626
2792
  refScroller,
2627
2793
  props: { maintainScrollAtEnd }
2628
2794
  } = state;
2629
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2795
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2630
2796
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2631
2797
  if (paddingTop > 0) {
2632
2798
  state.scroll = 0;
2633
2799
  }
2634
2800
  requestAnimationFrame(() => {
2635
2801
  var _a3;
2636
- if (state == null ? void 0 : state.isAtEnd) {
2802
+ if (state.isAtEnd) {
2637
2803
  state.maintainingScrollAtEnd = true;
2638
2804
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2639
2805
  animated
@@ -2704,28 +2870,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2704
2870
  }
2705
2871
 
2706
2872
  // src/core/checkResetContainers.ts
2707
- function checkResetContainers(ctx, state, dataProp) {
2873
+ function checkResetContainers(ctx, dataProp) {
2874
+ const state = ctx.state;
2708
2875
  const { previousData } = state;
2709
2876
  if (previousData) {
2710
2877
  updateAveragesOnDataChange(state, previousData, dataProp);
2711
2878
  }
2712
2879
  const { maintainScrollAtEnd } = state.props;
2713
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2880
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2714
2881
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2715
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2882
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2716
2883
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2717
2884
  state.isEndReached = false;
2718
2885
  }
2719
2886
  if (!didMaintainScrollAtEnd) {
2720
2887
  checkAtTop(state);
2721
- checkAtBottom(ctx, state);
2888
+ checkAtBottom(ctx);
2722
2889
  }
2723
2890
  delete state.previousData;
2724
2891
  }
2725
2892
 
2726
2893
  // src/core/doInitialAllocateContainers.ts
2727
- function doInitialAllocateContainers(ctx, state) {
2894
+ function doInitialAllocateContainers(ctx) {
2728
2895
  var _a3, _b, _c;
2896
+ const state = ctx.state;
2729
2897
  const {
2730
2898
  scrollLength,
2731
2899
  props: {
@@ -2763,10 +2931,10 @@ function doInitialAllocateContainers(ctx, state) {
2763
2931
  if (state.lastLayout) {
2764
2932
  if (state.initialScroll) {
2765
2933
  requestAnimationFrame(() => {
2766
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2934
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2767
2935
  });
2768
2936
  } else {
2769
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2937
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2770
2938
  }
2771
2939
  }
2772
2940
  return true;
@@ -2774,7 +2942,8 @@ function doInitialAllocateContainers(ctx, state) {
2774
2942
  }
2775
2943
 
2776
2944
  // src/core/handleLayout.ts
2777
- function handleLayout(ctx, state, layout, setCanRender) {
2945
+ function handleLayout(ctx, layout, setCanRender) {
2946
+ const state = ctx.state;
2778
2947
  const { maintainScrollAtEnd } = state.props;
2779
2948
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2780
2949
  const previousLength = state.scrollLength;
@@ -2790,19 +2959,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2790
2959
  state.lastBatchingAction = Date.now();
2791
2960
  state.scrollForNextCalculateItemsInView = void 0;
2792
2961
  if (scrollLength > 0) {
2793
- doInitialAllocateContainers(ctx, state);
2962
+ doInitialAllocateContainers(ctx);
2794
2963
  }
2795
2964
  if (needsCalculate) {
2796
- calculateItemsInView(ctx, state, { doMVCP: true });
2965
+ calculateItemsInView(ctx, { doMVCP: true });
2797
2966
  }
2798
2967
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2799
2968
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2800
2969
  }
2801
2970
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2802
- doMaintainScrollAtEnd(ctx, state, false);
2971
+ doMaintainScrollAtEnd(ctx, false);
2803
2972
  }
2804
- updateAlignItemsPaddingTop(ctx, state);
2805
- checkAtBottom(ctx, state);
2973
+ updateAlignItemsPaddingTop(ctx);
2974
+ checkAtBottom(ctx);
2806
2975
  checkAtTop(state);
2807
2976
  if (state) {
2808
2977
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2818,8 +2987,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2818
2987
  }
2819
2988
 
2820
2989
  // src/core/onScroll.ts
2821
- function onScroll(ctx, state, event) {
2990
+ function onScroll(ctx, event) {
2822
2991
  var _a3, _b, _c;
2992
+ const state = ctx.state;
2823
2993
  const {
2824
2994
  scrollProcessingEnabled,
2825
2995
  props: { onScroll: onScrollProp }
@@ -2830,9 +3000,23 @@ function onScroll(ctx, state, event) {
2830
3000
  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) {
2831
3001
  return;
2832
3002
  }
2833
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3003
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2834
3004
  state.scrollPending = newScroll;
2835
- updateScroll(ctx, state, newScroll);
3005
+ if (state.scrollingTo) {
3006
+ const maxOffset = clampScrollOffset(ctx, newScroll);
3007
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3008
+ newScroll = maxOffset;
3009
+ scrollTo(ctx, {
3010
+ forceScroll: true,
3011
+ isInitialScroll: true,
3012
+ noScrollingTo: true,
3013
+ offset: newScroll
3014
+ });
3015
+ return;
3016
+ }
3017
+ }
3018
+ updateScroll(ctx, newScroll);
3019
+ checkFinishedScroll(ctx);
2836
3020
  onScrollProp == null ? void 0 : onScrollProp(event);
2837
3021
  }
2838
3022
 
@@ -2841,51 +3025,47 @@ var ScrollAdjustHandler = class {
2841
3025
  constructor(ctx) {
2842
3026
  this.appliedAdjust = 0;
2843
3027
  this.pendingAdjust = 0;
2844
- this.mounted = false;
2845
- this.context = ctx;
2846
- {
2847
- const commitPendingAdjust = () => {
2848
- const state = this.context.internalState;
2849
- const pending = this.pendingAdjust;
2850
- if (pending !== 0) {
2851
- this.pendingAdjust = 0;
2852
- this.appliedAdjust += pending;
2853
- state.scroll += pending;
2854
- state.scrollForNextCalculateItemsInView = void 0;
2855
- set$(this.context, "scrollAdjustPending", 0);
2856
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2857
- calculateItemsInView(this.context, this.context.internalState);
2858
- }
2859
- };
2860
- listen$(this.context, "scrollingTo", (value) => {
2861
- if (value === void 0) {
2862
- commitPendingAdjust();
2863
- }
2864
- });
2865
- }
3028
+ this.ctx = ctx;
2866
3029
  }
2867
3030
  requestAdjust(add) {
2868
- const scrollingTo = peek$(this.context, "scrollingTo");
3031
+ const scrollingTo = this.ctx.state.scrollingTo;
2869
3032
  if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2870
3033
  this.pendingAdjust += add;
2871
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
3034
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2872
3035
  } else {
2873
3036
  this.appliedAdjust += add;
2874
- set$(this.context, "scrollAdjust", this.appliedAdjust);
3037
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3038
+ }
3039
+ if (this.ctx.state.scrollingTo) {
3040
+ checkFinishedScroll(this.ctx);
2875
3041
  }
2876
- }
2877
- setMounted() {
2878
- this.mounted = true;
2879
3042
  }
2880
3043
  getAdjust() {
2881
3044
  return this.appliedAdjust;
2882
3045
  }
3046
+ commitPendingAdjust() {
3047
+ {
3048
+ const state = this.ctx.state;
3049
+ const pending = this.pendingAdjust;
3050
+ if (pending !== 0) {
3051
+ this.pendingAdjust = 0;
3052
+ this.appliedAdjust += pending;
3053
+ state.scroll += pending;
3054
+ state.scrollForNextCalculateItemsInView = void 0;
3055
+ set$(this.ctx, "scrollAdjustPending", 0);
3056
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3057
+ calculateItemsInView(this.ctx);
3058
+ }
3059
+ }
3060
+ }
2883
3061
  };
2884
3062
 
2885
3063
  // src/core/updateItemSize.ts
2886
- function updateItemSize(ctx, state, itemKey, sizeObj) {
3064
+ function updateItemSize(ctx, itemKey, sizeObj) {
2887
3065
  var _a3;
3066
+ const state = ctx.state;
2888
3067
  const {
3068
+ didContainersLayout,
2889
3069
  sizesKnown,
2890
3070
  props: {
2891
3071
  getFixedItemSize,
@@ -2913,13 +3093,12 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2913
3093
  return;
2914
3094
  }
2915
3095
  }
2916
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2917
- let needsRecalculate = !containersDidLayout;
3096
+ let needsRecalculate = !didContainersLayout;
2918
3097
  let shouldMaintainScrollAtEnd = false;
2919
3098
  let minIndexSizeChanged;
2920
3099
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2921
3100
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2922
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3101
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
2923
3102
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2924
3103
  if (diff !== 0) {
2925
3104
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
@@ -2968,22 +3147,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2968
3147
  if (!cur || maxOtherAxisSize > cur) {
2969
3148
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
2970
3149
  }
2971
- if (containersDidLayout || checkAllSizesKnown(state)) {
3150
+ if (didContainersLayout || checkAllSizesKnown(state)) {
2972
3151
  if (needsRecalculate) {
2973
3152
  state.scrollForNextCalculateItemsInView = void 0;
2974
- calculateItemsInView(ctx, state, { doMVCP: true });
3153
+ calculateItemsInView(ctx, { doMVCP: true });
2975
3154
  }
2976
3155
  if (shouldMaintainScrollAtEnd) {
2977
3156
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2978
- doMaintainScrollAtEnd(ctx, state, false);
3157
+ doMaintainScrollAtEnd(ctx, false);
2979
3158
  }
2980
3159
  }
2981
3160
  }
2982
3161
  }
2983
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3162
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
2984
3163
  var _a3;
3164
+ const state = ctx.state;
2985
3165
  const {
2986
- sizes,
2987
3166
  indexByKey,
2988
3167
  sizesKnown,
2989
3168
  averageSizes,
@@ -2991,9 +3170,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2991
3170
  } = state;
2992
3171
  if (!data) return 0;
2993
3172
  const index = indexByKey.get(itemKey);
2994
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3173
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
2995
3174
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2996
3175
  const size = Math.round(rawSize) ;
3176
+ const prevSizeKnown = sizesKnown.get(itemKey);
2997
3177
  sizesKnown.set(itemKey, size);
2998
3178
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2999
3179
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -3001,11 +3181,15 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3001
3181
  if (!averages) {
3002
3182
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3003
3183
  }
3004
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3005
- averages.num++;
3184
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3185
+ averages.avg += (size - prevSizeKnown) / averages.num;
3186
+ } else {
3187
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3188
+ averages.num++;
3189
+ }
3006
3190
  }
3007
3191
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
3008
- setSize(ctx, state, itemKey, size);
3192
+ setSize(ctx, itemKey, size);
3009
3193
  return size - prevSize;
3010
3194
  }
3011
3195
  return 0;
@@ -3052,14 +3236,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
3052
3236
  }
3053
3237
 
3054
3238
  // src/utils/createImperativeHandle.ts
3055
- function createImperativeHandle(ctx, state) {
3239
+ function createImperativeHandle(ctx) {
3240
+ const state = ctx.state;
3056
3241
  const scrollIndexIntoView = (options) => {
3057
3242
  if (state) {
3058
3243
  const { index, ...rest } = options;
3059
3244
  const { startNoBuffer, endNoBuffer } = state;
3060
3245
  if (index < startNoBuffer || index > endNoBuffer) {
3061
3246
  const viewPosition = index < startNoBuffer ? 0 : 1;
3062
- scrollToIndex(ctx, state, {
3247
+ scrollToIndex(ctx, {
3063
3248
  ...rest,
3064
3249
  index,
3065
3250
  viewPosition
@@ -3074,7 +3259,7 @@ function createImperativeHandle(ctx, state) {
3074
3259
  getScrollableNode: () => refScroller.current.getScrollableNode(),
3075
3260
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3076
3261
  getState: () => ({
3077
- activeStickyIndex: state.activeStickyIndex,
3262
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3078
3263
  contentLength: state.totalSize,
3079
3264
  data: state.props.data,
3080
3265
  elementAtIndex: (index) => {
@@ -3085,6 +3270,8 @@ function createImperativeHandle(ctx, state) {
3085
3270
  endBuffered: state.endBuffered,
3086
3271
  isAtEnd: state.isAtEnd,
3087
3272
  isAtStart: state.isAtStart,
3273
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3274
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3088
3275
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
3089
3276
  positions: state.positions,
3090
3277
  scroll: state.scroll,
@@ -3109,23 +3296,23 @@ function createImperativeHandle(ctx, state) {
3109
3296
  if (index !== -1) {
3110
3297
  const paddingBottom = stylePaddingBottom || 0;
3111
3298
  const footerSize = peek$(ctx, "footerSize") || 0;
3112
- scrollToIndex(ctx, state, {
3299
+ scrollToIndex(ctx, {
3300
+ ...options,
3113
3301
  index,
3114
3302
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3115
- viewPosition: 1,
3116
- ...options
3303
+ viewPosition: 1
3117
3304
  });
3118
3305
  }
3119
3306
  },
3120
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3307
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
3121
3308
  scrollToItem: ({ item, ...props }) => {
3122
3309
  const data = state.props.data;
3123
3310
  const index = data.indexOf(item);
3124
3311
  if (index !== -1) {
3125
- scrollToIndex(ctx, state, { index, ...props });
3312
+ scrollToIndex(ctx, { index, ...props });
3126
3313
  }
3127
3314
  },
3128
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3315
+ scrollToOffset: (params) => scrollTo(ctx, params),
3129
3316
  setScrollProcessingEnabled: (enabled) => {
3130
3317
  state.scrollProcessingEnabled = enabled;
3131
3318
  },
@@ -3135,8 +3322,9 @@ function createImperativeHandle(ctx, state) {
3135
3322
  }
3136
3323
  };
3137
3324
  }
3138
- function getRenderedItem(ctx, state, key) {
3325
+ function getRenderedItem(ctx, key) {
3139
3326
  var _a3;
3327
+ const state = ctx.state;
3140
3328
  if (!state) {
3141
3329
  return null;
3142
3330
  }
@@ -3213,11 +3401,13 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3213
3401
  var DEFAULT_DRAW_DISTANCE = 250;
3214
3402
  var DEFAULT_ITEM_SIZE = 100;
3215
3403
  var LegendList = typedMemo(
3404
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3216
3405
  typedForwardRef(function LegendList2(props, forwardedRef) {
3217
3406
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3218
3407
  const isChildrenMode = children !== void 0 && dataProp === void 0;
3219
3408
  const processedProps = isChildrenMode ? {
3220
3409
  ...restProps,
3410
+ childrenMode: true,
3221
3411
  data: (isArray(children) ? children : React3.Children.toArray(children)).flat(1),
3222
3412
  renderItem: ({ item }) => item
3223
3413
  } : {
@@ -3234,10 +3424,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3234
3424
  alignItemsAtEnd = false,
3235
3425
  columnWrapperStyle,
3236
3426
  contentContainerStyle: contentContainerStyleProp,
3427
+ contentInset,
3237
3428
  data: dataProp = [],
3238
3429
  dataVersion,
3239
3430
  drawDistance = 250,
3240
- enableAverages = true,
3241
3431
  estimatedItemSize: estimatedItemSizeProp,
3242
3432
  estimatedListSize,
3243
3433
  extraData,
@@ -3279,6 +3469,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3279
3469
  snapToIndices,
3280
3470
  stickyHeaderIndices: stickyHeaderIndicesProp,
3281
3471
  stickyIndices: stickyIndicesDeprecated,
3472
+ // TODOV3: Remove from v3 release
3282
3473
  style: styleProp,
3283
3474
  suggestEstimatedItemSize,
3284
3475
  viewabilityConfig,
@@ -3286,6 +3477,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3286
3477
  waitForInitialLayout = true,
3287
3478
  ...rest
3288
3479
  } = props;
3480
+ const animatedPropsInternal = props.animatedPropsInternal;
3481
+ const { childrenMode } = rest;
3289
3482
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3290
3483
  const style = { ...StyleSheet.flatten(styleProp) };
3291
3484
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
@@ -3309,10 +3502,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3309
3502
  }
3310
3503
  const refState = useRef();
3311
3504
  if (!refState.current) {
3312
- if (!ctx.internalState) {
3505
+ if (!ctx.state) {
3313
3506
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
3314
- ctx.internalState = {
3315
- activeStickyIndex: void 0,
3507
+ ctx.state = {
3508
+ activeStickyIndex: -1,
3316
3509
  averageSizes: {},
3317
3510
  columns: /* @__PURE__ */ new Map(),
3318
3511
  containerItemKeys: /* @__PURE__ */ new Set(),
@@ -3338,9 +3531,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3338
3531
  initialScroll: initialScrollProp,
3339
3532
  isAtEnd: false,
3340
3533
  isAtStart: false,
3341
- isEndReached: false,
3534
+ isEndReached: null,
3342
3535
  isFirst: true,
3343
- isStartReached: false,
3536
+ isStartReached: null,
3344
3537
  lastBatchingAction: Date.now(),
3345
3538
  lastLayout: void 0,
3346
3539
  loadStartTime: Date.now(),
@@ -3372,12 +3565,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3372
3565
  totalSize: 0,
3373
3566
  viewabilityConfigCallbackPairs: void 0
3374
3567
  };
3375
- const internalState = ctx.internalState;
3376
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3568
+ const internalState = ctx.state;
3569
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3377
3570
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3378
3571
  set$(ctx, "extraData", extraData);
3379
3572
  }
3380
- refState.current = ctx.internalState;
3573
+ refState.current = ctx.state;
3381
3574
  }
3382
3575
  const state = refState.current;
3383
3576
  const isFirstLocal = state.isFirst;
@@ -3391,9 +3584,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3391
3584
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3392
3585
  state.props = {
3393
3586
  alignItemsAtEnd,
3587
+ animatedProps: animatedPropsInternal,
3588
+ contentInset,
3394
3589
  data: dataProp,
3395
3590
  dataVersion,
3396
- enableAverages,
3397
3591
  estimatedItemSize,
3398
3592
  getEstimatedItemSize,
3399
3593
  getFixedItemSize,
@@ -3436,62 +3630,52 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3436
3630
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3437
3631
  set$(ctx, "numColumns", numColumnsProp);
3438
3632
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3439
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3633
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3440
3634
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3441
3635
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3442
3636
  if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3443
3637
  if (state.scroll < 0) {
3444
3638
  paddingDiff += state.scroll;
3445
3639
  }
3446
- requestAdjust(ctx, state, paddingDiff);
3640
+ requestAdjust(ctx, paddingDiff);
3447
3641
  }
3448
3642
  };
3449
3643
  if (isFirstLocal) {
3450
3644
  initializeStateVars();
3451
3645
  updateItemPositions(
3452
3646
  ctx,
3453
- state,
3454
3647
  /*dataChanged*/
3455
3648
  true
3456
3649
  );
3457
3650
  }
3458
3651
  const initialContentOffset = useMemo(() => {
3459
- var _a4, _b2;
3460
- const { initialScroll } = refState.current;
3461
- if (!initialScroll) {
3652
+ let value;
3653
+ const { initialScroll, initialAnchor } = refState.current;
3654
+ if (initialScroll) {
3655
+ if (initialScroll.contentOffset !== void 0) {
3656
+ value = initialScroll.contentOffset;
3657
+ } else {
3658
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3659
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3660
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3661
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3662
+ refState.current.initialScroll = updatedInitialScroll;
3663
+ state.initialScroll = updatedInitialScroll;
3664
+ value = clampedOffset;
3665
+ }
3666
+ } else {
3462
3667
  refState.current.initialAnchor = void 0;
3463
- return 0;
3464
- }
3465
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3466
- refState.current.initialAnchor = {
3467
- attempts: 0,
3468
- index: initialScroll.index,
3469
- settledTicks: 0,
3470
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3471
- viewPosition: initialScroll.viewPosition
3472
- };
3668
+ value = 0;
3669
+ }
3670
+ if (!value) {
3671
+ state.didFinishInitialScroll = true;
3473
3672
  }
3474
- if (initialScroll.contentOffset !== void 0) {
3475
- return initialScroll.contentOffset;
3476
- }
3477
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3478
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3479
- let clampedOffset = resolvedOffset;
3480
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3481
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3482
- clampedOffset = Math.min(clampedOffset, maxOffset);
3483
- }
3484
- clampedOffset = Math.max(0, clampedOffset);
3485
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3486
- refState.current.initialScroll = updatedInitialScroll;
3487
- state.initialScroll = updatedInitialScroll;
3488
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3489
- return clampedOffset;
3673
+ return value;
3490
3674
  }, [renderNum]);
3491
3675
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3492
3676
  refState.current.lastBatchingAction = Date.now();
3493
3677
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3494
- IS_DEV && warnDevOnce(
3678
+ IS_DEV && !childrenMode && warnDevOnce(
3495
3679
  "keyExtractor",
3496
3680
  "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."
3497
3681
  );
@@ -3514,12 +3698,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3514
3698
  }
3515
3699
  }, []);
3516
3700
  const doInitialScroll = useCallback(() => {
3517
- var _a4;
3518
3701
  const initialScroll = state.initialScroll;
3519
3702
  if (initialScroll) {
3520
- scrollTo(ctx, state, {
3703
+ scrollTo(ctx, {
3521
3704
  animated: false,
3522
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3705
+ index: initialScroll == null ? void 0 : initialScroll.index,
3523
3706
  isInitialScroll: true,
3524
3707
  offset: initialContentOffset,
3525
3708
  precomputedWithViewOffset: true
@@ -3528,7 +3711,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3528
3711
  }, [initialContentOffset]);
3529
3712
  const onLayoutChange = useCallback((layout) => {
3530
3713
  doInitialScroll();
3531
- handleLayout(ctx, state, layout, setCanRender);
3714
+ handleLayout(ctx, layout, setCanRender);
3532
3715
  }, []);
3533
3716
  const { onLayout } = useOnLayoutSync({
3534
3717
  onLayoutChange,
@@ -3538,7 +3721,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3538
3721
  });
3539
3722
  useLayoutEffect(() => {
3540
3723
  if (snapToIndices) {
3541
- updateSnapToOffsets(ctx, state);
3724
+ updateSnapToOffsets(ctx);
3542
3725
  }
3543
3726
  }, [snapToIndices]);
3544
3727
  useLayoutEffect(() => {
@@ -3548,9 +3731,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3548
3731
  isFirst,
3549
3732
  props: { data }
3550
3733
  } = state;
3551
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3734
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3552
3735
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3553
- checkResetContainers(ctx, state, data);
3736
+ checkResetContainers(ctx, data);
3554
3737
  }
3555
3738
  state.didColumnsChange = false;
3556
3739
  state.didDataChange = false;
@@ -3575,15 +3758,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3575
3758
  state.viewabilityConfigCallbackPairs = viewability;
3576
3759
  state.enableScrollForNextCalculateItemsInView = !viewability;
3577
3760
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3578
- useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3761
+ useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3579
3762
  {
3580
3763
  useEffect(doInitialScroll, []);
3581
3764
  }
3582
3765
  const fns = useMemo(
3583
3766
  () => ({
3584
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3585
- onScroll: (event) => onScroll(ctx, state, event),
3586
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3767
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
3768
+ onMomentumScrollEnd: (event) => {
3769
+ checkFinishedScrollFallback(ctx);
3770
+ if (onMomentumScrollEnd) {
3771
+ onMomentumScrollEnd(event);
3772
+ }
3773
+ },
3774
+ onScroll: (event) => onScroll(ctx, event),
3775
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3587
3776
  }),
3588
3777
  []
3589
3778
  );
@@ -3595,6 +3784,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3595
3784
  alignItemsAtEnd,
3596
3785
  canRender,
3597
3786
  contentContainerStyle,
3787
+ contentInset,
3598
3788
  getRenderedItem: fns.getRenderedItem,
3599
3789
  horizontal,
3600
3790
  initialContentOffset,
@@ -3603,16 +3793,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3603
3793
  maintainVisibleContentPosition,
3604
3794
  onLayout,
3605
3795
  onLayoutHeader,
3606
- onMomentumScrollEnd: (event) => {
3607
- {
3608
- requestAnimationFrame(() => {
3609
- finishScrollTo(ctx, refState.current);
3610
- });
3611
- }
3612
- if (onMomentumScrollEnd) {
3613
- onMomentumScrollEnd(event);
3614
- }
3615
- },
3796
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3616
3797
  onScroll: onScrollHandler,
3617
3798
  recycleItems,
3618
3799
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
@@ -3627,7 +3808,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3627
3808
  ),
3628
3809
  refScrollView: combinedRef,
3629
3810
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3630
- scrollEventThrottle: 16 ,
3811
+ scrollEventThrottle: 0,
3631
3812
  snapToIndices,
3632
3813
  stickyHeaderIndices,
3633
3814
  style,
@@ -3673,8 +3854,8 @@ function buildSectionListData({
3673
3854
  if (hasHeader) {
3674
3855
  const headerIndex = data.length;
3675
3856
  data.push({
3676
- kind: "header",
3677
3857
  key: `${sectionKey}:header`,
3858
+ kind: "header",
3678
3859
  section,
3679
3860
  sectionIndex
3680
3861
  });
@@ -3688,31 +3869,31 @@ function buildSectionListData({
3688
3869
  const itemKeyExtractor = (_b = section.keyExtractor) != null ? _b : keyExtractor;
3689
3870
  const itemKey = itemKeyExtractor(item, itemIndex);
3690
3871
  data.push({
3691
- kind: "item",
3692
- key: `${sectionKey}:item:${itemKey}`,
3693
- section,
3694
- sectionIndex,
3872
+ absoluteItemIndex: absoluteItemIndex++,
3695
3873
  item,
3696
3874
  itemIndex,
3697
- absoluteItemIndex: absoluteItemIndex++
3875
+ key: `${sectionKey}:item:${itemKey}`,
3876
+ kind: "item",
3877
+ section,
3878
+ sectionIndex
3698
3879
  });
3699
3880
  meta.items.push(data.length - 1);
3700
3881
  if (hasItemSeparator && itemIndex < items.length - 1) {
3701
3882
  data.push({
3702
- kind: "item-separator",
3703
3883
  key: `${sectionKey}:separator:${itemIndex}`,
3704
- section,
3705
- sectionIndex,
3884
+ kind: "item-separator",
3706
3885
  leadingItem: item,
3707
3886
  leadingItemIndex: itemIndex,
3887
+ section,
3888
+ sectionIndex,
3708
3889
  trailingItem: items[itemIndex + 1]
3709
3890
  });
3710
3891
  }
3711
3892
  }
3712
3893
  if (hasFooter) {
3713
3894
  data.push({
3714
- kind: "footer",
3715
3895
  key: `${sectionKey}:footer`,
3896
+ kind: "footer",
3716
3897
  section,
3717
3898
  sectionIndex
3718
3899
  });
@@ -3721,8 +3902,8 @@ function buildSectionListData({
3721
3902
  const isLastSection = sectionIndex === sections.length - 1;
3722
3903
  if (hasSectionSeparator && !isLastSection) {
3723
3904
  data.push({
3724
- kind: "section-separator",
3725
3905
  key: `${sectionKey}:section-separator`,
3906
+ kind: "section-separator",
3726
3907
  leadingSection: section,
3727
3908
  leadingSectionIndex: sectionIndex,
3728
3909
  trailingSection: sections[sectionIndex + 1]