@legendapp/list 3.0.0-beta.2 → 3.0.0-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -33,31 +33,65 @@ var View = React3.forwardRef(function View2(props, ref) {
33
33
  });
34
34
  var Text = View;
35
35
 
36
+ // src/state/getContentInsetEnd.ts
37
+ function getContentInsetEnd(state) {
38
+ var _a3;
39
+ const { props } = state;
40
+ const horizontal = props.horizontal;
41
+ let contentInset = props.contentInset;
42
+ if (!contentInset) {
43
+ const animatedInset = (_a3 = props.animatedProps) == null ? void 0 : _a3.contentInset;
44
+ if (animatedInset) {
45
+ if ("get" in animatedInset) {
46
+ contentInset = animatedInset.get();
47
+ } else {
48
+ contentInset = animatedInset;
49
+ }
50
+ }
51
+ }
52
+ return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
53
+ }
54
+
55
+ // src/state/getContentSize.ts
56
+ function getContentSize(ctx) {
57
+ var _a3;
58
+ const { values, state } = ctx;
59
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
60
+ const stylePaddingBottom = state.props.stylePaddingBottom || 0;
61
+ const headerSize = values.get("headerSize") || 0;
62
+ const footerSize = values.get("footerSize") || 0;
63
+ const contentInsetBottom = getContentInsetEnd(state);
64
+ const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
65
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
66
+ }
67
+
36
68
  // src/platform/Animated.tsx
37
69
  var createAnimatedValue = (value) => value;
38
70
 
39
71
  // src/state/state.tsx
40
72
  var ContextState = React3__namespace.createContext(null);
73
+ var contextNum = 0;
41
74
  function StateProvider({ children }) {
42
75
  const [value] = React3__namespace.useState(() => ({
43
76
  animatedScrollY: createAnimatedValue(0),
44
77
  columnWrapperStyle: void 0,
45
- internalState: void 0,
78
+ contextNum: contextNum++,
46
79
  listeners: /* @__PURE__ */ new Map(),
47
80
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
48
81
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
49
82
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
50
83
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
51
84
  mapViewabilityValues: /* @__PURE__ */ new Map(),
85
+ positionListeners: /* @__PURE__ */ new Map(),
86
+ state: void 0,
52
87
  values: /* @__PURE__ */ new Map([
53
88
  ["alignItemsPaddingTop", 0],
54
89
  ["stylePaddingTop", 0],
55
90
  ["headerSize", 0],
56
91
  ["numContainers", 0],
57
- ["activeStickyIndex", void 0],
92
+ ["activeStickyIndex", -1],
58
93
  ["totalSize", 0],
59
- ["scrollAdjustPending", 0],
60
- ["scrollingTo", void 0]
94
+ ["scrollAdjustPending", 0]
61
95
  ]),
62
96
  viewRefs: /* @__PURE__ */ new Map()
63
97
  }));
@@ -125,15 +159,24 @@ function set$(ctx, signalName, value) {
125
159
  }
126
160
  }
127
161
  }
128
- function getContentSize(ctx) {
129
- var _a3, _b;
130
- const { values, internalState } = ctx;
131
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
132
- const stylePaddingBottom = (internalState == null ? void 0 : internalState.props.stylePaddingBottom) || 0;
133
- const headerSize = values.get("headerSize") || 0;
134
- const footerSize = values.get("footerSize") || 0;
135
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
136
- return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom;
162
+ function listenPosition$(ctx, key, cb) {
163
+ const { positionListeners } = ctx;
164
+ let setListeners = positionListeners.get(key);
165
+ if (!setListeners) {
166
+ setListeners = /* @__PURE__ */ new Set();
167
+ positionListeners.set(key, setListeners);
168
+ }
169
+ setListeners.add(cb);
170
+ return () => setListeners.delete(cb);
171
+ }
172
+ function notifyPosition$(ctx, key, value) {
173
+ const { positionListeners } = ctx;
174
+ const setListeners = positionListeners.get(key);
175
+ if (setListeners) {
176
+ for (const listener of setListeners) {
177
+ listener(value);
178
+ }
179
+ }
137
180
  }
138
181
  function useArr$(signalNames) {
139
182
  const ctx = React3__namespace.useContext(ContextState);
@@ -244,6 +287,11 @@ function extractPadding(style, contentContainerStyle, type) {
244
287
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
245
288
  }
246
289
  function findContainerId(ctx, key) {
290
+ var _a3, _b;
291
+ const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
292
+ if (directMatch !== void 0) {
293
+ return directMatch;
294
+ }
247
295
  const numContainers = peek$(ctx, "numContainers");
248
296
  for (let i = 0; i < numContainers; i++) {
249
297
  const itemKey = peek$(ctx, `containerItemKey${i}`);
@@ -255,12 +303,12 @@ function findContainerId(ctx, key) {
255
303
  }
256
304
 
257
305
  // src/components/PositionView.tsx
258
- var PositionViewState = typedMemo(function PositionView({
306
+ var PositionViewState = typedMemo(function PositionViewState2({
259
307
  id,
260
308
  horizontal,
261
309
  style,
262
310
  refView,
263
- ...rest
311
+ ...props
264
312
  }) {
265
313
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
266
314
  const base = {
@@ -268,7 +316,8 @@ var PositionViewState = typedMemo(function PositionView({
268
316
  };
269
317
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
270
318
  const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
271
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: combinedStyle, ...rest });
319
+ const { animatedScrollY, stickyOffset, onLayout, ...webProps } = props;
320
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, ...webProps, style: combinedStyle });
272
321
  });
273
322
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
274
323
  id,
@@ -313,63 +362,80 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
313
362
  }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
314
363
  return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
315
364
  });
316
- var PositionView2 = PositionViewState;
365
+ var PositionView = PositionViewState;
317
366
 
318
367
  // src/constants-platform.ts
319
368
  var IsNewArchitecture = true;
320
- var symbolFirst = Symbol();
321
369
  function useInit(cb) {
322
- const refValue = React3.useRef(symbolFirst);
323
- if (refValue.current === symbolFirst) {
324
- refValue.current = cb();
325
- }
326
- return refValue.current;
370
+ React3.useState(() => cb());
327
371
  }
328
372
 
329
373
  // src/state/ContextContainer.ts
330
374
  var ContextContainer = React3.createContext(null);
375
+ function useContextContainer() {
376
+ return React3.useContext(ContextContainer);
377
+ }
331
378
  function useViewability(callback, configId) {
332
379
  const ctx = useStateContext();
333
- const { containerId } = React3.useContext(ContextContainer);
334
- const key = containerId + (configId != null ? configId : "");
380
+ const containerContext = useContextContainer();
335
381
  useInit(() => {
382
+ if (!containerContext) {
383
+ return;
384
+ }
385
+ const { containerId } = containerContext;
386
+ const key = containerId + (configId != null ? configId : "");
336
387
  const value = ctx.mapViewabilityValues.get(key);
337
388
  if (value) {
338
389
  callback(value);
339
390
  }
340
391
  });
341
- ctx.mapViewabilityCallbacks.set(key, callback);
342
- React3.useEffect(
343
- () => () => {
392
+ React3.useEffect(() => {
393
+ if (!containerContext) {
394
+ return;
395
+ }
396
+ const { containerId } = containerContext;
397
+ const key = containerId + (configId != null ? configId : "");
398
+ ctx.mapViewabilityCallbacks.set(key, callback);
399
+ return () => {
344
400
  ctx.mapViewabilityCallbacks.delete(key);
345
- },
346
- []
347
- );
401
+ };
402
+ }, [ctx, callback, configId, containerContext]);
348
403
  }
349
404
  function useViewabilityAmount(callback) {
350
405
  const ctx = useStateContext();
351
- const { containerId } = React3.useContext(ContextContainer);
406
+ const containerContext = useContextContainer();
352
407
  useInit(() => {
408
+ if (!containerContext) {
409
+ return;
410
+ }
411
+ const { containerId } = containerContext;
353
412
  const value = ctx.mapViewabilityAmountValues.get(containerId);
354
413
  if (value) {
355
414
  callback(value);
356
415
  }
357
416
  });
358
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
359
- React3.useEffect(
360
- () => () => {
417
+ React3.useEffect(() => {
418
+ if (!containerContext) {
419
+ return;
420
+ }
421
+ const { containerId } = containerContext;
422
+ ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
423
+ return () => {
361
424
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
362
- },
363
- []
364
- );
425
+ };
426
+ }, [ctx, callback, containerContext]);
365
427
  }
366
428
  function useRecyclingEffect(effect) {
367
- const { index, value } = React3.useContext(ContextContainer);
429
+ const containerContext = useContextContainer();
368
430
  const prevValues = React3.useRef({
369
431
  prevIndex: void 0,
370
432
  prevItem: void 0
371
433
  });
372
434
  React3.useEffect(() => {
435
+ if (!containerContext) {
436
+ return;
437
+ }
438
+ const { index, value } = containerContext;
373
439
  let ret;
374
440
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
375
441
  ret = effect({
@@ -384,48 +450,73 @@ function useRecyclingEffect(effect) {
384
450
  prevItem: value
385
451
  };
386
452
  return ret;
387
- }, [index, value, effect]);
453
+ }, [effect, containerContext]);
388
454
  }
389
455
  function useRecyclingState(valueOrFun) {
390
- const { index, value, itemKey, triggerLayout } = React3.useContext(ContextContainer);
391
- const refState = React3.useRef({
392
- itemKey: null,
393
- value: null
456
+ var _a3, _b;
457
+ const containerContext = useContextContainer();
458
+ const computeValue = (ctx) => {
459
+ if (isFunction(valueOrFun)) {
460
+ const initializer = valueOrFun;
461
+ return ctx ? initializer({
462
+ index: ctx.index,
463
+ item: ctx.value,
464
+ prevIndex: void 0,
465
+ prevItem: void 0
466
+ }) : initializer();
467
+ }
468
+ return valueOrFun;
469
+ };
470
+ const [stateValue, setStateValue] = React3.useState(() => {
471
+ return computeValue(containerContext);
394
472
  });
395
- const [_, setRenderNum] = React3.useState(0);
396
- const state = refState.current;
397
- if (state.itemKey !== itemKey) {
398
- state.itemKey = itemKey;
399
- state.value = isFunction(valueOrFun) ? valueOrFun({
400
- index,
401
- item: value,
402
- prevIndex: void 0,
403
- prevItem: void 0
404
- }) : valueOrFun;
473
+ const prevItemKeyRef = React3.useRef((_a3 = containerContext == null ? void 0 : containerContext.itemKey) != null ? _a3 : null);
474
+ const currentItemKey = (_b = containerContext == null ? void 0 : containerContext.itemKey) != null ? _b : null;
475
+ if (currentItemKey !== null && prevItemKeyRef.current !== currentItemKey) {
476
+ prevItemKeyRef.current = currentItemKey;
477
+ setStateValue(computeValue(containerContext));
405
478
  }
479
+ const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
406
480
  const setState = React3.useCallback(
407
481
  (newState) => {
408
- state.value = isFunction(newState) ? newState(state.value) : newState;
409
- setRenderNum((v) => v + 1);
482
+ if (!triggerLayout) {
483
+ return;
484
+ }
485
+ setStateValue((prevValue) => {
486
+ return isFunction(newState) ? newState(prevValue) : newState;
487
+ });
410
488
  triggerLayout();
411
489
  },
412
- [triggerLayout, state]
490
+ [triggerLayout]
413
491
  );
414
- return [state.value, setState];
492
+ return [stateValue, setState];
415
493
  }
416
494
  function useIsLastItem() {
417
- const { itemKey } = React3.useContext(ContextContainer);
418
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
495
+ const containerContext = useContextContainer();
496
+ const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
497
+ if (containerContext) {
498
+ const { itemKey } = containerContext;
499
+ if (!isNullOrUndefined(itemKey)) {
500
+ return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
501
+ }
502
+ }
503
+ return false;
504
+ });
419
505
  return isLast;
420
506
  }
421
507
  function useListScrollSize() {
422
508
  const [scrollSize] = useArr$(["scrollSize"]);
423
509
  return scrollSize;
424
510
  }
511
+ var noop = () => {
512
+ };
425
513
  function useSyncLayout() {
426
- {
427
- const { triggerLayout: syncLayout } = React3.useContext(ContextContainer);
514
+ const containerContext = useContextContainer();
515
+ if (containerContext) {
516
+ const { triggerLayout: syncLayout } = containerContext;
428
517
  return syncLayout;
518
+ } else {
519
+ return noop;
429
520
  }
430
521
  }
431
522
 
@@ -471,10 +562,9 @@ function createResizeObserver(element, callback) {
471
562
  }
472
563
  callbacks.add(callback);
473
564
  return () => {
474
- const callbacks2 = callbackMap.get(element);
475
- if (callbacks2) {
476
- callbacks2.delete(callback);
477
- if (callbacks2.size === 0) {
565
+ if (callbacks) {
566
+ callbacks.delete(callback);
567
+ if (callbacks.size === 0) {
478
568
  callbackMap.delete(element);
479
569
  observer.unobserve(element);
480
570
  }
@@ -509,10 +599,10 @@ function useOnLayoutSync({
509
599
  return createResizeObserver(element, (entry) => {
510
600
  var _a4;
511
601
  const target = entry.target instanceof HTMLElement ? entry.target : void 0;
512
- const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
513
- if (rect2.width !== prevRect.width || rect2.height !== prevRect.height) {
514
- prevRect = rect2;
515
- emit(toLayout(rect2), false);
602
+ const rectObserved = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
603
+ if (rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height) {
604
+ prevRect = rectObserved;
605
+ emit(toLayout(rectObserved), false);
516
606
  }
517
607
  });
518
608
  }, deps || []);
@@ -537,7 +627,8 @@ var Container = typedMemo(function Container2({
537
627
  horizontal,
538
628
  getRenderedItem: getRenderedItem2,
539
629
  updateItemSize: updateItemSize2,
540
- ItemSeparatorComponent
630
+ ItemSeparatorComponent,
631
+ stickyHeaderConfig
541
632
  }) {
542
633
  const ctx = useStateContext();
543
634
  const { columnWrapperStyle, animatedScrollY } = ctx;
@@ -640,7 +731,7 @@ var Container = typedMemo(function Container2({
640
731
  },
641
732
  [itemKey, layoutRenderCount]
642
733
  );
643
- const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
734
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
644
735
  return /* @__PURE__ */ React3__namespace.createElement(
645
736
  PositionComponent,
646
737
  {
@@ -651,6 +742,7 @@ var Container = typedMemo(function Container2({
651
742
  key: recycleItems ? void 0 : itemKey,
652
743
  onLayout,
653
744
  refView: ref,
745
+ stickyHeaderConfig,
654
746
  stickyOffset: isSticky ? stickyOffset : void 0,
655
747
  style
656
748
  },
@@ -810,7 +902,8 @@ var Containers = typedMemo(function Containers2({
810
902
  ItemSeparatorComponent,
811
903
  waitForInitialLayout,
812
904
  updateItemSize: updateItemSize2,
813
- getRenderedItem: getRenderedItem2
905
+ getRenderedItem: getRenderedItem2,
906
+ stickyHeaderConfig
814
907
  }) {
815
908
  const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
816
909
  const containers = [];
@@ -825,6 +918,7 @@ var Containers = typedMemo(function Containers2({
825
918
  id: i,
826
919
  key: i,
827
920
  recycleItems,
921
+ stickyHeaderConfig,
828
922
  updateItemSize: updateItemSize2
829
923
  }
830
924
  )
@@ -833,7 +927,8 @@ var Containers = typedMemo(function Containers2({
833
927
  return /* @__PURE__ */ React3__namespace.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
834
928
  });
835
929
  function DevNumbers() {
836
- return IS_DEV && React3__namespace.memo(function DevNumbers2() {
930
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
931
+ React3__namespace.memo(function DevNumbers2() {
837
932
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3__namespace.createElement(
838
933
  "div",
839
934
  {
@@ -881,7 +976,6 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
881
976
  }, ref) {
882
977
  const scrollRef = React3.useRef(null);
883
978
  const contentRef = React3.useRef(null);
884
- const momentumTimeout = React3.useRef(null);
885
979
  React3.useImperativeHandle(ref, () => {
886
980
  const api = {
887
981
  getBoundingClientRect: () => {
@@ -947,16 +1041,6 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
947
1041
  }
948
1042
  };
949
1043
  onScroll2(scrollEvent);
950
- if (onMomentumScrollEnd) {
951
- if (momentumTimeout.current != null) clearTimeout(momentumTimeout.current);
952
- momentumTimeout.current = setTimeout(() => {
953
- onMomentumScrollEnd({
954
- nativeEvent: {
955
- contentOffset: scrollEvent.nativeEvent.contentOffset
956
- }
957
- });
958
- }, 100);
959
- }
960
1044
  },
961
1045
  [onScroll2, onMomentumScrollEnd]
962
1046
  );
@@ -1018,7 +1102,8 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1018
1102
  minWidth: horizontal ? "100%" : void 0,
1019
1103
  ...StyleSheet.flatten(contentContainerStyle)
1020
1104
  };
1021
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3__namespace.createElement("div", { ref: contentRef, style: contentStyle }, children));
1105
+ const { contentInset, scrollEventThrottle, ScrollComponent, ...webProps } = props;
1106
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3__namespace.createElement("div", { ref: contentRef, style: contentStyle }, children));
1022
1107
  });
1023
1108
  function Padding() {
1024
1109
  const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
@@ -1059,7 +1144,7 @@ function ScrollAdjust() {
1059
1144
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1060
1145
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1061
1146
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1062
- const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
1147
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1063
1148
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1064
1149
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1065
1150
  if (scrollDelta !== 0) {
@@ -1067,26 +1152,23 @@ function ScrollAdjust() {
1067
1152
  const prevScroll = el.scrollTop;
1068
1153
  const nextScroll = prevScroll + scrollDelta;
1069
1154
  const totalSize = el.scrollHeight;
1070
- if (scrollDelta > 0 && !ctx.internalState.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1155
+ if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1071
1156
  const child = el.firstElementChild;
1072
1157
  const prevPaddingBottom = child.style.paddingBottom;
1073
1158
  const pad = (nextScroll + el.clientHeight - totalSize) * 2;
1074
1159
  child.style.paddingBottom = `${pad}px`;
1075
1160
  void el.offsetHeight;
1076
1161
  scrollView.scrollBy(0, scrollDelta);
1077
- setTimeout(() => {
1162
+ requestAnimationFrame(() => {
1078
1163
  child.style.paddingBottom = prevPaddingBottom;
1079
- }, 100);
1164
+ });
1080
1165
  } else {
1081
1166
  scrollView.scrollBy(0, scrollDelta);
1082
1167
  }
1083
- if (IS_DEV) {
1084
- console.log("ScrollAdjust (web scrollBy)", scrollDelta, "total offset:", scrollOffset);
1085
- }
1086
1168
  }
1087
1169
  lastScrollOffsetRef.current = scrollOffset;
1088
1170
  }
1089
- }, []);
1171
+ }, [ctx]);
1090
1172
  useValueListener$("scrollAdjust", callback);
1091
1173
  useValueListener$("scrollAdjustUserOffset", callback);
1092
1174
  return null;
@@ -1100,8 +1182,6 @@ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1100
1182
  useOnLayoutSync({ onLayoutChange, ref });
1101
1183
  return /* @__PURE__ */ React3__namespace.createElement("div", { ...rest, ref }, children);
1102
1184
  };
1103
-
1104
- // src/components/ListComponent.tsx
1105
1185
  var getComponent = (Component) => {
1106
1186
  if (React3__namespace.isValidElement(Component)) {
1107
1187
  return Component;
@@ -1111,6 +1191,8 @@ var getComponent = (Component) => {
1111
1191
  }
1112
1192
  return null;
1113
1193
  };
1194
+
1195
+ // src/components/ListComponent.tsx
1114
1196
  var ListComponent = typedMemo(function ListComponent2({
1115
1197
  canRender,
1116
1198
  style,
@@ -1131,26 +1213,20 @@ var ListComponent = typedMemo(function ListComponent2({
1131
1213
  getRenderedItem: getRenderedItem2,
1132
1214
  updateItemSize: updateItemSize2,
1133
1215
  refScrollView,
1134
- maintainVisibleContentPosition,
1135
1216
  renderScrollComponent,
1136
1217
  scrollAdjustHandler,
1137
1218
  onLayoutHeader,
1138
1219
  snapToIndices,
1220
+ stickyHeaderConfig,
1139
1221
  stickyHeaderIndices,
1140
1222
  ...rest
1141
1223
  }) {
1142
1224
  const ctx = useStateContext();
1225
+ const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1143
1226
  const ScrollComponent = renderScrollComponent ? React3.useMemo(
1144
1227
  () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1145
1228
  [renderScrollComponent]
1146
1229
  ) : ListComponentScrollView;
1147
- React3__namespace.useEffect(() => {
1148
- if (canRender) {
1149
- setTimeout(() => {
1150
- scrollAdjustHandler.setMounted();
1151
- }, 0);
1152
- }
1153
- }, [canRender]);
1154
1230
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1155
1231
  return /* @__PURE__ */ React3__namespace.createElement(
1156
1232
  SnapOrScroll,
@@ -1164,7 +1240,7 @@ var ListComponent = typedMemo(function ListComponent2({
1164
1240
  ],
1165
1241
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1166
1242
  horizontal,
1167
- maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
1243
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
1168
1244
  onLayout,
1169
1245
  onScroll: onScroll2,
1170
1246
  ref: refScrollView,
@@ -1182,6 +1258,7 @@ var ListComponent = typedMemo(function ListComponent2({
1182
1258
  horizontal,
1183
1259
  ItemSeparatorComponent,
1184
1260
  recycleItems,
1261
+ stickyHeaderConfig,
1185
1262
  updateItemSize: updateItemSize2,
1186
1263
  waitForInitialLayout
1187
1264
  }
@@ -1214,10 +1291,11 @@ function getId(state, index) {
1214
1291
  }
1215
1292
 
1216
1293
  // src/core/calculateOffsetForIndex.ts
1217
- function calculateOffsetForIndex(ctx, state, index) {
1294
+ function calculateOffsetForIndex(ctx, index) {
1295
+ const state = ctx.state;
1218
1296
  let position = 0;
1219
1297
  if (index !== void 0) {
1220
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
1298
+ position = state.positions.get(getId(state, index)) || 0;
1221
1299
  const paddingTop = peek$(ctx, "stylePaddingTop");
1222
1300
  if (paddingTop) {
1223
1301
  position += paddingTop;
@@ -1231,7 +1309,8 @@ function calculateOffsetForIndex(ctx, state, index) {
1231
1309
  }
1232
1310
 
1233
1311
  // src/utils/setPaddingTop.ts
1234
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1312
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1313
+ const state = ctx.state;
1235
1314
  if (stylePaddingTop !== void 0) {
1236
1315
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1237
1316
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -1250,7 +1329,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1250
1329
  }
1251
1330
 
1252
1331
  // src/utils/updateAlignItemsPaddingTop.ts
1253
- function updateAlignItemsPaddingTop(ctx, state) {
1332
+ function updateAlignItemsPaddingTop(ctx) {
1333
+ const state = ctx.state;
1254
1334
  const {
1255
1335
  scrollLength,
1256
1336
  props: { alignItemsAtEnd, data }
@@ -1261,12 +1341,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
1261
1341
  const contentSize = getContentSize(ctx);
1262
1342
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1263
1343
  }
1264
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1344
+ setPaddingTop(ctx, { alignItemsPaddingTop });
1265
1345
  }
1266
1346
  }
1267
1347
 
1268
1348
  // src/core/addTotalSize.ts
1269
- function addTotalSize(ctx, state, key, add) {
1349
+ function addTotalSize(ctx, key, add) {
1350
+ const state = ctx.state;
1270
1351
  const { alignItemsAtEnd } = state.props;
1271
1352
  const prevTotalSize = state.totalSize;
1272
1353
  let totalSize = state.totalSize;
@@ -1285,31 +1366,34 @@ function addTotalSize(ctx, state, key, add) {
1285
1366
  state.totalSize = totalSize;
1286
1367
  set$(ctx, "totalSize", totalSize);
1287
1368
  if (alignItemsAtEnd) {
1288
- updateAlignItemsPaddingTop(ctx, state);
1369
+ updateAlignItemsPaddingTop(ctx);
1289
1370
  }
1290
1371
  }
1291
1372
  }
1292
1373
  }
1293
1374
 
1294
1375
  // src/core/setSize.ts
1295
- function setSize(ctx, state, itemKey, size) {
1376
+ function setSize(ctx, itemKey, size) {
1377
+ const state = ctx.state;
1296
1378
  const { sizes } = state;
1297
1379
  const previousSize = sizes.get(itemKey);
1298
1380
  const diff = previousSize !== void 0 ? size - previousSize : size;
1299
1381
  if (diff !== 0) {
1300
- addTotalSize(ctx, state, itemKey, diff);
1382
+ addTotalSize(ctx, itemKey, diff);
1301
1383
  }
1302
1384
  sizes.set(itemKey, size);
1303
1385
  }
1304
1386
 
1305
1387
  // src/utils/getItemSize.ts
1306
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1388
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1307
1389
  var _a3, _b;
1390
+ const state = ctx.state;
1308
1391
  const {
1309
1392
  sizesKnown,
1310
1393
  sizes,
1311
1394
  averageSizes,
1312
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1395
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1396
+ scrollingTo
1313
1397
  } = state;
1314
1398
  const sizeKnown = sizesKnown.get(key);
1315
1399
  if (sizeKnown !== void 0) {
@@ -1317,7 +1401,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1317
1401
  }
1318
1402
  let size;
1319
1403
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1320
- const scrollingTo = peek$(ctx, "scrollingTo");
1321
1404
  if (preferCachedSize) {
1322
1405
  const cachedSize = sizes.get(key);
1323
1406
  if (cachedSize !== void 0) {
@@ -1325,7 +1408,7 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1325
1408
  }
1326
1409
  }
1327
1410
  if (getFixedItemSize) {
1328
- size = getFixedItemSize(index, data, itemType);
1411
+ size = getFixedItemSize(data, index, itemType);
1329
1412
  if (size !== void 0) {
1330
1413
  sizesKnown.set(key, size);
1331
1414
  }
@@ -1343,93 +1426,188 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1343
1426
  }
1344
1427
  }
1345
1428
  if (size === void 0) {
1346
- size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1429
+ size = getEstimatedItemSize ? getEstimatedItemSize(data, index, itemType) : estimatedItemSize;
1347
1430
  }
1348
- setSize(ctx, state, key, size);
1431
+ setSize(ctx, key, size);
1349
1432
  return size;
1350
1433
  }
1351
1434
 
1352
1435
  // src/core/calculateOffsetWithOffsetPosition.ts
1353
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1436
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1437
+ const state = ctx.state;
1354
1438
  const { index, viewOffset, viewPosition } = params;
1355
1439
  let offset = offsetParam;
1356
1440
  if (viewOffset) {
1357
1441
  offset -= viewOffset;
1358
1442
  }
1359
1443
  if (viewPosition !== void 0 && index !== void 0) {
1360
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1444
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1445
+ const trailingInset = getContentInsetEnd(state);
1446
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1361
1447
  }
1362
1448
  return offset;
1363
1449
  }
1364
1450
 
1451
+ // src/core/clampScrollOffset.ts
1452
+ function clampScrollOffset(ctx, offset) {
1453
+ const state = ctx.state;
1454
+ const contentSize = getContentSize(ctx);
1455
+ let clampedOffset = offset;
1456
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android")) {
1457
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1458
+ clampedOffset = Math.min(offset, maxOffset);
1459
+ }
1460
+ clampedOffset = Math.max(0, clampedOffset);
1461
+ return clampedOffset;
1462
+ }
1463
+
1464
+ // src/utils/setInitialRenderState.ts
1465
+ function setInitialRenderState(ctx, {
1466
+ didLayout,
1467
+ didInitialScroll
1468
+ }) {
1469
+ const { state } = ctx;
1470
+ if (didLayout) {
1471
+ state.didContainersLayout = true;
1472
+ }
1473
+ if (didInitialScroll) {
1474
+ state.didFinishInitialScroll = true;
1475
+ }
1476
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1477
+ set$(ctx, "readyToRender", true);
1478
+ }
1479
+ }
1480
+
1365
1481
  // src/core/finishScrollTo.ts
1366
- function finishScrollTo(ctx, state) {
1482
+ function finishScrollTo(ctx) {
1367
1483
  var _a3, _b;
1368
- if (state) {
1484
+ const state = ctx.state;
1485
+ if (state == null ? void 0 : state.scrollingTo) {
1486
+ const scrollingTo = state.scrollingTo;
1369
1487
  state.scrollHistory.length = 0;
1370
1488
  state.initialScroll = void 0;
1371
1489
  state.initialAnchor = void 0;
1372
- set$(ctx, "scrollingTo", void 0);
1490
+ state.scrollingTo = void 0;
1373
1491
  if (state.pendingTotalSize !== void 0) {
1374
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1492
+ addTotalSize(ctx, null, state.pendingTotalSize);
1375
1493
  }
1376
1494
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1377
1495
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1378
1496
  }
1497
+ {
1498
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1499
+ }
1500
+ setInitialRenderState(ctx, { didInitialScroll: true });
1501
+ }
1502
+ }
1503
+
1504
+ // src/core/doScrollTo.ts
1505
+ var SCROLL_END_IDLE_MS = 80;
1506
+ var SCROLL_END_MAX_MS = 1500;
1507
+ var SMOOTH_SCROLL_DURATION_MS = 320;
1508
+ function doScrollTo(ctx, params) {
1509
+ const state = ctx.state;
1510
+ const { animated, horizontal, offset } = params;
1511
+ const scroller = state.refScroller.current;
1512
+ const node = typeof (scroller == null ? void 0 : scroller.getScrollableNode) === "function" ? scroller.getScrollableNode() : scroller;
1513
+ if (node) {
1514
+ const left = horizontal ? offset : 0;
1515
+ const top = horizontal ? 0 : offset;
1516
+ node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1517
+ if (animated) {
1518
+ listenForScrollEnd(ctx, node);
1519
+ } else {
1520
+ state.scroll = offset;
1521
+ setTimeout(() => {
1522
+ finishScrollTo(ctx);
1523
+ }, 100);
1524
+ }
1379
1525
  }
1380
1526
  }
1527
+ function listenForScrollEnd(ctx, node) {
1528
+ const supportsScrollEnd = "onscrollend" in node;
1529
+ let idleTimeout;
1530
+ let maxTimeout;
1531
+ let settled = false;
1532
+ const targetToken = ctx.state.scrollingTo;
1533
+ const finish = () => {
1534
+ if (settled) return;
1535
+ settled = true;
1536
+ cleanup();
1537
+ if (targetToken === ctx.state.scrollingTo) {
1538
+ finishScrollTo(ctx);
1539
+ }
1540
+ };
1541
+ const onScroll2 = () => {
1542
+ if (idleTimeout) {
1543
+ clearTimeout(idleTimeout);
1544
+ }
1545
+ idleTimeout = setTimeout(finish, SCROLL_END_IDLE_MS);
1546
+ };
1547
+ const cleanup = () => {
1548
+ if (supportsScrollEnd) {
1549
+ node.removeEventListener("scrollend", finish);
1550
+ } else {
1551
+ node.removeEventListener("scroll", onScroll2);
1552
+ }
1553
+ if (idleTimeout) {
1554
+ clearTimeout(idleTimeout);
1555
+ }
1556
+ if (maxTimeout) {
1557
+ clearTimeout(maxTimeout);
1558
+ }
1559
+ };
1560
+ if (supportsScrollEnd) {
1561
+ node.addEventListener("scrollend", finish, { once: true });
1562
+ } else {
1563
+ node.addEventListener("scroll", onScroll2);
1564
+ idleTimeout = setTimeout(finish, SMOOTH_SCROLL_DURATION_MS);
1565
+ maxTimeout = setTimeout(finish, SCROLL_END_MAX_MS);
1566
+ }
1567
+ return cleanup;
1568
+ }
1381
1569
 
1382
1570
  // src/core/scrollTo.ts
1383
- function scrollTo(ctx, state, params) {
1384
- var _a3;
1385
- const { noScrollingTo, ...scrollTarget } = params;
1571
+ function scrollTo(ctx, params) {
1572
+ const state = ctx.state;
1573
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1386
1574
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1387
1575
  const {
1388
- refScroller,
1389
1576
  props: { horizontal }
1390
1577
  } = state;
1391
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1392
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1393
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1394
- offset = Math.min(offset, maxOffset);
1578
+ if (state.animFrameCheckFinishedScroll) {
1579
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1395
1580
  }
1581
+ if (state.timeoutCheckFinishedScrollFallback) {
1582
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1583
+ }
1584
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1585
+ offset = clampScrollOffset(ctx, offset);
1396
1586
  state.scrollHistory.length = 0;
1397
1587
  if (!noScrollingTo) {
1398
- set$(ctx, "scrollingTo", scrollTarget);
1588
+ state.scrollingTo = scrollTarget;
1399
1589
  }
1400
1590
  state.scrollPending = offset;
1401
- if (!isInitialScroll || Platform.OS === "android") {
1402
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1403
- animated: !!animated,
1404
- x: horizontal ? offset : 0,
1405
- y: horizontal ? 0 : offset
1406
- });
1407
- }
1408
- if (!animated) {
1591
+ if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1592
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1593
+ } else {
1409
1594
  state.scroll = offset;
1410
- {
1411
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1412
- if (value && peek$(ctx, "scrollingTo")) {
1413
- finishScrollTo(ctx, state);
1414
- unlisten();
1415
- }
1416
- });
1417
- }
1418
- if (isInitialScroll) {
1419
- setTimeout(() => {
1420
- state.initialScroll = void 0;
1421
- }, 500);
1422
- }
1423
1595
  }
1424
1596
  }
1425
1597
 
1426
1598
  // src/utils/checkThreshold.ts
1427
1599
  var HYSTERESIS_MULTIPLIER = 1.3;
1428
- var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1600
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot, allowReentryOnChange) => {
1429
1601
  const absDistance = Math.abs(distance);
1430
1602
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1603
+ if (wasReached === null) {
1604
+ if (!within && distance >= 0) {
1605
+ return false;
1606
+ }
1607
+ return null;
1608
+ }
1431
1609
  const updateSnapshot = () => {
1432
- setSnapshot == null ? void 0 : setSnapshot({
1610
+ setSnapshot({
1433
1611
  atThreshold,
1434
1612
  contentSize: context.contentSize,
1435
1613
  dataLength: context.dataLength,
@@ -1440,19 +1618,21 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1440
1618
  if (!within) {
1441
1619
  return false;
1442
1620
  }
1443
- onReached == null ? void 0 : onReached(distance);
1621
+ onReached(distance);
1444
1622
  updateSnapshot();
1445
1623
  return true;
1446
1624
  }
1447
1625
  const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1448
1626
  if (reset) {
1449
- setSnapshot == null ? void 0 : setSnapshot(void 0);
1627
+ setSnapshot(void 0);
1450
1628
  return false;
1451
1629
  }
1452
1630
  if (within) {
1453
1631
  const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
1454
1632
  if (changed) {
1455
- onReached == null ? void 0 : onReached(distance);
1633
+ if (allowReentryOnChange) {
1634
+ onReached(distance);
1635
+ }
1456
1636
  updateSnapshot();
1457
1637
  }
1458
1638
  }
@@ -1460,8 +1640,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1460
1640
  };
1461
1641
 
1462
1642
  // src/utils/checkAtBottom.ts
1463
- function checkAtBottom(ctx, state) {
1643
+ function checkAtBottom(ctx) {
1464
1644
  var _a3;
1645
+ const state = ctx.state;
1465
1646
  if (!state) {
1466
1647
  return;
1467
1648
  }
@@ -1494,7 +1675,8 @@ function checkAtBottom(ctx, state) {
1494
1675
  },
1495
1676
  (snapshot) => {
1496
1677
  state.endReachedSnapshot = snapshot;
1497
- }
1678
+ },
1679
+ true
1498
1680
  );
1499
1681
  }
1500
1682
  }
@@ -1529,20 +1711,21 @@ function checkAtTop(state) {
1529
1711
  },
1530
1712
  (snapshot) => {
1531
1713
  state.startReachedSnapshot = snapshot;
1532
- }
1714
+ },
1715
+ false
1533
1716
  );
1534
1717
  }
1535
1718
 
1536
1719
  // src/core/updateScroll.ts
1537
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1538
- var _a3;
1539
- const scrollingTo = peek$(ctx, "scrollingTo");
1720
+ function updateScroll(ctx, newScroll, forceUpdate) {
1721
+ const state = ctx.state;
1722
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1723
+ const prevScroll = state.scroll;
1540
1724
  state.hasScrolled = true;
1541
1725
  state.lastBatchingAction = Date.now();
1542
1726
  const currentTime = Date.now();
1543
- const adjust = state.scrollAdjustHandler.getAdjust();
1544
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1545
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1727
+ const adjust = scrollAdjustHandler.getAdjust();
1728
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1546
1729
  if (adjustChanged) {
1547
1730
  state.scrollHistory.length = 0;
1548
1731
  }
@@ -1555,7 +1738,7 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1555
1738
  if (state.scrollHistory.length > 5) {
1556
1739
  state.scrollHistory.shift();
1557
1740
  }
1558
- state.scrollPrev = state.scroll;
1741
+ state.scrollPrev = prevScroll;
1559
1742
  state.scrollPrevTime = state.scrollTime;
1560
1743
  state.scroll = newScroll;
1561
1744
  state.scrollTime = currentTime;
@@ -1567,17 +1750,33 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1567
1750
  return;
1568
1751
  }
1569
1752
  }
1570
- if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1753
+ const scrollDelta = Math.abs(newScroll - prevScroll);
1754
+ const scrollLength = state.scrollLength;
1755
+ const lastCalculated = state.scrollLastCalculate;
1756
+ const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1757
+ if (shouldUpdate) {
1758
+ state.scrollLastCalculate = state.scroll;
1571
1759
  state.ignoreScrollFromMVCPIgnored = false;
1572
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1573
- checkAtBottom(ctx, state);
1574
- checkAtTop(state);
1760
+ state.lastScrollDelta = scrollDelta;
1761
+ const runCalculateItems = () => {
1762
+ var _a3;
1763
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1764
+ checkAtBottom(ctx);
1765
+ checkAtTop(state);
1766
+ };
1767
+ if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
1768
+ reactDom.flushSync(runCalculateItems);
1769
+ } else {
1770
+ runCalculateItems();
1771
+ }
1575
1772
  state.dataChangeNeedsScrollUpdate = false;
1773
+ state.lastScrollDelta = 0;
1576
1774
  }
1577
1775
  }
1578
1776
 
1579
1777
  // src/utils/requestAdjust.ts
1580
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1778
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1779
+ const state = ctx.state;
1581
1780
  if (Math.abs(positionDiff) > 0.1) {
1582
1781
  const doit = () => {
1583
1782
  {
@@ -1589,8 +1788,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1589
1788
  };
1590
1789
  state.scroll += positionDiff;
1591
1790
  state.scrollForNextCalculateItemsInView = void 0;
1592
- const didLayout = peek$(ctx, "containersDidLayout");
1593
- if (didLayout) {
1791
+ const readyToRender = peek$(ctx, "readyToRender");
1792
+ if (readyToRender) {
1594
1793
  doit();
1595
1794
  } else {
1596
1795
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -1599,73 +1798,25 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1599
1798
  }
1600
1799
  }
1601
1800
 
1602
- // src/core/ensureInitialAnchor.ts
1603
- var INITIAL_ANCHOR_TOLERANCE = 0.5;
1604
- var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1605
- var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1606
- function ensureInitialAnchor(ctx, state) {
1607
- var _a3, _b, _c, _d, _e;
1608
- const anchor = state.initialAnchor;
1609
- const item = state.props.data[anchor.index];
1610
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1611
- if (!containersDidLayout) {
1612
- return;
1613
- }
1614
- const id = getId(state, anchor.index);
1615
- if (state.positions.get(id) === void 0) {
1616
- return;
1617
- }
1618
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1619
- if (size === void 0) {
1620
- return;
1621
- }
1622
- const availableSpace = Math.max(0, state.scrollLength - size);
1623
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1624
- const contentSize = getContentSize(ctx);
1625
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1626
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1627
- const delta = clampedDesiredOffset - state.scroll;
1628
- if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1629
- const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1630
- if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1631
- state.initialAnchor = void 0;
1632
- } else {
1633
- anchor.settledTicks = settledTicks;
1634
- }
1635
- return;
1636
- }
1637
- if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1638
- state.initialAnchor = void 0;
1639
- return;
1640
- }
1641
- const lastDelta = anchor.lastDelta;
1642
- if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1643
- state.initialAnchor = void 0;
1644
- return;
1645
- }
1646
- Object.assign(anchor, {
1647
- attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1648
- lastDelta: delta,
1649
- settledTicks: 0
1650
- });
1651
- requestAdjust(ctx, state, delta);
1652
- }
1653
-
1654
1801
  // src/core/mvcp.ts
1655
- function prepareMVCP(ctx, state, dataChanged) {
1802
+ function prepareMVCP(ctx, dataChanged) {
1803
+ const state = ctx.state;
1656
1804
  const { idsInView, positions, props } = state;
1657
- const { maintainVisibleContentPosition } = props;
1658
- const scrollingTo = peek$(ctx, "scrollingTo");
1805
+ const {
1806
+ maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll, shouldRestorePosition }
1807
+ } = props;
1808
+ const scrollingTo = state.scrollingTo;
1659
1809
  let prevPosition;
1660
1810
  let targetId;
1661
1811
  const idsInViewWithPositions = [];
1662
1812
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1663
- const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1813
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1814
+ const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1664
1815
  const indexByKey = state.indexByKey;
1665
1816
  if (shouldMVCP) {
1666
1817
  if (scrollTarget !== void 0) {
1667
1818
  targetId = getId(state, scrollTarget);
1668
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1819
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1669
1820
  if (dataChanged) {
1670
1821
  for (let i = 0; i < idsInView.length; i++) {
1671
1822
  const id = idsInView[i];
@@ -1682,10 +1833,18 @@ function prepareMVCP(ctx, state, dataChanged) {
1682
1833
  prevPosition = positions.get(targetId);
1683
1834
  }
1684
1835
  return () => {
1685
- let positionDiff;
1686
- if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1836
+ let positionDiff = 0;
1837
+ if (dataChanged && targetId === void 0 && mvcpData) {
1838
+ const data = state.props.data;
1687
1839
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1688
1840
  const { id, position } = idsInViewWithPositions[i];
1841
+ const index = indexByKey.get(id);
1842
+ if (index !== void 0 && shouldRestorePosition) {
1843
+ const item = data[index];
1844
+ if (item === void 0 || !shouldRestorePosition(item, index, data)) {
1845
+ continue;
1846
+ }
1847
+ }
1689
1848
  const newPosition = positions.get(id);
1690
1849
  if (newPosition !== void 0) {
1691
1850
  positionDiff = newPosition - position;
@@ -1708,16 +1867,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1708
1867
  positionDiff = diff;
1709
1868
  }
1710
1869
  }
1711
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1712
- requestAdjust(ctx, state, positionDiff);
1870
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1871
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1872
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1873
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1874
+ const diff = newSize - prevSize;
1875
+ if (diff !== 0) {
1876
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1877
+ scrollingTo.itemSize = newSize;
1878
+ }
1879
+ }
1880
+ }
1881
+ if (Math.abs(positionDiff) > 0.1) {
1882
+ requestAdjust(ctx, positionDiff);
1713
1883
  }
1714
1884
  };
1715
1885
  }
1716
1886
  }
1717
1887
 
1718
1888
  // src/core/prepareColumnStartState.ts
1719
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1889
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1720
1890
  var _a3;
1891
+ const state = ctx.state;
1721
1892
  const numColumns = peek$(ctx, "numColumns");
1722
1893
  let rowStartIndex = startIndex;
1723
1894
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1732,7 +1903,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1732
1903
  const prevId = state.idCache[prevIndex];
1733
1904
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1734
1905
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1735
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1906
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1736
1907
  currentRowTop = prevPosition + prevRowHeight;
1737
1908
  }
1738
1909
  return {
@@ -1755,7 +1926,8 @@ function findRowStartIndex(state, numColumns, index) {
1755
1926
  }
1756
1927
  return rowStart;
1757
1928
  }
1758
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1929
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1930
+ const state = ctx.state;
1759
1931
  if (endIndex < startIndex) {
1760
1932
  return 0;
1761
1933
  }
@@ -1769,7 +1941,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1769
1941
  continue;
1770
1942
  }
1771
1943
  const id = state.idCache[i];
1772
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1944
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1773
1945
  if (size > maxSize) {
1774
1946
  maxSize = size;
1775
1947
  }
@@ -1778,22 +1950,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1778
1950
  }
1779
1951
 
1780
1952
  // src/core/updateTotalSize.ts
1781
- function updateTotalSize(ctx, state) {
1953
+ function updateTotalSize(ctx) {
1954
+ const state = ctx.state;
1782
1955
  const {
1783
1956
  positions,
1784
1957
  props: { data }
1785
1958
  } = state;
1786
1959
  if (data.length === 0) {
1787
- addTotalSize(ctx, state, null, 0);
1960
+ addTotalSize(ctx, null, 0);
1788
1961
  } else {
1789
1962
  const lastId = getId(state, data.length - 1);
1790
1963
  if (lastId !== void 0) {
1791
1964
  const lastPosition = positions.get(lastId);
1792
1965
  if (lastPosition !== void 0) {
1793
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1966
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1794
1967
  if (lastSize !== void 0) {
1795
1968
  const totalSize = lastPosition + lastSize;
1796
- addTotalSize(ctx, state, null, totalSize);
1969
+ addTotalSize(ctx, null, totalSize);
1797
1970
  }
1798
1971
  }
1799
1972
  }
@@ -1803,43 +1976,45 @@ function updateTotalSize(ctx, state) {
1803
1976
  // src/utils/getScrollVelocity.ts
1804
1977
  var getScrollVelocity = (state) => {
1805
1978
  const { scrollHistory } = state;
1806
- let velocity = 0;
1807
- if (scrollHistory.length >= 1) {
1808
- const newest = scrollHistory[scrollHistory.length - 1];
1809
- let oldest;
1810
- let start = 0;
1811
- const now = Date.now();
1812
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1813
- const entry = scrollHistory[i];
1814
- const nextEntry = scrollHistory[i + 1];
1815
- if (i > 0) {
1816
- const prevEntry = scrollHistory[i - 1];
1817
- const prevDirection = entry.scroll - prevEntry.scroll;
1818
- const currentDirection = nextEntry.scroll - entry.scroll;
1819
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1820
- start = i;
1821
- break;
1822
- }
1823
- }
1979
+ const newestIndex = scrollHistory.length - 1;
1980
+ if (newestIndex < 1) {
1981
+ return 0;
1982
+ }
1983
+ const newest = scrollHistory[newestIndex];
1984
+ const now = Date.now();
1985
+ let direction = 0;
1986
+ for (let i = newestIndex; i > 0; i--) {
1987
+ const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
1988
+ if (delta !== 0) {
1989
+ direction = Math.sign(delta);
1990
+ break;
1824
1991
  }
1825
- for (let i = start; i < scrollHistory.length - 1; i++) {
1826
- const entry = scrollHistory[i];
1827
- if (now - entry.time <= 1e3) {
1828
- oldest = entry;
1829
- break;
1830
- }
1992
+ }
1993
+ if (direction === 0) {
1994
+ return 0;
1995
+ }
1996
+ let oldest = newest;
1997
+ for (let i = newestIndex - 1; i >= 0; i--) {
1998
+ const current = scrollHistory[i];
1999
+ const next = scrollHistory[i + 1];
2000
+ const delta = next.scroll - current.scroll;
2001
+ const deltaSign = Math.sign(delta);
2002
+ if (deltaSign !== 0 && deltaSign !== direction) {
2003
+ break;
1831
2004
  }
1832
- if (oldest && oldest !== newest) {
1833
- const scrollDiff = newest.scroll - oldest.scroll;
1834
- const timeDiff = newest.time - oldest.time;
1835
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
2005
+ if (now - current.time > 1e3) {
2006
+ break;
1836
2007
  }
2008
+ oldest = current;
1837
2009
  }
1838
- return velocity;
2010
+ const scrollDiff = newest.scroll - oldest.scroll;
2011
+ const timeDiff = newest.time - oldest.time;
2012
+ return timeDiff > 0 ? scrollDiff / timeDiff : 0;
1839
2013
  };
1840
2014
 
1841
2015
  // src/utils/updateSnapToOffsets.ts
1842
- function updateSnapToOffsets(ctx, state) {
2016
+ function updateSnapToOffsets(ctx) {
2017
+ const state = ctx.state;
1843
2018
  const {
1844
2019
  positions,
1845
2020
  props: { snapToIndices }
@@ -1854,30 +2029,32 @@ function updateSnapToOffsets(ctx, state) {
1854
2029
  }
1855
2030
 
1856
2031
  // src/core/updateItemPositions.ts
1857
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
2032
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1858
2033
  doMVCP: false,
1859
2034
  forceFullUpdate: false,
1860
2035
  scrollBottomBuffered: -1,
1861
2036
  startIndex: 0
1862
2037
  }) {
1863
2038
  var _a3, _b, _c, _d, _e;
2039
+ const state = ctx.state;
1864
2040
  const {
1865
2041
  columns,
1866
2042
  indexByKey,
1867
2043
  positions,
1868
2044
  idCache,
1869
2045
  sizesKnown,
1870
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
2046
+ props: { data, getEstimatedItemSize, snapToIndices },
2047
+ scrollingTo
1871
2048
  } = state;
1872
- const data = state.props.data;
1873
2049
  const dataLength = data.length;
1874
2050
  const numColumns = peek$(ctx, "numColumns");
1875
- const scrollingTo = peek$(ctx, "scrollingTo");
1876
2051
  const hasColumns = numColumns > 1;
1877
2052
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1878
- const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
2053
+ const lastScrollDelta = state.lastScrollDelta;
2054
+ const velocity = getScrollVelocity(state);
2055
+ const shouldOptimize = !forceFullUpdate && !dataChanged && (Math.abs(velocity) > 0 || state.scrollLength > 0 && lastScrollDelta > state.scrollLength);
1879
2056
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1880
- const useAverageSize = enableAverages && !getEstimatedItemSize;
2057
+ const useAverageSize = !getEstimatedItemSize;
1881
2058
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1882
2059
  let currentRowTop = 0;
1883
2060
  let column = 1;
@@ -1886,7 +2063,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1886
2063
  if (hasColumns) {
1887
2064
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1888
2065
  ctx,
1889
- state,
1890
2066
  startIndex,
1891
2067
  useAverageSize
1892
2068
  );
@@ -1896,7 +2072,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1896
2072
  const prevIndex = startIndex - 1;
1897
2073
  const prevId = getId(state, prevIndex);
1898
2074
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1899
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
2075
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1900
2076
  currentRowTop = prevPosition + prevSize;
1901
2077
  }
1902
2078
  }
@@ -1913,7 +2089,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1913
2089
  breakAt = i + itemsPerRow + 10;
1914
2090
  }
1915
2091
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1916
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
2092
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1917
2093
  if (IS_DEV && needsIndexByKey) {
1918
2094
  if (indexByKeyForChecking.has(id)) {
1919
2095
  console.error(
@@ -1922,7 +2098,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1922
2098
  }
1923
2099
  indexByKeyForChecking.set(id, i);
1924
2100
  }
1925
- positions.set(id, currentRowTop);
2101
+ if (currentRowTop !== positions.get(id)) {
2102
+ positions.set(id, currentRowTop);
2103
+ notifyPosition$(ctx, id, currentRowTop);
2104
+ }
1926
2105
  if (needsIndexByKey) {
1927
2106
  indexByKey.set(id, i);
1928
2107
  }
@@ -1942,10 +2121,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1942
2121
  }
1943
2122
  }
1944
2123
  if (!didBreakEarly) {
1945
- updateTotalSize(ctx, state);
2124
+ updateTotalSize(ctx);
1946
2125
  }
1947
2126
  if (snapToIndices) {
1948
- updateSnapToOffsets(ctx, state);
2127
+ updateSnapToOffsets(ctx);
1949
2128
  }
1950
2129
  }
1951
2130
 
@@ -2023,7 +2202,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
2023
2202
  if (previousViewableItems) {
2024
2203
  for (const viewToken of previousViewableItems) {
2025
2204
  const containerId = findContainerId(ctx, viewToken.key);
2026
- if (!isViewable(
2205
+ if (!checkIsViewable(
2027
2206
  state,
2028
2207
  ctx,
2029
2208
  viewabilityConfig,
@@ -2044,7 +2223,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
2044
2223
  if (item) {
2045
2224
  const key = getId(state, i);
2046
2225
  const containerId = findContainerId(ctx, key);
2047
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2226
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2048
2227
  const viewToken = {
2049
2228
  containerId,
2050
2229
  index: i,
@@ -2104,11 +2283,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2104
2283
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
2105
2284
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
2106
2285
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
2107
- const isViewable2 = percent >= viewablePercentThreshold;
2286
+ const isViewable = percent >= viewablePercentThreshold;
2108
2287
  const value = {
2109
2288
  containerId,
2110
2289
  index,
2111
- isViewable: isViewable2,
2290
+ isViewable,
2112
2291
  item,
2113
2292
  key,
2114
2293
  percentOfScroller,
@@ -2127,8 +2306,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2127
2306
  }
2128
2307
  return value;
2129
2308
  }
2130
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2131
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2309
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2310
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2311
+ if (!value || value.key !== key) {
2312
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2313
+ }
2132
2314
  return value.isViewable;
2133
2315
  }
2134
2316
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -2156,8 +2338,9 @@ function checkAllSizesKnown(state) {
2156
2338
  }
2157
2339
 
2158
2340
  // src/utils/findAvailableContainers.ts
2159
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2341
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2160
2342
  const numContainers = peek$(ctx, "numContainers");
2343
+ const state = ctx.state;
2161
2344
  const { stickyContainerPool, containerItemTypes } = state;
2162
2345
  const result = [];
2163
2346
  const availableContainers = [];
@@ -2277,21 +2460,26 @@ function comparatorByDistance(a, b) {
2277
2460
  }
2278
2461
 
2279
2462
  // src/core/scrollToIndex.ts
2280
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2281
- if (index >= state.props.data.length) {
2282
- index = state.props.data.length - 1;
2463
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2464
+ const state = ctx.state;
2465
+ const { data } = state.props;
2466
+ if (index >= data.length) {
2467
+ index = data.length - 1;
2283
2468
  } else if (index < 0) {
2284
2469
  index = 0;
2285
2470
  }
2286
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2287
- const isLast = index === state.props.data.length - 1;
2471
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2472
+ const isLast = index === data.length - 1;
2288
2473
  if (isLast && viewPosition === void 0) {
2289
2474
  viewPosition = 1;
2290
2475
  }
2291
2476
  state.scrollForNextCalculateItemsInView = void 0;
2292
- scrollTo(ctx, state, {
2477
+ const targetId = getId(state, index);
2478
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2479
+ scrollTo(ctx, {
2293
2480
  animated,
2294
2481
  index,
2482
+ itemSize,
2295
2483
  offset: firstIndexOffset,
2296
2484
  viewOffset,
2297
2485
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2299,23 +2487,28 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2299
2487
  }
2300
2488
 
2301
2489
  // src/utils/setDidLayout.ts
2302
- function setDidLayout(ctx, state) {
2490
+ function setDidLayout(ctx) {
2491
+ const state = ctx.state;
2303
2492
  const {
2304
2493
  loadStartTime,
2305
2494
  initialScroll,
2306
2495
  props: { onLoad }
2307
2496
  } = state;
2308
2497
  state.queuedInitialLayout = true;
2309
- checkAtBottom(ctx, state);
2498
+ checkAtBottom(ctx);
2310
2499
  const setIt = () => {
2311
- set$(ctx, "containersDidLayout", true);
2500
+ setInitialRenderState(ctx, { didLayout: true });
2312
2501
  if (onLoad) {
2313
2502
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2314
2503
  }
2315
2504
  };
2316
- {
2317
- setIt();
2505
+ if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
2506
+ const target = initialScroll;
2507
+ const runScroll = () => scrollToIndex(ctx, { ...target, animated: false });
2508
+ runScroll();
2509
+ requestAnimationFrame(runScroll);
2318
2510
  }
2511
+ setIt();
2319
2512
  }
2320
2513
 
2321
2514
  // src/core/calculateItemsInView.ts
@@ -2333,15 +2526,17 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2333
2526
  }
2334
2527
  return -1;
2335
2528
  }
2336
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2529
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2530
+ const state = ctx.state;
2337
2531
  return new Set(
2338
2532
  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))
2339
2533
  );
2340
2534
  }
2341
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2535
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2342
2536
  var _a3;
2343
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2344
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2537
+ const state = ctx.state;
2538
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2539
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2345
2540
  for (let offset = 0; offset <= 1; offset++) {
2346
2541
  const idx = currentStickyIdx - offset;
2347
2542
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -2352,8 +2547,9 @@ function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, cu
2352
2547
  }
2353
2548
  }
2354
2549
  }
2355
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2550
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2356
2551
  var _a3, _b, _c;
2552
+ const state = ctx.state;
2357
2553
  for (const containerIndex of state.stickyContainerPool) {
2358
2554
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2359
2555
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
@@ -2377,7 +2573,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2377
2573
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2378
2574
  if (currentId) {
2379
2575
  const currentPos = state.positions.get(currentId);
2380
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2576
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2381
2577
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2382
2578
  }
2383
2579
  }
@@ -2386,7 +2582,8 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2386
2582
  }
2387
2583
  }
2388
2584
  }
2389
- function calculateItemsInView(ctx, state, params = {}) {
2585
+ function calculateItemsInView(ctx, params = {}) {
2586
+ const state = ctx.state;
2390
2587
  reactDom.unstable_batchedUpdates(() => {
2391
2588
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2392
2589
  const {
@@ -2410,9 +2607,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2410
2607
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2411
2608
  const prevNumContainers = peek$(ctx, "numContainers");
2412
2609
  if (!data || scrollLength === 0 || !prevNumContainers) {
2413
- if (state.initialAnchor) {
2414
- ensureInitialAnchor(ctx, state);
2415
- }
2416
2610
  return;
2417
2611
  }
2418
2612
  const totalSize = getContentSize(ctx);
@@ -2426,15 +2620,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2426
2620
  if (!queuedInitialLayout && initialScroll) {
2427
2621
  const updatedOffset = calculateOffsetWithOffsetPosition(
2428
2622
  ctx,
2429
- state,
2430
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2623
+ calculateOffsetForIndex(ctx, initialScroll.index),
2431
2624
  initialScroll
2432
2625
  );
2433
2626
  scrollState = updatedOffset;
2434
2627
  }
2435
2628
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2436
2629
  const scrollAdjustPad = scrollAdjustPending - topPad;
2437
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2630
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2438
2631
  if (scroll + scrollLength > totalSize) {
2439
2632
  scroll = Math.max(0, totalSize - scrollLength);
2440
2633
  }
@@ -2442,11 +2635,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2442
2635
  set$(ctx, "debugRawScroll", scrollState);
2443
2636
  set$(ctx, "debugComputedScroll", scroll);
2444
2637
  }
2445
- const previousStickyIndex = state.activeStickyIndex;
2638
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2446
2639
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2447
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2448
- state.activeStickyIndex = nextActiveStickyIndex;
2449
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2640
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2641
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2642
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2643
+ }
2450
2644
  let scrollBufferTop = scrollBuffer;
2451
2645
  let scrollBufferBottom = scrollBuffer;
2452
2646
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2459,23 +2653,22 @@ function calculateItemsInView(ctx, state, params = {}) {
2459
2653
  const scrollTopBuffered = scroll - scrollBufferTop;
2460
2654
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2461
2655
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2462
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2656
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2463
2657
  const { top, bottom } = scrollForNextCalculateItemsInView;
2464
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2465
- if (state.initialAnchor) {
2466
- ensureInitialAnchor(ctx, state);
2467
- }
2658
+ if (top === null && bottom === null) {
2659
+ state.scrollForNextCalculateItemsInView = void 0;
2660
+ } else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2468
2661
  return;
2469
2662
  }
2470
2663
  }
2471
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2664
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2472
2665
  if (dataChanged) {
2473
2666
  indexByKey.clear();
2474
2667
  idCache.length = 0;
2475
2668
  positions.clear();
2476
2669
  }
2477
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2478
- updateItemPositions(ctx, state, dataChanged, {
2670
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2671
+ updateItemPositions(ctx, dataChanged, {
2479
2672
  doMVCP,
2480
2673
  forceFullUpdate: !!forceFullItemPositions,
2481
2674
  scrollBottomBuffered,
@@ -2494,9 +2687,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2494
2687
  for (let i = loopStart; i >= 0; i--) {
2495
2688
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2496
2689
  const top = positions.get(id);
2497
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2690
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2498
2691
  const bottom = top + size;
2499
- if (bottom > scroll - scrollBuffer) {
2692
+ if (bottom > scroll - scrollBufferTop) {
2500
2693
  loopStart = i;
2501
2694
  } else {
2502
2695
  break;
@@ -2521,7 +2714,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2521
2714
  const dataLength = data.length;
2522
2715
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2523
2716
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2524
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2717
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2525
2718
  const top = positions.get(id);
2526
2719
  if (!foundEnd) {
2527
2720
  if (startNoBuffer === null && top + size > scroll) {
@@ -2533,7 +2726,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2533
2726
  if (startBuffered === null && top + size > scrollTopBuffered) {
2534
2727
  startBuffered = i;
2535
2728
  startBufferedId = id;
2536
- nextTop = top;
2729
+ if (scrollTopBuffered < 0) {
2730
+ nextTop = null;
2731
+ } else {
2732
+ nextTop = top;
2733
+ }
2537
2734
  }
2538
2735
  if (startNoBuffer !== null) {
2539
2736
  if (top <= scrollBottom) {
@@ -2541,7 +2738,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2541
2738
  }
2542
2739
  if (top <= scrollBottomBuffered) {
2543
2740
  endBuffered = i;
2544
- nextBottom = top + size;
2741
+ if (scrollBottomBuffered > totalSize) {
2742
+ nextBottom = null;
2743
+ } else {
2744
+ nextBottom = top + size;
2745
+ }
2545
2746
  } else {
2546
2747
  foundEnd = true;
2547
2748
  }
@@ -2563,12 +2764,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2563
2764
  startNoBuffer
2564
2765
  });
2565
2766
  if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
2566
- state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
2767
+ state.scrollForNextCalculateItemsInView = isNullOrUndefined(nextTop) && isNullOrUndefined(nextBottom) ? void 0 : {
2567
2768
  bottom: nextBottom,
2568
2769
  top: nextTop
2569
- } : void 0;
2770
+ };
2570
2771
  }
2571
- const numContainers = peek$(ctx, "numContainers");
2772
+ let numContainers = prevNumContainers;
2572
2773
  const pendingRemoval = [];
2573
2774
  if (dataChanged) {
2574
2775
  for (let i = 0; i < numContainers; i++) {
@@ -2579,7 +2780,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2579
2780
  }
2580
2781
  }
2581
2782
  if (startBuffered !== null && endBuffered !== null) {
2582
- let numContainers2 = prevNumContainers;
2583
2783
  const needNewContainers = [];
2584
2784
  for (let i = startBuffered; i <= endBuffered; i++) {
2585
2785
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
@@ -2590,7 +2790,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2590
2790
  if (stickyIndicesArr.length > 0) {
2591
2791
  handleStickyActivation(
2592
2792
  ctx,
2593
- state,
2594
2793
  stickyIndicesSet,
2595
2794
  stickyIndicesArr,
2596
2795
  currentStickyIdx,
@@ -2598,18 +2797,16 @@ function calculateItemsInView(ctx, state, params = {}) {
2598
2797
  startBuffered,
2599
2798
  endBuffered
2600
2799
  );
2601
- } else {
2602
- state.activeStickyIndex = void 0;
2603
- set$(ctx, "activeStickyIndex", void 0);
2800
+ } else if (previousStickyIndex !== -1) {
2801
+ set$(ctx, "activeStickyIndex", -1);
2604
2802
  }
2605
2803
  if (needNewContainers.length > 0) {
2606
2804
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2607
2805
  const itemType = getItemType(data[i], i);
2608
- return itemType ? String(itemType) : "";
2806
+ return itemType !== void 0 ? String(itemType) : "";
2609
2807
  }) : void 0;
2610
2808
  const availableContainers = findAvailableContainers(
2611
2809
  ctx,
2612
- state,
2613
2810
  needNewContainers.length,
2614
2811
  startBuffered,
2615
2812
  endBuffered,
@@ -2630,30 +2827,31 @@ function calculateItemsInView(ctx, state, params = {}) {
2630
2827
  if (requiredItemTypes) {
2631
2828
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2632
2829
  }
2633
- containerItemKeys.add(id);
2830
+ containerItemKeys.set(id, containerIndex);
2831
+ const containerSticky = `containerSticky${containerIndex}`;
2634
2832
  if (stickyIndicesSet.has(i)) {
2635
- set$(ctx, `containerSticky${containerIndex}`, true);
2833
+ set$(ctx, containerSticky, true);
2636
2834
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2637
2835
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2638
2836
  state.stickyContainerPool.add(containerIndex);
2639
- } else {
2640
- set$(ctx, `containerSticky${containerIndex}`, false);
2837
+ } else if (peek$(ctx, containerSticky)) {
2838
+ set$(ctx, containerSticky, false);
2641
2839
  state.stickyContainerPool.delete(containerIndex);
2642
2840
  }
2643
- if (containerIndex >= numContainers2) {
2644
- numContainers2 = containerIndex + 1;
2841
+ if (containerIndex >= numContainers) {
2842
+ numContainers = containerIndex + 1;
2645
2843
  }
2646
2844
  }
2647
- if (numContainers2 !== prevNumContainers) {
2648
- set$(ctx, "numContainers", numContainers2);
2649
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2650
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2845
+ if (numContainers !== prevNumContainers) {
2846
+ set$(ctx, "numContainers", numContainers);
2847
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2848
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2651
2849
  }
2652
2850
  }
2653
2851
  }
2654
2852
  }
2655
2853
  if (stickyIndicesArr.length > 0) {
2656
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2854
+ handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2657
2855
  }
2658
2856
  let didChangePositions = false;
2659
2857
  for (let i = 0; i < numContainers; i++) {
@@ -2705,7 +2903,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2705
2903
  }
2706
2904
  if (!queuedInitialLayout && endBuffered !== null) {
2707
2905
  if (checkAllSizesKnown(state)) {
2708
- setDidLayout(ctx, state);
2906
+ setDidLayout(ctx);
2709
2907
  }
2710
2908
  }
2711
2909
  if (viewabilityConfigCallbackPairs) {
@@ -2718,9 +2916,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2718
2916
  }
2719
2917
  }
2720
2918
  });
2721
- if (state.initialAnchor) {
2722
- ensureInitialAnchor(ctx, state);
2723
- }
2724
2919
  }
2725
2920
 
2726
2921
  // src/core/checkActualChange.ts
@@ -2743,20 +2938,69 @@ function checkActualChange(state, dataProp, previousData) {
2743
2938
  return false;
2744
2939
  }
2745
2940
 
2941
+ // src/core/checkFinishedScroll.ts
2942
+ function checkFinishedScroll(ctx) {
2943
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2944
+ }
2945
+ function checkFinishedScrollFrame(ctx) {
2946
+ const scrollingTo = ctx.state.scrollingTo;
2947
+ if (scrollingTo) {
2948
+ const { state } = ctx;
2949
+ state.animFrameCheckFinishedScroll = void 0;
2950
+ const scroll = state.scrollPending;
2951
+ const adjust = state.scrollAdjustHandler.getAdjust();
2952
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
2953
+ const maxOffset = clampScrollOffset(ctx, scroll);
2954
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
2955
+ const diff2 = Math.abs(diff1 - adjust);
2956
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
2957
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
2958
+ finishScrollTo(ctx);
2959
+ }
2960
+ }
2961
+ }
2962
+ function checkFinishedScrollFallback(ctx) {
2963
+ const state = ctx.state;
2964
+ const scrollingTo = state.scrollingTo;
2965
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
2966
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
2967
+ () => {
2968
+ let numChecks = 0;
2969
+ const checkHasScrolled = () => {
2970
+ state.timeoutCheckFinishedScrollFallback = void 0;
2971
+ const isStillScrollingTo = state.scrollingTo;
2972
+ if (isStillScrollingTo) {
2973
+ numChecks++;
2974
+ if (state.hasScrolled || numChecks > 5) {
2975
+ finishScrollTo(ctx);
2976
+ } else {
2977
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
2978
+ }
2979
+ }
2980
+ };
2981
+ checkHasScrolled();
2982
+ },
2983
+ slowTimeout ? 500 : 100
2984
+ );
2985
+ }
2986
+
2746
2987
  // src/core/doMaintainScrollAtEnd.ts
2747
- function doMaintainScrollAtEnd(ctx, state, animated) {
2988
+ function doMaintainScrollAtEnd(ctx, animated) {
2989
+ const state = ctx.state;
2748
2990
  const {
2991
+ didContainersLayout,
2992
+ isAtEnd,
2749
2993
  refScroller,
2750
2994
  props: { maintainScrollAtEnd }
2751
2995
  } = state;
2752
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2996
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2753
2997
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2754
2998
  if (paddingTop > 0) {
2755
2999
  state.scroll = 0;
2756
3000
  }
2757
3001
  requestAnimationFrame(() => {
2758
3002
  var _a3;
2759
- if (state == null ? void 0 : state.isAtEnd) {
3003
+ if (state.isAtEnd) {
2760
3004
  state.maintainingScrollAtEnd = true;
2761
3005
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2762
3006
  animated
@@ -2827,28 +3071,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2827
3071
  }
2828
3072
 
2829
3073
  // src/core/checkResetContainers.ts
2830
- function checkResetContainers(ctx, state, dataProp) {
3074
+ function checkResetContainers(ctx, dataProp) {
3075
+ const state = ctx.state;
2831
3076
  const { previousData } = state;
2832
3077
  if (previousData) {
2833
3078
  updateAveragesOnDataChange(state, previousData, dataProp);
2834
3079
  }
2835
3080
  const { maintainScrollAtEnd } = state.props;
2836
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
3081
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2837
3082
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2838
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
3083
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2839
3084
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2840
3085
  state.isEndReached = false;
2841
3086
  }
2842
3087
  if (!didMaintainScrollAtEnd) {
2843
3088
  checkAtTop(state);
2844
- checkAtBottom(ctx, state);
3089
+ checkAtBottom(ctx);
2845
3090
  }
2846
3091
  delete state.previousData;
2847
3092
  }
2848
3093
 
2849
3094
  // src/core/doInitialAllocateContainers.ts
2850
- function doInitialAllocateContainers(ctx, state) {
3095
+ function doInitialAllocateContainers(ctx) {
2851
3096
  var _a3, _b, _c;
3097
+ const state = ctx.state;
2852
3098
  const {
2853
3099
  scrollLength,
2854
3100
  props: {
@@ -2869,8 +3115,10 @@ function doInitialAllocateContainers(ctx, state) {
2869
3115
  const num = Math.min(20, data.length);
2870
3116
  for (let i = 0; i < num; i++) {
2871
3117
  const item = data[i];
2872
- const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2873
- totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
3118
+ if (item !== void 0) {
3119
+ const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
3120
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(item, i, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(item, i, itemType)) != null ? _c : estimatedItemSize;
3121
+ }
2874
3122
  }
2875
3123
  averageItemSize = totalSize / num;
2876
3124
  } else {
@@ -2886,10 +3134,10 @@ function doInitialAllocateContainers(ctx, state) {
2886
3134
  if (state.lastLayout) {
2887
3135
  if (state.initialScroll) {
2888
3136
  requestAnimationFrame(() => {
2889
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
3137
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2890
3138
  });
2891
3139
  } else {
2892
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
3140
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2893
3141
  }
2894
3142
  }
2895
3143
  return true;
@@ -2897,7 +3145,8 @@ function doInitialAllocateContainers(ctx, state) {
2897
3145
  }
2898
3146
 
2899
3147
  // src/core/handleLayout.ts
2900
- function handleLayout(ctx, state, layout, setCanRender) {
3148
+ function handleLayout(ctx, layout, setCanRender) {
3149
+ const state = ctx.state;
2901
3150
  const { maintainScrollAtEnd } = state.props;
2902
3151
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2903
3152
  const previousLength = state.scrollLength;
@@ -2913,19 +3162,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2913
3162
  state.lastBatchingAction = Date.now();
2914
3163
  state.scrollForNextCalculateItemsInView = void 0;
2915
3164
  if (scrollLength > 0) {
2916
- doInitialAllocateContainers(ctx, state);
3165
+ doInitialAllocateContainers(ctx);
2917
3166
  }
2918
3167
  if (needsCalculate) {
2919
- calculateItemsInView(ctx, state, { doMVCP: true });
3168
+ calculateItemsInView(ctx, { doMVCP: true });
2920
3169
  }
2921
3170
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2922
3171
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2923
3172
  }
2924
3173
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2925
- doMaintainScrollAtEnd(ctx, state, false);
3174
+ doMaintainScrollAtEnd(ctx, false);
2926
3175
  }
2927
- updateAlignItemsPaddingTop(ctx, state);
2928
- checkAtBottom(ctx, state);
3176
+ updateAlignItemsPaddingTop(ctx);
3177
+ checkAtBottom(ctx);
2929
3178
  checkAtTop(state);
2930
3179
  if (state) {
2931
3180
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2941,8 +3190,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2941
3190
  }
2942
3191
 
2943
3192
  // src/core/onScroll.ts
2944
- function onScroll(ctx, state, event) {
3193
+ function onScroll(ctx, event) {
2945
3194
  var _a3, _b, _c;
3195
+ const state = ctx.state;
2946
3196
  const {
2947
3197
  scrollProcessingEnabled,
2948
3198
  props: { onScroll: onScrollProp }
@@ -2953,9 +3203,25 @@ function onScroll(ctx, state, event) {
2953
3203
  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) {
2954
3204
  return;
2955
3205
  }
2956
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3206
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3207
+ if (state.scrollingTo) {
3208
+ const maxOffset = clampScrollOffset(ctx, newScroll);
3209
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3210
+ newScroll = maxOffset;
3211
+ scrollTo(ctx, {
3212
+ forceScroll: true,
3213
+ isInitialScroll: true,
3214
+ noScrollingTo: true,
3215
+ offset: newScroll
3216
+ });
3217
+ return;
3218
+ }
3219
+ }
2957
3220
  state.scrollPending = newScroll;
2958
- updateScroll(ctx, state, newScroll);
3221
+ updateScroll(ctx, newScroll);
3222
+ if (state.scrollingTo) {
3223
+ checkFinishedScroll(ctx);
3224
+ }
2959
3225
  onScrollProp == null ? void 0 : onScrollProp(event);
2960
3226
  }
2961
3227
 
@@ -2964,51 +3230,58 @@ var ScrollAdjustHandler = class {
2964
3230
  constructor(ctx) {
2965
3231
  this.appliedAdjust = 0;
2966
3232
  this.pendingAdjust = 0;
2967
- this.mounted = false;
2968
- this.context = ctx;
2969
- {
2970
- const commitPendingAdjust = () => {
2971
- const state = this.context.internalState;
2972
- const pending = this.pendingAdjust;
2973
- if (pending !== 0) {
2974
- this.pendingAdjust = 0;
2975
- this.appliedAdjust += pending;
2976
- state.scroll += pending;
2977
- state.scrollForNextCalculateItemsInView = void 0;
2978
- set$(this.context, "scrollAdjustPending", 0);
2979
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2980
- calculateItemsInView(this.context, this.context.internalState);
2981
- }
2982
- };
2983
- listen$(this.context, "scrollingTo", (value) => {
2984
- if (value === void 0) {
2985
- commitPendingAdjust();
2986
- }
2987
- });
2988
- }
3233
+ this.ctx = ctx;
2989
3234
  }
2990
3235
  requestAdjust(add) {
2991
- const scrollingTo = peek$(this.context, "scrollingTo");
3236
+ const scrollingTo = this.ctx.state.scrollingTo;
2992
3237
  if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2993
3238
  this.pendingAdjust += add;
2994
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
3239
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2995
3240
  } else {
2996
3241
  this.appliedAdjust += add;
2997
- set$(this.context, "scrollAdjust", this.appliedAdjust);
3242
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3243
+ }
3244
+ if (this.ctx.state.scrollingTo) {
3245
+ checkFinishedScroll(this.ctx);
2998
3246
  }
2999
- }
3000
- setMounted() {
3001
- this.mounted = true;
3002
3247
  }
3003
3248
  getAdjust() {
3004
3249
  return this.appliedAdjust;
3005
3250
  }
3251
+ commitPendingAdjust(scrollTarget) {
3252
+ {
3253
+ const state = this.ctx.state;
3254
+ const pending = this.pendingAdjust;
3255
+ this.pendingAdjust = 0;
3256
+ if (pending !== 0) {
3257
+ let targetScroll;
3258
+ if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3259
+ const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3260
+ targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3261
+ targetScroll = clampScrollOffset(this.ctx, targetScroll);
3262
+ } else {
3263
+ targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3264
+ }
3265
+ const adjustment = targetScroll - state.scroll;
3266
+ if (Math.abs(adjustment) > 0.1 || Math.abs(pending) > 0.1) {
3267
+ this.appliedAdjust += adjustment;
3268
+ state.scroll = targetScroll;
3269
+ state.scrollForNextCalculateItemsInView = void 0;
3270
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3271
+ }
3272
+ set$(this.ctx, "scrollAdjustPending", 0);
3273
+ calculateItemsInView(this.ctx);
3274
+ }
3275
+ }
3276
+ }
3006
3277
  };
3007
3278
 
3008
3279
  // src/core/updateItemSize.ts
3009
- function updateItemSize(ctx, state, itemKey, sizeObj) {
3280
+ function updateItemSize(ctx, itemKey, sizeObj) {
3010
3281
  var _a3;
3282
+ const state = ctx.state;
3011
3283
  const {
3284
+ didContainersLayout,
3012
3285
  sizesKnown,
3013
3286
  props: {
3014
3287
  getFixedItemSize,
@@ -3031,31 +3304,24 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
3031
3304
  return;
3032
3305
  }
3033
3306
  const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
3034
- const size2 = getFixedItemSize(index, itemData, type);
3307
+ const size2 = getFixedItemSize(itemData, index, type);
3035
3308
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
3036
3309
  return;
3037
3310
  }
3038
3311
  }
3039
- const containersDidLayout = peek$(ctx, "containersDidLayout");
3040
- let needsRecalculate = !containersDidLayout;
3312
+ let needsRecalculate = !didContainersLayout;
3041
3313
  let shouldMaintainScrollAtEnd = false;
3042
3314
  let minIndexSizeChanged;
3043
3315
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
3044
3316
  const prevSizeKnown = state.sizesKnown.get(itemKey);
3045
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3317
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
3046
3318
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
3047
3319
  if (diff !== 0) {
3048
3320
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
3049
3321
  const { startBuffered, endBuffered } = state;
3050
3322
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
3051
- if (!needsRecalculate) {
3052
- const numContainers = ctx.values.get("numContainers");
3053
- for (let i = 0; i < numContainers; i++) {
3054
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
3055
- needsRecalculate = true;
3056
- break;
3057
- }
3058
- }
3323
+ if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
3324
+ needsRecalculate = true;
3059
3325
  }
3060
3326
  if (state.needsOtherAxisSize) {
3061
3327
  const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
@@ -3091,22 +3357,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
3091
3357
  if (!cur || maxOtherAxisSize > cur) {
3092
3358
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
3093
3359
  }
3094
- if (containersDidLayout || checkAllSizesKnown(state)) {
3360
+ if (didContainersLayout || checkAllSizesKnown(state)) {
3095
3361
  if (needsRecalculate) {
3096
3362
  state.scrollForNextCalculateItemsInView = void 0;
3097
- calculateItemsInView(ctx, state, { doMVCP: true });
3363
+ calculateItemsInView(ctx, { doMVCP: true });
3098
3364
  }
3099
3365
  if (shouldMaintainScrollAtEnd) {
3100
3366
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
3101
- doMaintainScrollAtEnd(ctx, state, false);
3367
+ doMaintainScrollAtEnd(ctx, false);
3102
3368
  }
3103
3369
  }
3104
3370
  }
3105
3371
  }
3106
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3372
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
3107
3373
  var _a3;
3374
+ const state = ctx.state;
3108
3375
  const {
3109
- sizes,
3110
3376
  indexByKey,
3111
3377
  sizesKnown,
3112
3378
  averageSizes,
@@ -3114,9 +3380,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3114
3380
  } = state;
3115
3381
  if (!data) return 0;
3116
3382
  const index = indexByKey.get(itemKey);
3117
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3383
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
3118
3384
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
3119
3385
  const size = Math.round(rawSize) ;
3386
+ const prevSizeKnown = sizesKnown.get(itemKey);
3120
3387
  sizesKnown.set(itemKey, size);
3121
3388
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
3122
3389
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -3124,15 +3391,25 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3124
3391
  if (!averages) {
3125
3392
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3126
3393
  }
3127
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3128
- averages.num++;
3394
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3395
+ averages.avg += (size - prevSizeKnown) / averages.num;
3396
+ } else {
3397
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3398
+ averages.num++;
3399
+ }
3129
3400
  }
3130
3401
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
3131
- setSize(ctx, state, itemKey, size);
3402
+ setSize(ctx, itemKey, size);
3132
3403
  return size - prevSize;
3133
3404
  }
3134
3405
  return 0;
3135
3406
  }
3407
+ function useWrapIfItem(fn) {
3408
+ return React3.useMemo(
3409
+ () => fn ? (arg1, arg2, arg3) => arg1 !== void 0 && arg2 !== void 0 ? fn(arg1, arg2, arg3) : void 0 : void 0,
3410
+ [fn]
3411
+ );
3412
+ }
3136
3413
  var useCombinedRef = (...refs) => {
3137
3414
  const callback = React3.useCallback((element) => {
3138
3415
  for (const ref of refs) {
@@ -3175,14 +3452,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
3175
3452
  }
3176
3453
 
3177
3454
  // src/utils/createImperativeHandle.ts
3178
- function createImperativeHandle(ctx, state) {
3455
+ function createImperativeHandle(ctx) {
3456
+ const state = ctx.state;
3179
3457
  const scrollIndexIntoView = (options) => {
3180
3458
  if (state) {
3181
3459
  const { index, ...rest } = options;
3182
3460
  const { startNoBuffer, endNoBuffer } = state;
3183
3461
  if (index < startNoBuffer || index > endNoBuffer) {
3184
3462
  const viewPosition = index < startNoBuffer ? 0 : 1;
3185
- scrollToIndex(ctx, state, {
3463
+ scrollToIndex(ctx, {
3186
3464
  ...rest,
3187
3465
  index,
3188
3466
  viewPosition
@@ -3197,7 +3475,7 @@ function createImperativeHandle(ctx, state) {
3197
3475
  getScrollableNode: () => refScroller.current.getScrollableNode(),
3198
3476
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3199
3477
  getState: () => ({
3200
- activeStickyIndex: state.activeStickyIndex,
3478
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3201
3479
  contentLength: state.totalSize,
3202
3480
  data: state.props.data,
3203
3481
  elementAtIndex: (index) => {
@@ -3208,6 +3486,8 @@ function createImperativeHandle(ctx, state) {
3208
3486
  endBuffered: state.endBuffered,
3209
3487
  isAtEnd: state.isAtEnd,
3210
3488
  isAtStart: state.isAtStart,
3489
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3490
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3211
3491
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
3212
3492
  positions: state.positions,
3213
3493
  scroll: state.scroll,
@@ -3232,23 +3512,23 @@ function createImperativeHandle(ctx, state) {
3232
3512
  if (index !== -1) {
3233
3513
  const paddingBottom = stylePaddingBottom || 0;
3234
3514
  const footerSize = peek$(ctx, "footerSize") || 0;
3235
- scrollToIndex(ctx, state, {
3515
+ scrollToIndex(ctx, {
3516
+ ...options,
3236
3517
  index,
3237
3518
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3238
- viewPosition: 1,
3239
- ...options
3519
+ viewPosition: 1
3240
3520
  });
3241
3521
  }
3242
3522
  },
3243
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3523
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
3244
3524
  scrollToItem: ({ item, ...props }) => {
3245
3525
  const data = state.props.data;
3246
3526
  const index = data.indexOf(item);
3247
3527
  if (index !== -1) {
3248
- scrollToIndex(ctx, state, { index, ...props });
3528
+ scrollToIndex(ctx, { index, ...props });
3249
3529
  }
3250
3530
  },
3251
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3531
+ scrollToOffset: (params) => scrollTo(ctx, params),
3252
3532
  setScrollProcessingEnabled: (enabled) => {
3253
3533
  state.scrollProcessingEnabled = enabled;
3254
3534
  },
@@ -3258,8 +3538,9 @@ function createImperativeHandle(ctx, state) {
3258
3538
  }
3259
3539
  };
3260
3540
  }
3261
- function getRenderedItem(ctx, state, key) {
3541
+ function getRenderedItem(ctx, key) {
3262
3542
  var _a3;
3543
+ const state = ctx.state;
3263
3544
  if (!state) {
3264
3545
  return null;
3265
3546
  }
@@ -3286,6 +3567,25 @@ function getRenderedItem(ctx, state, key) {
3286
3567
  }
3287
3568
  return { index, item: data[index], renderedItem };
3288
3569
  }
3570
+
3571
+ // src/utils/normalizeMaintainVisibleContentPosition.ts
3572
+ function normalizeMaintainVisibleContentPosition(value) {
3573
+ var _a3, _b;
3574
+ if (value === true) {
3575
+ return { data: true, size: true };
3576
+ }
3577
+ if (value && typeof value === "object") {
3578
+ return {
3579
+ data: (_a3 = value.data) != null ? _a3 : false,
3580
+ size: (_b = value.size) != null ? _b : true,
3581
+ shouldRestorePosition: value.shouldRestorePosition
3582
+ };
3583
+ }
3584
+ if (value === false) {
3585
+ return { data: false, size: false };
3586
+ }
3587
+ return { data: false, size: true };
3588
+ }
3289
3589
  function useThrottleDebounce(mode) {
3290
3590
  const timeoutRef = React3.useRef(null);
3291
3591
  const lastCallTimeRef = React3.useRef(0);
@@ -3336,6 +3636,7 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3336
3636
  var DEFAULT_DRAW_DISTANCE = 250;
3337
3637
  var DEFAULT_ITEM_SIZE = 100;
3338
3638
  var LegendList = typedMemo(
3639
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3339
3640
  typedForwardRef(function LegendList2(props, forwardedRef) {
3340
3641
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3341
3642
  const isChildrenMode = children !== void 0 && dataProp === void 0;
@@ -3358,10 +3659,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3358
3659
  alignItemsAtEnd = false,
3359
3660
  columnWrapperStyle,
3360
3661
  contentContainerStyle: contentContainerStyleProp,
3662
+ contentInset,
3361
3663
  data: dataProp = [],
3362
3664
  dataVersion,
3363
3665
  drawDistance = 250,
3364
- enableAverages = true,
3365
3666
  estimatedItemSize: estimatedItemSizeProp,
3366
3667
  estimatedListSize,
3367
3668
  extraData,
@@ -3379,7 +3680,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3379
3680
  ListHeaderComponent,
3380
3681
  maintainScrollAtEnd = false,
3381
3682
  maintainScrollAtEndThreshold = 0.1,
3382
- maintainVisibleContentPosition = false,
3683
+ maintainVisibleContentPosition: maintainVisibleContentPositionProp,
3383
3684
  numColumns: numColumnsProp = 1,
3384
3685
  onEndReached,
3385
3686
  onEndReachedThreshold = 0.5,
@@ -3403,20 +3704,26 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3403
3704
  snapToIndices,
3404
3705
  stickyHeaderIndices: stickyHeaderIndicesProp,
3405
3706
  stickyIndices: stickyIndicesDeprecated,
3707
+ // TODOV3: Remove from v3 release
3406
3708
  style: styleProp,
3407
3709
  suggestEstimatedItemSize,
3408
3710
  viewabilityConfig,
3409
3711
  viewabilityConfigCallbackPairs,
3410
3712
  waitForInitialLayout = true,
3713
+ stickyHeaderConfig,
3411
3714
  ...rest
3412
3715
  } = props;
3716
+ const animatedPropsInternal = props.animatedPropsInternal;
3413
3717
  const { childrenMode } = rest;
3414
3718
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3415
3719
  const style = { ...StyleSheet.flatten(styleProp) };
3416
3720
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
3417
3721
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
3722
+ const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
3723
+ maintainVisibleContentPositionProp
3724
+ );
3418
3725
  const [renderNum, setRenderNum] = React3.useState(0);
3419
- const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState } : initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3726
+ const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState, viewPosition: 1 } : initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3420
3727
  const [canRender, setCanRender] = React3__namespace.useState(!IsNewArchitecture);
3421
3728
  const ctx = useStateContext();
3422
3729
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
@@ -3434,13 +3741,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3434
3741
  }
3435
3742
  const refState = React3.useRef();
3436
3743
  if (!refState.current) {
3437
- if (!ctx.internalState) {
3744
+ if (!ctx.state) {
3438
3745
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
3439
- ctx.internalState = {
3440
- activeStickyIndex: void 0,
3746
+ ctx.state = {
3747
+ activeStickyIndex: -1,
3441
3748
  averageSizes: {},
3442
3749
  columns: /* @__PURE__ */ new Map(),
3443
- containerItemKeys: /* @__PURE__ */ new Set(),
3750
+ containerItemKeys: /* @__PURE__ */ new Map(),
3444
3751
  containerItemTypes: /* @__PURE__ */ new Map(),
3445
3752
  dataChangeNeedsScrollUpdate: false,
3446
3753
  didColumnsChange: false,
@@ -3463,11 +3770,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3463
3770
  initialScroll: initialScrollProp,
3464
3771
  isAtEnd: false,
3465
3772
  isAtStart: false,
3466
- isEndReached: false,
3773
+ isEndReached: null,
3467
3774
  isFirst: true,
3468
- isStartReached: false,
3775
+ isStartReached: null,
3469
3776
  lastBatchingAction: Date.now(),
3470
3777
  lastLayout: void 0,
3778
+ lastScrollDelta: 0,
3471
3779
  loadStartTime: Date.now(),
3472
3780
  minIndexSizeChanged: 0,
3473
3781
  nativeMarginTop: 0,
@@ -3497,12 +3805,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3497
3805
  totalSize: 0,
3498
3806
  viewabilityConfigCallbackPairs: void 0
3499
3807
  };
3500
- const internalState = ctx.internalState;
3501
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3502
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3808
+ const internalState = ctx.state;
3809
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3810
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
3503
3811
  set$(ctx, "extraData", extraData);
3504
3812
  }
3505
- refState.current = ctx.internalState;
3813
+ refState.current = ctx.state;
3506
3814
  }
3507
3815
  const state = refState.current;
3508
3816
  const isFirstLocal = state.isFirst;
@@ -3516,20 +3824,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3516
3824
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3517
3825
  state.props = {
3518
3826
  alignItemsAtEnd,
3827
+ animatedProps: animatedPropsInternal,
3828
+ contentInset,
3519
3829
  data: dataProp,
3520
3830
  dataVersion,
3521
- enableAverages,
3522
3831
  estimatedItemSize,
3523
- getEstimatedItemSize,
3524
- getFixedItemSize,
3525
- getItemType,
3832
+ getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3833
+ getFixedItemSize: useWrapIfItem(getFixedItemSize),
3834
+ getItemType: useWrapIfItem(getItemType),
3526
3835
  horizontal: !!horizontal,
3527
3836
  initialContainerPoolRatio,
3528
3837
  itemsAreEqual,
3529
- keyExtractor,
3838
+ keyExtractor: useWrapIfItem(keyExtractor),
3530
3839
  maintainScrollAtEnd,
3531
3840
  maintainScrollAtEndThreshold,
3532
- maintainVisibleContentPosition,
3841
+ maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
3533
3842
  numColumns: numColumnsProp,
3534
3843
  onEndReached,
3535
3844
  onEndReachedThreshold,
@@ -3561,57 +3870,47 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3561
3870
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3562
3871
  set$(ctx, "numColumns", numColumnsProp);
3563
3872
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3564
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3873
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3565
3874
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3566
3875
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3567
- if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3876
+ if (maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3568
3877
  if (state.scroll < 0) {
3569
3878
  paddingDiff += state.scroll;
3570
3879
  }
3571
- requestAdjust(ctx, state, paddingDiff);
3880
+ requestAdjust(ctx, paddingDiff);
3572
3881
  }
3573
3882
  };
3574
3883
  if (isFirstLocal) {
3575
3884
  initializeStateVars();
3576
3885
  updateItemPositions(
3577
3886
  ctx,
3578
- state,
3579
3887
  /*dataChanged*/
3580
3888
  true
3581
3889
  );
3582
3890
  }
3583
3891
  const initialContentOffset = React3.useMemo(() => {
3584
- var _a4, _b2;
3585
- const { initialScroll } = refState.current;
3586
- if (!initialScroll) {
3892
+ let value;
3893
+ const { initialScroll, initialAnchor } = refState.current;
3894
+ if (initialScroll) {
3895
+ if (initialScroll.contentOffset !== void 0) {
3896
+ value = initialScroll.contentOffset;
3897
+ } else {
3898
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3899
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3900
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3901
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3902
+ refState.current.initialScroll = updatedInitialScroll;
3903
+ state.initialScroll = updatedInitialScroll;
3904
+ value = clampedOffset;
3905
+ }
3906
+ } else {
3587
3907
  refState.current.initialAnchor = void 0;
3588
- return 0;
3589
- }
3590
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3591
- refState.current.initialAnchor = {
3592
- attempts: 0,
3593
- index: initialScroll.index,
3594
- settledTicks: 0,
3595
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3596
- viewPosition: initialScroll.viewPosition
3597
- };
3908
+ value = 0;
3909
+ }
3910
+ if (!value) {
3911
+ setInitialRenderState(ctx, { didInitialScroll: true });
3598
3912
  }
3599
- if (initialScroll.contentOffset !== void 0) {
3600
- return initialScroll.contentOffset;
3601
- }
3602
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3603
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3604
- let clampedOffset = resolvedOffset;
3605
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3606
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3607
- clampedOffset = Math.min(clampedOffset, maxOffset);
3608
- }
3609
- clampedOffset = Math.max(0, clampedOffset);
3610
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3611
- refState.current.initialScroll = updatedInitialScroll;
3612
- state.initialScroll = updatedInitialScroll;
3613
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3614
- return clampedOffset;
3913
+ return value;
3615
3914
  }, [renderNum]);
3616
3915
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3617
3916
  refState.current.lastBatchingAction = Date.now();
@@ -3639,12 +3938,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3639
3938
  }
3640
3939
  }, []);
3641
3940
  const doInitialScroll = React3.useCallback(() => {
3642
- var _a4;
3643
- const initialScroll = state.initialScroll;
3644
- if (initialScroll) {
3645
- scrollTo(ctx, state, {
3941
+ const { initialScroll, didFinishInitialScroll, queuedInitialLayout, scrollingTo } = state;
3942
+ if (initialScroll && !queuedInitialLayout && !didFinishInitialScroll && !scrollingTo) {
3943
+ scrollTo(ctx, {
3646
3944
  animated: false,
3647
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3945
+ index: initialScroll == null ? void 0 : initialScroll.index,
3648
3946
  isInitialScroll: true,
3649
3947
  offset: initialContentOffset,
3650
3948
  precomputedWithViewOffset: true
@@ -3653,7 +3951,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3653
3951
  }, [initialContentOffset]);
3654
3952
  const onLayoutChange = React3.useCallback((layout) => {
3655
3953
  doInitialScroll();
3656
- handleLayout(ctx, state, layout, setCanRender);
3954
+ handleLayout(ctx, layout, setCanRender);
3657
3955
  }, []);
3658
3956
  const { onLayout } = useOnLayoutSync({
3659
3957
  onLayoutChange,
@@ -3663,7 +3961,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3663
3961
  });
3664
3962
  React3.useLayoutEffect(() => {
3665
3963
  if (snapToIndices) {
3666
- updateSnapToOffsets(ctx, state);
3964
+ updateSnapToOffsets(ctx);
3667
3965
  }
3668
3966
  }, [snapToIndices]);
3669
3967
  React3.useLayoutEffect(() => {
@@ -3673,9 +3971,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3673
3971
  isFirst,
3674
3972
  props: { data }
3675
3973
  } = state;
3676
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3974
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3677
3975
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3678
- checkResetContainers(ctx, state, data);
3976
+ checkResetContainers(ctx, data);
3679
3977
  }
3680
3978
  state.didColumnsChange = false;
3681
3979
  state.didDataChange = false;
@@ -3700,15 +3998,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3700
3998
  state.viewabilityConfigCallbackPairs = viewability;
3701
3999
  state.enableScrollForNextCalculateItemsInView = !viewability;
3702
4000
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3703
- React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
4001
+ React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3704
4002
  {
3705
4003
  React3.useEffect(doInitialScroll, []);
3706
4004
  }
3707
4005
  const fns = React3.useMemo(
3708
4006
  () => ({
3709
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3710
- onScroll: (event) => onScroll(ctx, state, event),
3711
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
4007
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
4008
+ onMomentumScrollEnd: (event) => {
4009
+ checkFinishedScrollFallback(ctx);
4010
+ if (onMomentumScrollEnd) {
4011
+ onMomentumScrollEnd(event);
4012
+ }
4013
+ },
4014
+ onScroll: (event) => onScroll(ctx, event),
4015
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3712
4016
  }),
3713
4017
  []
3714
4018
  );
@@ -3720,24 +4024,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3720
4024
  alignItemsAtEnd,
3721
4025
  canRender,
3722
4026
  contentContainerStyle,
4027
+ contentInset,
3723
4028
  getRenderedItem: fns.getRenderedItem,
3724
4029
  horizontal,
3725
4030
  initialContentOffset,
3726
4031
  ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
3727
4032
  ListHeaderComponent,
3728
- maintainVisibleContentPosition,
3729
4033
  onLayout,
3730
4034
  onLayoutHeader,
3731
- onMomentumScrollEnd: (event) => {
3732
- {
3733
- requestAnimationFrame(() => {
3734
- finishScrollTo(ctx, refState.current);
3735
- });
3736
- }
3737
- if (onMomentumScrollEnd) {
3738
- onMomentumScrollEnd(event);
3739
- }
3740
- },
4035
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3741
4036
  onScroll: onScrollHandler,
3742
4037
  recycleItems,
3743
4038
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControl, {
@@ -3752,8 +4047,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3752
4047
  ),
3753
4048
  refScrollView: combinedRef,
3754
4049
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3755
- scrollEventThrottle: 16 ,
4050
+ scrollEventThrottle: 0,
3756
4051
  snapToIndices,
4052
+ stickyHeaderConfig,
3757
4053
  stickyHeaderIndices,
3758
4054
  style,
3759
4055
  updateItemSize: fns.updateItemSize,
@@ -3763,6 +4059,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3763
4059
  });
3764
4060
 
3765
4061
  exports.LegendList = LegendList;
4062
+ exports.typedForwardRef = typedForwardRef;
4063
+ exports.typedMemo = typedMemo;
3766
4064
  exports.useIsLastItem = useIsLastItem;
3767
4065
  exports.useListScrollSize = useListScrollSize;
3768
4066
  exports.useRecyclingEffect = useRecyclingEffect;