@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.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React3 from 'react';
2
2
  import React3__default, { forwardRef, useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useImperativeHandle, useLayoutEffect, memo, useContext } from 'react';
3
3
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
4
- import { unstable_batchedUpdates } from 'react-dom';
4
+ import { unstable_batchedUpdates, flushSync } from 'react-dom';
5
5
 
6
6
  // src/components/LegendList.tsx
7
7
  forwardRef(function AnimatedView2(props, ref) {
@@ -12,31 +12,65 @@ var View = forwardRef(function View2(props, ref) {
12
12
  });
13
13
  var Text = View;
14
14
 
15
+ // src/state/getContentInsetEnd.ts
16
+ function getContentInsetEnd(state) {
17
+ var _a3;
18
+ const { props } = state;
19
+ const horizontal = props.horizontal;
20
+ let contentInset = props.contentInset;
21
+ if (!contentInset) {
22
+ const animatedInset = (_a3 = props.animatedProps) == null ? void 0 : _a3.contentInset;
23
+ if (animatedInset) {
24
+ if ("get" in animatedInset) {
25
+ contentInset = animatedInset.get();
26
+ } else {
27
+ contentInset = animatedInset;
28
+ }
29
+ }
30
+ }
31
+ return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
32
+ }
33
+
34
+ // src/state/getContentSize.ts
35
+ function getContentSize(ctx) {
36
+ var _a3;
37
+ const { values, state } = ctx;
38
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
39
+ const stylePaddingBottom = state.props.stylePaddingBottom || 0;
40
+ const headerSize = values.get("headerSize") || 0;
41
+ const footerSize = values.get("footerSize") || 0;
42
+ const contentInsetBottom = getContentInsetEnd(state);
43
+ const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
44
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
45
+ }
46
+
15
47
  // src/platform/Animated.tsx
16
48
  var createAnimatedValue = (value) => value;
17
49
 
18
50
  // src/state/state.tsx
19
51
  var ContextState = React3.createContext(null);
52
+ var contextNum = 0;
20
53
  function StateProvider({ children }) {
21
54
  const [value] = React3.useState(() => ({
22
55
  animatedScrollY: createAnimatedValue(0),
23
56
  columnWrapperStyle: void 0,
24
- internalState: void 0,
57
+ contextNum: contextNum++,
25
58
  listeners: /* @__PURE__ */ new Map(),
26
59
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
27
60
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
28
61
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
29
62
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
30
63
  mapViewabilityValues: /* @__PURE__ */ new Map(),
64
+ positionListeners: /* @__PURE__ */ new Map(),
65
+ state: void 0,
31
66
  values: /* @__PURE__ */ new Map([
32
67
  ["alignItemsPaddingTop", 0],
33
68
  ["stylePaddingTop", 0],
34
69
  ["headerSize", 0],
35
70
  ["numContainers", 0],
36
- ["activeStickyIndex", void 0],
71
+ ["activeStickyIndex", -1],
37
72
  ["totalSize", 0],
38
- ["scrollAdjustPending", 0],
39
- ["scrollingTo", void 0]
73
+ ["scrollAdjustPending", 0]
40
74
  ]),
41
75
  viewRefs: /* @__PURE__ */ new Map()
42
76
  }));
@@ -104,15 +138,24 @@ function set$(ctx, signalName, value) {
104
138
  }
105
139
  }
106
140
  }
107
- function getContentSize(ctx) {
108
- var _a3, _b;
109
- const { values, internalState } = ctx;
110
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
111
- const stylePaddingBottom = (internalState == null ? void 0 : internalState.props.stylePaddingBottom) || 0;
112
- const headerSize = values.get("headerSize") || 0;
113
- const footerSize = values.get("footerSize") || 0;
114
- const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
115
- return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom;
141
+ function listenPosition$(ctx, key, cb) {
142
+ const { positionListeners } = ctx;
143
+ let setListeners = positionListeners.get(key);
144
+ if (!setListeners) {
145
+ setListeners = /* @__PURE__ */ new Set();
146
+ positionListeners.set(key, setListeners);
147
+ }
148
+ setListeners.add(cb);
149
+ return () => setListeners.delete(cb);
150
+ }
151
+ function notifyPosition$(ctx, key, value) {
152
+ const { positionListeners } = ctx;
153
+ const setListeners = positionListeners.get(key);
154
+ if (setListeners) {
155
+ for (const listener of setListeners) {
156
+ listener(value);
157
+ }
158
+ }
116
159
  }
117
160
  function useArr$(signalNames) {
118
161
  const ctx = React3.useContext(ContextState);
@@ -223,6 +266,11 @@ function extractPadding(style, contentContainerStyle, type) {
223
266
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
224
267
  }
225
268
  function findContainerId(ctx, key) {
269
+ var _a3, _b;
270
+ const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
271
+ if (directMatch !== void 0) {
272
+ return directMatch;
273
+ }
226
274
  const numContainers = peek$(ctx, "numContainers");
227
275
  for (let i = 0; i < numContainers; i++) {
228
276
  const itemKey = peek$(ctx, `containerItemKey${i}`);
@@ -234,12 +282,12 @@ function findContainerId(ctx, key) {
234
282
  }
235
283
 
236
284
  // src/components/PositionView.tsx
237
- var PositionViewState = typedMemo(function PositionView({
285
+ var PositionViewState = typedMemo(function PositionViewState2({
238
286
  id,
239
287
  horizontal,
240
288
  style,
241
289
  refView,
242
- ...rest
290
+ ...props
243
291
  }) {
244
292
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
245
293
  const base = {
@@ -247,7 +295,8 @@ var PositionViewState = typedMemo(function PositionView({
247
295
  };
248
296
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
249
297
  const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
250
- return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: combinedStyle, ...rest });
298
+ const { animatedScrollY, stickyOffset, onLayout, ...webProps } = props;
299
+ return /* @__PURE__ */ React3.createElement("div", { ref: refView, ...webProps, style: combinedStyle });
251
300
  });
252
301
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
253
302
  id,
@@ -292,63 +341,80 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
292
341
  }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
293
342
  return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
294
343
  });
295
- var PositionView2 = PositionViewState;
344
+ var PositionView = PositionViewState;
296
345
 
297
346
  // src/constants-platform.ts
298
347
  var IsNewArchitecture = true;
299
- var symbolFirst = Symbol();
300
348
  function useInit(cb) {
301
- const refValue = useRef(symbolFirst);
302
- if (refValue.current === symbolFirst) {
303
- refValue.current = cb();
304
- }
305
- return refValue.current;
349
+ useState(() => cb());
306
350
  }
307
351
 
308
352
  // src/state/ContextContainer.ts
309
353
  var ContextContainer = createContext(null);
354
+ function useContextContainer() {
355
+ return useContext(ContextContainer);
356
+ }
310
357
  function useViewability(callback, configId) {
311
358
  const ctx = useStateContext();
312
- const { containerId } = useContext(ContextContainer);
313
- const key = containerId + (configId != null ? configId : "");
359
+ const containerContext = useContextContainer();
314
360
  useInit(() => {
361
+ if (!containerContext) {
362
+ return;
363
+ }
364
+ const { containerId } = containerContext;
365
+ const key = containerId + (configId != null ? configId : "");
315
366
  const value = ctx.mapViewabilityValues.get(key);
316
367
  if (value) {
317
368
  callback(value);
318
369
  }
319
370
  });
320
- ctx.mapViewabilityCallbacks.set(key, callback);
321
- useEffect(
322
- () => () => {
371
+ useEffect(() => {
372
+ if (!containerContext) {
373
+ return;
374
+ }
375
+ const { containerId } = containerContext;
376
+ const key = containerId + (configId != null ? configId : "");
377
+ ctx.mapViewabilityCallbacks.set(key, callback);
378
+ return () => {
323
379
  ctx.mapViewabilityCallbacks.delete(key);
324
- },
325
- []
326
- );
380
+ };
381
+ }, [ctx, callback, configId, containerContext]);
327
382
  }
328
383
  function useViewabilityAmount(callback) {
329
384
  const ctx = useStateContext();
330
- const { containerId } = useContext(ContextContainer);
385
+ const containerContext = useContextContainer();
331
386
  useInit(() => {
387
+ if (!containerContext) {
388
+ return;
389
+ }
390
+ const { containerId } = containerContext;
332
391
  const value = ctx.mapViewabilityAmountValues.get(containerId);
333
392
  if (value) {
334
393
  callback(value);
335
394
  }
336
395
  });
337
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
338
- useEffect(
339
- () => () => {
396
+ useEffect(() => {
397
+ if (!containerContext) {
398
+ return;
399
+ }
400
+ const { containerId } = containerContext;
401
+ ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
402
+ return () => {
340
403
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
341
- },
342
- []
343
- );
404
+ };
405
+ }, [ctx, callback, containerContext]);
344
406
  }
345
407
  function useRecyclingEffect(effect) {
346
- const { index, value } = useContext(ContextContainer);
408
+ const containerContext = useContextContainer();
347
409
  const prevValues = useRef({
348
410
  prevIndex: void 0,
349
411
  prevItem: void 0
350
412
  });
351
413
  useEffect(() => {
414
+ if (!containerContext) {
415
+ return;
416
+ }
417
+ const { index, value } = containerContext;
352
418
  let ret;
353
419
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
354
420
  ret = effect({
@@ -363,48 +429,73 @@ function useRecyclingEffect(effect) {
363
429
  prevItem: value
364
430
  };
365
431
  return ret;
366
- }, [index, value, effect]);
432
+ }, [effect, containerContext]);
367
433
  }
368
434
  function useRecyclingState(valueOrFun) {
369
- const { index, value, itemKey, triggerLayout } = useContext(ContextContainer);
370
- const refState = useRef({
371
- itemKey: null,
372
- value: null
435
+ var _a3, _b;
436
+ const containerContext = useContextContainer();
437
+ const computeValue = (ctx) => {
438
+ if (isFunction(valueOrFun)) {
439
+ const initializer = valueOrFun;
440
+ return ctx ? initializer({
441
+ index: ctx.index,
442
+ item: ctx.value,
443
+ prevIndex: void 0,
444
+ prevItem: void 0
445
+ }) : initializer();
446
+ }
447
+ return valueOrFun;
448
+ };
449
+ const [stateValue, setStateValue] = useState(() => {
450
+ return computeValue(containerContext);
373
451
  });
374
- const [_, setRenderNum] = useState(0);
375
- const state = refState.current;
376
- if (state.itemKey !== itemKey) {
377
- state.itemKey = itemKey;
378
- state.value = isFunction(valueOrFun) ? valueOrFun({
379
- index,
380
- item: value,
381
- prevIndex: void 0,
382
- prevItem: void 0
383
- }) : valueOrFun;
452
+ const prevItemKeyRef = useRef((_a3 = containerContext == null ? void 0 : containerContext.itemKey) != null ? _a3 : null);
453
+ const currentItemKey = (_b = containerContext == null ? void 0 : containerContext.itemKey) != null ? _b : null;
454
+ if (currentItemKey !== null && prevItemKeyRef.current !== currentItemKey) {
455
+ prevItemKeyRef.current = currentItemKey;
456
+ setStateValue(computeValue(containerContext));
384
457
  }
458
+ const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
385
459
  const setState = useCallback(
386
460
  (newState) => {
387
- state.value = isFunction(newState) ? newState(state.value) : newState;
388
- setRenderNum((v) => v + 1);
461
+ if (!triggerLayout) {
462
+ return;
463
+ }
464
+ setStateValue((prevValue) => {
465
+ return isFunction(newState) ? newState(prevValue) : newState;
466
+ });
389
467
  triggerLayout();
390
468
  },
391
- [triggerLayout, state]
469
+ [triggerLayout]
392
470
  );
393
- return [state.value, setState];
471
+ return [stateValue, setState];
394
472
  }
395
473
  function useIsLastItem() {
396
- const { itemKey } = useContext(ContextContainer);
397
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
474
+ const containerContext = useContextContainer();
475
+ const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
476
+ if (containerContext) {
477
+ const { itemKey } = containerContext;
478
+ if (!isNullOrUndefined(itemKey)) {
479
+ return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
480
+ }
481
+ }
482
+ return false;
483
+ });
398
484
  return isLast;
399
485
  }
400
486
  function useListScrollSize() {
401
487
  const [scrollSize] = useArr$(["scrollSize"]);
402
488
  return scrollSize;
403
489
  }
490
+ var noop = () => {
491
+ };
404
492
  function useSyncLayout() {
405
- {
406
- const { triggerLayout: syncLayout } = useContext(ContextContainer);
493
+ const containerContext = useContextContainer();
494
+ if (containerContext) {
495
+ const { triggerLayout: syncLayout } = containerContext;
407
496
  return syncLayout;
497
+ } else {
498
+ return noop;
408
499
  }
409
500
  }
410
501
 
@@ -450,10 +541,9 @@ function createResizeObserver(element, callback) {
450
541
  }
451
542
  callbacks.add(callback);
452
543
  return () => {
453
- const callbacks2 = callbackMap.get(element);
454
- if (callbacks2) {
455
- callbacks2.delete(callback);
456
- if (callbacks2.size === 0) {
544
+ if (callbacks) {
545
+ callbacks.delete(callback);
546
+ if (callbacks.size === 0) {
457
547
  callbackMap.delete(element);
458
548
  observer.unobserve(element);
459
549
  }
@@ -488,10 +578,10 @@ function useOnLayoutSync({
488
578
  return createResizeObserver(element, (entry) => {
489
579
  var _a4;
490
580
  const target = entry.target instanceof HTMLElement ? entry.target : void 0;
491
- const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
492
- if (rect2.width !== prevRect.width || rect2.height !== prevRect.height) {
493
- prevRect = rect2;
494
- emit(toLayout(rect2), false);
581
+ const rectObserved = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
582
+ if (rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height) {
583
+ prevRect = rectObserved;
584
+ emit(toLayout(rectObserved), false);
495
585
  }
496
586
  });
497
587
  }, deps || []);
@@ -516,7 +606,8 @@ var Container = typedMemo(function Container2({
516
606
  horizontal,
517
607
  getRenderedItem: getRenderedItem2,
518
608
  updateItemSize: updateItemSize2,
519
- ItemSeparatorComponent
609
+ ItemSeparatorComponent,
610
+ stickyHeaderConfig
520
611
  }) {
521
612
  const ctx = useStateContext();
522
613
  const { columnWrapperStyle, animatedScrollY } = ctx;
@@ -619,7 +710,7 @@ var Container = typedMemo(function Container2({
619
710
  },
620
711
  [itemKey, layoutRenderCount]
621
712
  );
622
- const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
713
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView;
623
714
  return /* @__PURE__ */ React3.createElement(
624
715
  PositionComponent,
625
716
  {
@@ -630,6 +721,7 @@ var Container = typedMemo(function Container2({
630
721
  key: recycleItems ? void 0 : itemKey,
631
722
  onLayout,
632
723
  refView: ref,
724
+ stickyHeaderConfig,
633
725
  stickyOffset: isSticky ? stickyOffset : void 0,
634
726
  style
635
727
  },
@@ -789,7 +881,8 @@ var Containers = typedMemo(function Containers2({
789
881
  ItemSeparatorComponent,
790
882
  waitForInitialLayout,
791
883
  updateItemSize: updateItemSize2,
792
- getRenderedItem: getRenderedItem2
884
+ getRenderedItem: getRenderedItem2,
885
+ stickyHeaderConfig
793
886
  }) {
794
887
  const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
795
888
  const containers = [];
@@ -804,6 +897,7 @@ var Containers = typedMemo(function Containers2({
804
897
  id: i,
805
898
  key: i,
806
899
  recycleItems,
900
+ stickyHeaderConfig,
807
901
  updateItemSize: updateItemSize2
808
902
  }
809
903
  )
@@ -812,7 +906,8 @@ var Containers = typedMemo(function Containers2({
812
906
  return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
813
907
  });
814
908
  function DevNumbers() {
815
- return IS_DEV && React3.memo(function DevNumbers2() {
909
+ return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
910
+ React3.memo(function DevNumbers2() {
816
911
  return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3.createElement(
817
912
  "div",
818
913
  {
@@ -860,7 +955,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
860
955
  }, ref) {
861
956
  const scrollRef = useRef(null);
862
957
  const contentRef = useRef(null);
863
- const momentumTimeout = useRef(null);
864
958
  useImperativeHandle(ref, () => {
865
959
  const api = {
866
960
  getBoundingClientRect: () => {
@@ -926,16 +1020,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
926
1020
  }
927
1021
  };
928
1022
  onScroll2(scrollEvent);
929
- if (onMomentumScrollEnd) {
930
- if (momentumTimeout.current != null) clearTimeout(momentumTimeout.current);
931
- momentumTimeout.current = setTimeout(() => {
932
- onMomentumScrollEnd({
933
- nativeEvent: {
934
- contentOffset: scrollEvent.nativeEvent.contentOffset
935
- }
936
- });
937
- }, 100);
938
- }
939
1023
  },
940
1024
  [onScroll2, onMomentumScrollEnd]
941
1025
  );
@@ -997,7 +1081,8 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
997
1081
  minWidth: horizontal ? "100%" : void 0,
998
1082
  ...StyleSheet.flatten(contentContainerStyle)
999
1083
  };
1000
- return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
1084
+ const { contentInset, scrollEventThrottle, ScrollComponent, ...webProps } = props;
1085
+ return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
1001
1086
  });
1002
1087
  function Padding() {
1003
1088
  const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
@@ -1038,7 +1123,7 @@ function ScrollAdjust() {
1038
1123
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1039
1124
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1040
1125
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1041
- const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
1126
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1042
1127
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1043
1128
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1044
1129
  if (scrollDelta !== 0) {
@@ -1046,26 +1131,23 @@ function ScrollAdjust() {
1046
1131
  const prevScroll = el.scrollTop;
1047
1132
  const nextScroll = prevScroll + scrollDelta;
1048
1133
  const totalSize = el.scrollHeight;
1049
- if (scrollDelta > 0 && !ctx.internalState.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1134
+ if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1050
1135
  const child = el.firstElementChild;
1051
1136
  const prevPaddingBottom = child.style.paddingBottom;
1052
1137
  const pad = (nextScroll + el.clientHeight - totalSize) * 2;
1053
1138
  child.style.paddingBottom = `${pad}px`;
1054
1139
  void el.offsetHeight;
1055
1140
  scrollView.scrollBy(0, scrollDelta);
1056
- setTimeout(() => {
1141
+ requestAnimationFrame(() => {
1057
1142
  child.style.paddingBottom = prevPaddingBottom;
1058
- }, 100);
1143
+ });
1059
1144
  } else {
1060
1145
  scrollView.scrollBy(0, scrollDelta);
1061
1146
  }
1062
- if (IS_DEV) {
1063
- console.log("ScrollAdjust (web scrollBy)", scrollDelta, "total offset:", scrollOffset);
1064
- }
1065
1147
  }
1066
1148
  lastScrollOffsetRef.current = scrollOffset;
1067
1149
  }
1068
- }, []);
1150
+ }, [ctx]);
1069
1151
  useValueListener$("scrollAdjust", callback);
1070
1152
  useValueListener$("scrollAdjustUserOffset", callback);
1071
1153
  return null;
@@ -1079,8 +1161,6 @@ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1079
1161
  useOnLayoutSync({ onLayoutChange, ref });
1080
1162
  return /* @__PURE__ */ React3.createElement("div", { ...rest, ref }, children);
1081
1163
  };
1082
-
1083
- // src/components/ListComponent.tsx
1084
1164
  var getComponent = (Component) => {
1085
1165
  if (React3.isValidElement(Component)) {
1086
1166
  return Component;
@@ -1090,6 +1170,8 @@ var getComponent = (Component) => {
1090
1170
  }
1091
1171
  return null;
1092
1172
  };
1173
+
1174
+ // src/components/ListComponent.tsx
1093
1175
  var ListComponent = typedMemo(function ListComponent2({
1094
1176
  canRender,
1095
1177
  style,
@@ -1110,26 +1192,20 @@ var ListComponent = typedMemo(function ListComponent2({
1110
1192
  getRenderedItem: getRenderedItem2,
1111
1193
  updateItemSize: updateItemSize2,
1112
1194
  refScrollView,
1113
- maintainVisibleContentPosition,
1114
1195
  renderScrollComponent,
1115
1196
  scrollAdjustHandler,
1116
1197
  onLayoutHeader,
1117
1198
  snapToIndices,
1199
+ stickyHeaderConfig,
1118
1200
  stickyHeaderIndices,
1119
1201
  ...rest
1120
1202
  }) {
1121
1203
  const ctx = useStateContext();
1204
+ const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1122
1205
  const ScrollComponent = renderScrollComponent ? useMemo(
1123
1206
  () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1124
1207
  [renderScrollComponent]
1125
1208
  ) : ListComponentScrollView;
1126
- React3.useEffect(() => {
1127
- if (canRender) {
1128
- setTimeout(() => {
1129
- scrollAdjustHandler.setMounted();
1130
- }, 0);
1131
- }
1132
- }, [canRender]);
1133
1209
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1134
1210
  return /* @__PURE__ */ React3.createElement(
1135
1211
  SnapOrScroll,
@@ -1143,7 +1219,7 @@ var ListComponent = typedMemo(function ListComponent2({
1143
1219
  ],
1144
1220
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1145
1221
  horizontal,
1146
- maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
1222
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
1147
1223
  onLayout,
1148
1224
  onScroll: onScroll2,
1149
1225
  ref: refScrollView,
@@ -1161,6 +1237,7 @@ var ListComponent = typedMemo(function ListComponent2({
1161
1237
  horizontal,
1162
1238
  ItemSeparatorComponent,
1163
1239
  recycleItems,
1240
+ stickyHeaderConfig,
1164
1241
  updateItemSize: updateItemSize2,
1165
1242
  waitForInitialLayout
1166
1243
  }
@@ -1193,10 +1270,11 @@ function getId(state, index) {
1193
1270
  }
1194
1271
 
1195
1272
  // src/core/calculateOffsetForIndex.ts
1196
- function calculateOffsetForIndex(ctx, state, index) {
1273
+ function calculateOffsetForIndex(ctx, index) {
1274
+ const state = ctx.state;
1197
1275
  let position = 0;
1198
1276
  if (index !== void 0) {
1199
- position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
1277
+ position = state.positions.get(getId(state, index)) || 0;
1200
1278
  const paddingTop = peek$(ctx, "stylePaddingTop");
1201
1279
  if (paddingTop) {
1202
1280
  position += paddingTop;
@@ -1210,7 +1288,8 @@ function calculateOffsetForIndex(ctx, state, index) {
1210
1288
  }
1211
1289
 
1212
1290
  // src/utils/setPaddingTop.ts
1213
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1291
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1292
+ const state = ctx.state;
1214
1293
  if (stylePaddingTop !== void 0) {
1215
1294
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1216
1295
  if (stylePaddingTop < prevStylePaddingTop) {
@@ -1229,7 +1308,8 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1229
1308
  }
1230
1309
 
1231
1310
  // src/utils/updateAlignItemsPaddingTop.ts
1232
- function updateAlignItemsPaddingTop(ctx, state) {
1311
+ function updateAlignItemsPaddingTop(ctx) {
1312
+ const state = ctx.state;
1233
1313
  const {
1234
1314
  scrollLength,
1235
1315
  props: { alignItemsAtEnd, data }
@@ -1240,12 +1320,13 @@ function updateAlignItemsPaddingTop(ctx, state) {
1240
1320
  const contentSize = getContentSize(ctx);
1241
1321
  alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1242
1322
  }
1243
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1323
+ setPaddingTop(ctx, { alignItemsPaddingTop });
1244
1324
  }
1245
1325
  }
1246
1326
 
1247
1327
  // src/core/addTotalSize.ts
1248
- function addTotalSize(ctx, state, key, add) {
1328
+ function addTotalSize(ctx, key, add) {
1329
+ const state = ctx.state;
1249
1330
  const { alignItemsAtEnd } = state.props;
1250
1331
  const prevTotalSize = state.totalSize;
1251
1332
  let totalSize = state.totalSize;
@@ -1264,31 +1345,34 @@ function addTotalSize(ctx, state, key, add) {
1264
1345
  state.totalSize = totalSize;
1265
1346
  set$(ctx, "totalSize", totalSize);
1266
1347
  if (alignItemsAtEnd) {
1267
- updateAlignItemsPaddingTop(ctx, state);
1348
+ updateAlignItemsPaddingTop(ctx);
1268
1349
  }
1269
1350
  }
1270
1351
  }
1271
1352
  }
1272
1353
 
1273
1354
  // src/core/setSize.ts
1274
- function setSize(ctx, state, itemKey, size) {
1355
+ function setSize(ctx, itemKey, size) {
1356
+ const state = ctx.state;
1275
1357
  const { sizes } = state;
1276
1358
  const previousSize = sizes.get(itemKey);
1277
1359
  const diff = previousSize !== void 0 ? size - previousSize : size;
1278
1360
  if (diff !== 0) {
1279
- addTotalSize(ctx, state, itemKey, diff);
1361
+ addTotalSize(ctx, itemKey, diff);
1280
1362
  }
1281
1363
  sizes.set(itemKey, size);
1282
1364
  }
1283
1365
 
1284
1366
  // src/utils/getItemSize.ts
1285
- function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1367
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1286
1368
  var _a3, _b;
1369
+ const state = ctx.state;
1287
1370
  const {
1288
1371
  sizesKnown,
1289
1372
  sizes,
1290
1373
  averageSizes,
1291
- props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1374
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
1375
+ scrollingTo
1292
1376
  } = state;
1293
1377
  const sizeKnown = sizesKnown.get(key);
1294
1378
  if (sizeKnown !== void 0) {
@@ -1296,7 +1380,6 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1296
1380
  }
1297
1381
  let size;
1298
1382
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1299
- const scrollingTo = peek$(ctx, "scrollingTo");
1300
1383
  if (preferCachedSize) {
1301
1384
  const cachedSize = sizes.get(key);
1302
1385
  if (cachedSize !== void 0) {
@@ -1304,7 +1387,7 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1304
1387
  }
1305
1388
  }
1306
1389
  if (getFixedItemSize) {
1307
- size = getFixedItemSize(index, data, itemType);
1390
+ size = getFixedItemSize(data, index, itemType);
1308
1391
  if (size !== void 0) {
1309
1392
  sizesKnown.set(key, size);
1310
1393
  }
@@ -1322,93 +1405,188 @@ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedS
1322
1405
  }
1323
1406
  }
1324
1407
  if (size === void 0) {
1325
- size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1408
+ size = getEstimatedItemSize ? getEstimatedItemSize(data, index, itemType) : estimatedItemSize;
1326
1409
  }
1327
- setSize(ctx, state, key, size);
1410
+ setSize(ctx, key, size);
1328
1411
  return size;
1329
1412
  }
1330
1413
 
1331
1414
  // src/core/calculateOffsetWithOffsetPosition.ts
1332
- function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1415
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1416
+ const state = ctx.state;
1333
1417
  const { index, viewOffset, viewPosition } = params;
1334
1418
  let offset = offsetParam;
1335
1419
  if (viewOffset) {
1336
1420
  offset -= viewOffset;
1337
1421
  }
1338
1422
  if (viewPosition !== void 0 && index !== void 0) {
1339
- offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1423
+ const itemSize = getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1424
+ const trailingInset = getContentInsetEnd(state);
1425
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1340
1426
  }
1341
1427
  return offset;
1342
1428
  }
1343
1429
 
1430
+ // src/core/clampScrollOffset.ts
1431
+ function clampScrollOffset(ctx, offset) {
1432
+ const state = ctx.state;
1433
+ const contentSize = getContentSize(ctx);
1434
+ let clampedOffset = offset;
1435
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android")) {
1436
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1437
+ clampedOffset = Math.min(offset, maxOffset);
1438
+ }
1439
+ clampedOffset = Math.max(0, clampedOffset);
1440
+ return clampedOffset;
1441
+ }
1442
+
1443
+ // src/utils/setInitialRenderState.ts
1444
+ function setInitialRenderState(ctx, {
1445
+ didLayout,
1446
+ didInitialScroll
1447
+ }) {
1448
+ const { state } = ctx;
1449
+ if (didLayout) {
1450
+ state.didContainersLayout = true;
1451
+ }
1452
+ if (didInitialScroll) {
1453
+ state.didFinishInitialScroll = true;
1454
+ }
1455
+ if (state.didContainersLayout && state.didFinishInitialScroll) {
1456
+ set$(ctx, "readyToRender", true);
1457
+ }
1458
+ }
1459
+
1344
1460
  // src/core/finishScrollTo.ts
1345
- function finishScrollTo(ctx, state) {
1461
+ function finishScrollTo(ctx) {
1346
1462
  var _a3, _b;
1347
- if (state) {
1463
+ const state = ctx.state;
1464
+ if (state == null ? void 0 : state.scrollingTo) {
1465
+ const scrollingTo = state.scrollingTo;
1348
1466
  state.scrollHistory.length = 0;
1349
1467
  state.initialScroll = void 0;
1350
1468
  state.initialAnchor = void 0;
1351
- set$(ctx, "scrollingTo", void 0);
1469
+ state.scrollingTo = void 0;
1352
1470
  if (state.pendingTotalSize !== void 0) {
1353
- addTotalSize(ctx, state, null, state.pendingTotalSize);
1471
+ addTotalSize(ctx, null, state.pendingTotalSize);
1354
1472
  }
1355
1473
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1356
1474
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1357
1475
  }
1476
+ {
1477
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1478
+ }
1479
+ setInitialRenderState(ctx, { didInitialScroll: true });
1480
+ }
1481
+ }
1482
+
1483
+ // src/core/doScrollTo.ts
1484
+ var SCROLL_END_IDLE_MS = 80;
1485
+ var SCROLL_END_MAX_MS = 1500;
1486
+ var SMOOTH_SCROLL_DURATION_MS = 320;
1487
+ function doScrollTo(ctx, params) {
1488
+ const state = ctx.state;
1489
+ const { animated, horizontal, offset } = params;
1490
+ const scroller = state.refScroller.current;
1491
+ const node = typeof (scroller == null ? void 0 : scroller.getScrollableNode) === "function" ? scroller.getScrollableNode() : scroller;
1492
+ if (node) {
1493
+ const left = horizontal ? offset : 0;
1494
+ const top = horizontal ? 0 : offset;
1495
+ node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1496
+ if (animated) {
1497
+ listenForScrollEnd(ctx, node);
1498
+ } else {
1499
+ state.scroll = offset;
1500
+ setTimeout(() => {
1501
+ finishScrollTo(ctx);
1502
+ }, 100);
1503
+ }
1358
1504
  }
1359
1505
  }
1506
+ function listenForScrollEnd(ctx, node) {
1507
+ const supportsScrollEnd = "onscrollend" in node;
1508
+ let idleTimeout;
1509
+ let maxTimeout;
1510
+ let settled = false;
1511
+ const targetToken = ctx.state.scrollingTo;
1512
+ const finish = () => {
1513
+ if (settled) return;
1514
+ settled = true;
1515
+ cleanup();
1516
+ if (targetToken === ctx.state.scrollingTo) {
1517
+ finishScrollTo(ctx);
1518
+ }
1519
+ };
1520
+ const onScroll2 = () => {
1521
+ if (idleTimeout) {
1522
+ clearTimeout(idleTimeout);
1523
+ }
1524
+ idleTimeout = setTimeout(finish, SCROLL_END_IDLE_MS);
1525
+ };
1526
+ const cleanup = () => {
1527
+ if (supportsScrollEnd) {
1528
+ node.removeEventListener("scrollend", finish);
1529
+ } else {
1530
+ node.removeEventListener("scroll", onScroll2);
1531
+ }
1532
+ if (idleTimeout) {
1533
+ clearTimeout(idleTimeout);
1534
+ }
1535
+ if (maxTimeout) {
1536
+ clearTimeout(maxTimeout);
1537
+ }
1538
+ };
1539
+ if (supportsScrollEnd) {
1540
+ node.addEventListener("scrollend", finish, { once: true });
1541
+ } else {
1542
+ node.addEventListener("scroll", onScroll2);
1543
+ idleTimeout = setTimeout(finish, SMOOTH_SCROLL_DURATION_MS);
1544
+ maxTimeout = setTimeout(finish, SCROLL_END_MAX_MS);
1545
+ }
1546
+ return cleanup;
1547
+ }
1360
1548
 
1361
1549
  // src/core/scrollTo.ts
1362
- function scrollTo(ctx, state, params) {
1363
- var _a3;
1364
- const { noScrollingTo, ...scrollTarget } = params;
1550
+ function scrollTo(ctx, params) {
1551
+ const state = ctx.state;
1552
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1365
1553
  const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1366
1554
  const {
1367
- refScroller,
1368
1555
  props: { horizontal }
1369
1556
  } = state;
1370
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1371
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1372
- const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1373
- offset = Math.min(offset, maxOffset);
1557
+ if (state.animFrameCheckFinishedScroll) {
1558
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1374
1559
  }
1560
+ if (state.timeoutCheckFinishedScrollFallback) {
1561
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1562
+ }
1563
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1564
+ offset = clampScrollOffset(ctx, offset);
1375
1565
  state.scrollHistory.length = 0;
1376
1566
  if (!noScrollingTo) {
1377
- set$(ctx, "scrollingTo", scrollTarget);
1567
+ state.scrollingTo = scrollTarget;
1378
1568
  }
1379
1569
  state.scrollPending = offset;
1380
- if (!isInitialScroll || Platform.OS === "android") {
1381
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1382
- animated: !!animated,
1383
- x: horizontal ? offset : 0,
1384
- y: horizontal ? 0 : offset
1385
- });
1386
- }
1387
- if (!animated) {
1570
+ if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1571
+ doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1572
+ } else {
1388
1573
  state.scroll = offset;
1389
- {
1390
- const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1391
- if (value && peek$(ctx, "scrollingTo")) {
1392
- finishScrollTo(ctx, state);
1393
- unlisten();
1394
- }
1395
- });
1396
- }
1397
- if (isInitialScroll) {
1398
- setTimeout(() => {
1399
- state.initialScroll = void 0;
1400
- }, 500);
1401
- }
1402
1574
  }
1403
1575
  }
1404
1576
 
1405
1577
  // src/utils/checkThreshold.ts
1406
1578
  var HYSTERESIS_MULTIPLIER = 1.3;
1407
- var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1579
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot, allowReentryOnChange) => {
1408
1580
  const absDistance = Math.abs(distance);
1409
1581
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
1582
+ if (wasReached === null) {
1583
+ if (!within && distance >= 0) {
1584
+ return false;
1585
+ }
1586
+ return null;
1587
+ }
1410
1588
  const updateSnapshot = () => {
1411
- setSnapshot == null ? void 0 : setSnapshot({
1589
+ setSnapshot({
1412
1590
  atThreshold,
1413
1591
  contentSize: context.contentSize,
1414
1592
  dataLength: context.dataLength,
@@ -1419,19 +1597,21 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1419
1597
  if (!within) {
1420
1598
  return false;
1421
1599
  }
1422
- onReached == null ? void 0 : onReached(distance);
1600
+ onReached(distance);
1423
1601
  updateSnapshot();
1424
1602
  return true;
1425
1603
  }
1426
1604
  const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1427
1605
  if (reset) {
1428
- setSnapshot == null ? void 0 : setSnapshot(void 0);
1606
+ setSnapshot(void 0);
1429
1607
  return false;
1430
1608
  }
1431
1609
  if (within) {
1432
1610
  const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
1433
1611
  if (changed) {
1434
- onReached == null ? void 0 : onReached(distance);
1612
+ if (allowReentryOnChange) {
1613
+ onReached(distance);
1614
+ }
1435
1615
  updateSnapshot();
1436
1616
  }
1437
1617
  }
@@ -1439,8 +1619,9 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
1439
1619
  };
1440
1620
 
1441
1621
  // src/utils/checkAtBottom.ts
1442
- function checkAtBottom(ctx, state) {
1622
+ function checkAtBottom(ctx) {
1443
1623
  var _a3;
1624
+ const state = ctx.state;
1444
1625
  if (!state) {
1445
1626
  return;
1446
1627
  }
@@ -1473,7 +1654,8 @@ function checkAtBottom(ctx, state) {
1473
1654
  },
1474
1655
  (snapshot) => {
1475
1656
  state.endReachedSnapshot = snapshot;
1476
- }
1657
+ },
1658
+ true
1477
1659
  );
1478
1660
  }
1479
1661
  }
@@ -1508,20 +1690,21 @@ function checkAtTop(state) {
1508
1690
  },
1509
1691
  (snapshot) => {
1510
1692
  state.startReachedSnapshot = snapshot;
1511
- }
1693
+ },
1694
+ false
1512
1695
  );
1513
1696
  }
1514
1697
 
1515
1698
  // src/core/updateScroll.ts
1516
- function updateScroll(ctx, state, newScroll, forceUpdate) {
1517
- var _a3;
1518
- const scrollingTo = peek$(ctx, "scrollingTo");
1699
+ function updateScroll(ctx, newScroll, forceUpdate) {
1700
+ const state = ctx.state;
1701
+ const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1702
+ const prevScroll = state.scroll;
1519
1703
  state.hasScrolled = true;
1520
1704
  state.lastBatchingAction = Date.now();
1521
1705
  const currentTime = Date.now();
1522
- const adjust = state.scrollAdjustHandler.getAdjust();
1523
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1524
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1706
+ const adjust = scrollAdjustHandler.getAdjust();
1707
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1525
1708
  if (adjustChanged) {
1526
1709
  state.scrollHistory.length = 0;
1527
1710
  }
@@ -1534,7 +1717,7 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1534
1717
  if (state.scrollHistory.length > 5) {
1535
1718
  state.scrollHistory.shift();
1536
1719
  }
1537
- state.scrollPrev = state.scroll;
1720
+ state.scrollPrev = prevScroll;
1538
1721
  state.scrollPrevTime = state.scrollTime;
1539
1722
  state.scroll = newScroll;
1540
1723
  state.scrollTime = currentTime;
@@ -1546,17 +1729,33 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1546
1729
  return;
1547
1730
  }
1548
1731
  }
1549
- if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1732
+ const scrollDelta = Math.abs(newScroll - prevScroll);
1733
+ const scrollLength = state.scrollLength;
1734
+ const lastCalculated = state.scrollLastCalculate;
1735
+ const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1736
+ if (shouldUpdate) {
1737
+ state.scrollLastCalculate = state.scroll;
1550
1738
  state.ignoreScrollFromMVCPIgnored = false;
1551
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1552
- checkAtBottom(ctx, state);
1553
- checkAtTop(state);
1739
+ state.lastScrollDelta = scrollDelta;
1740
+ const runCalculateItems = () => {
1741
+ var _a3;
1742
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1743
+ checkAtBottom(ctx);
1744
+ checkAtTop(state);
1745
+ };
1746
+ if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
1747
+ flushSync(runCalculateItems);
1748
+ } else {
1749
+ runCalculateItems();
1750
+ }
1554
1751
  state.dataChangeNeedsScrollUpdate = false;
1752
+ state.lastScrollDelta = 0;
1555
1753
  }
1556
1754
  }
1557
1755
 
1558
1756
  // src/utils/requestAdjust.ts
1559
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1757
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1758
+ const state = ctx.state;
1560
1759
  if (Math.abs(positionDiff) > 0.1) {
1561
1760
  const doit = () => {
1562
1761
  {
@@ -1568,8 +1767,8 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1568
1767
  };
1569
1768
  state.scroll += positionDiff;
1570
1769
  state.scrollForNextCalculateItemsInView = void 0;
1571
- const didLayout = peek$(ctx, "containersDidLayout");
1572
- if (didLayout) {
1770
+ const readyToRender = peek$(ctx, "readyToRender");
1771
+ if (readyToRender) {
1573
1772
  doit();
1574
1773
  } else {
1575
1774
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -1578,73 +1777,25 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1578
1777
  }
1579
1778
  }
1580
1779
 
1581
- // src/core/ensureInitialAnchor.ts
1582
- var INITIAL_ANCHOR_TOLERANCE = 0.5;
1583
- var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1584
- var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1585
- function ensureInitialAnchor(ctx, state) {
1586
- var _a3, _b, _c, _d, _e;
1587
- const anchor = state.initialAnchor;
1588
- const item = state.props.data[anchor.index];
1589
- const containersDidLayout = peek$(ctx, "containersDidLayout");
1590
- if (!containersDidLayout) {
1591
- return;
1592
- }
1593
- const id = getId(state, anchor.index);
1594
- if (state.positions.get(id) === void 0) {
1595
- return;
1596
- }
1597
- const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1598
- if (size === void 0) {
1599
- return;
1600
- }
1601
- const availableSpace = Math.max(0, state.scrollLength - size);
1602
- const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1603
- const contentSize = getContentSize(ctx);
1604
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1605
- const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1606
- const delta = clampedDesiredOffset - state.scroll;
1607
- if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1608
- const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1609
- if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1610
- state.initialAnchor = void 0;
1611
- } else {
1612
- anchor.settledTicks = settledTicks;
1613
- }
1614
- return;
1615
- }
1616
- if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1617
- state.initialAnchor = void 0;
1618
- return;
1619
- }
1620
- const lastDelta = anchor.lastDelta;
1621
- if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1622
- state.initialAnchor = void 0;
1623
- return;
1624
- }
1625
- Object.assign(anchor, {
1626
- attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1627
- lastDelta: delta,
1628
- settledTicks: 0
1629
- });
1630
- requestAdjust(ctx, state, delta);
1631
- }
1632
-
1633
1780
  // src/core/mvcp.ts
1634
- function prepareMVCP(ctx, state, dataChanged) {
1781
+ function prepareMVCP(ctx, dataChanged) {
1782
+ const state = ctx.state;
1635
1783
  const { idsInView, positions, props } = state;
1636
- const { maintainVisibleContentPosition } = props;
1637
- const scrollingTo = peek$(ctx, "scrollingTo");
1784
+ const {
1785
+ maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll, shouldRestorePosition }
1786
+ } = props;
1787
+ const scrollingTo = state.scrollingTo;
1638
1788
  let prevPosition;
1639
1789
  let targetId;
1640
1790
  const idsInViewWithPositions = [];
1641
1791
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1642
- const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1792
+ const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1793
+ const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1643
1794
  const indexByKey = state.indexByKey;
1644
1795
  if (shouldMVCP) {
1645
1796
  if (scrollTarget !== void 0) {
1646
1797
  targetId = getId(state, scrollTarget);
1647
- } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1798
+ } else if (idsInView.length > 0 && state.didContainersLayout) {
1648
1799
  if (dataChanged) {
1649
1800
  for (let i = 0; i < idsInView.length; i++) {
1650
1801
  const id = idsInView[i];
@@ -1661,10 +1812,18 @@ function prepareMVCP(ctx, state, dataChanged) {
1661
1812
  prevPosition = positions.get(targetId);
1662
1813
  }
1663
1814
  return () => {
1664
- let positionDiff;
1665
- if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1815
+ let positionDiff = 0;
1816
+ if (dataChanged && targetId === void 0 && mvcpData) {
1817
+ const data = state.props.data;
1666
1818
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1667
1819
  const { id, position } = idsInViewWithPositions[i];
1820
+ const index = indexByKey.get(id);
1821
+ if (index !== void 0 && shouldRestorePosition) {
1822
+ const item = data[index];
1823
+ if (item === void 0 || !shouldRestorePosition(item, index, data)) {
1824
+ continue;
1825
+ }
1826
+ }
1668
1827
  const newPosition = positions.get(id);
1669
1828
  if (newPosition !== void 0) {
1670
1829
  positionDiff = newPosition - position;
@@ -1687,16 +1846,28 @@ function prepareMVCP(ctx, state, dataChanged) {
1687
1846
  positionDiff = diff;
1688
1847
  }
1689
1848
  }
1690
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1691
- requestAdjust(ctx, state, positionDiff);
1849
+ if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1850
+ const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1851
+ const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1852
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1853
+ const diff = newSize - prevSize;
1854
+ if (diff !== 0) {
1855
+ positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1856
+ scrollingTo.itemSize = newSize;
1857
+ }
1858
+ }
1859
+ }
1860
+ if (Math.abs(positionDiff) > 0.1) {
1861
+ requestAdjust(ctx, positionDiff);
1692
1862
  }
1693
1863
  };
1694
1864
  }
1695
1865
  }
1696
1866
 
1697
1867
  // src/core/prepareColumnStartState.ts
1698
- function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1868
+ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1699
1869
  var _a3;
1870
+ const state = ctx.state;
1700
1871
  const numColumns = peek$(ctx, "numColumns");
1701
1872
  let rowStartIndex = startIndex;
1702
1873
  const columnAtStart = state.columns.get(state.idCache[startIndex]);
@@ -1711,7 +1882,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1711
1882
  const prevId = state.idCache[prevIndex];
1712
1883
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1713
1884
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1714
- const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1885
+ const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1715
1886
  currentRowTop = prevPosition + prevRowHeight;
1716
1887
  }
1717
1888
  return {
@@ -1734,7 +1905,8 @@ function findRowStartIndex(state, numColumns, index) {
1734
1905
  }
1735
1906
  return rowStart;
1736
1907
  }
1737
- function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1908
+ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
1909
+ const state = ctx.state;
1738
1910
  if (endIndex < startIndex) {
1739
1911
  return 0;
1740
1912
  }
@@ -1748,7 +1920,7 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1748
1920
  continue;
1749
1921
  }
1750
1922
  const id = state.idCache[i];
1751
- const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1923
+ const size = getItemSize(ctx, id, i, data[i], useAverageSize);
1752
1924
  if (size > maxSize) {
1753
1925
  maxSize = size;
1754
1926
  }
@@ -1757,22 +1929,23 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1757
1929
  }
1758
1930
 
1759
1931
  // src/core/updateTotalSize.ts
1760
- function updateTotalSize(ctx, state) {
1932
+ function updateTotalSize(ctx) {
1933
+ const state = ctx.state;
1761
1934
  const {
1762
1935
  positions,
1763
1936
  props: { data }
1764
1937
  } = state;
1765
1938
  if (data.length === 0) {
1766
- addTotalSize(ctx, state, null, 0);
1939
+ addTotalSize(ctx, null, 0);
1767
1940
  } else {
1768
1941
  const lastId = getId(state, data.length - 1);
1769
1942
  if (lastId !== void 0) {
1770
1943
  const lastPosition = positions.get(lastId);
1771
1944
  if (lastPosition !== void 0) {
1772
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1945
+ const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
1773
1946
  if (lastSize !== void 0) {
1774
1947
  const totalSize = lastPosition + lastSize;
1775
- addTotalSize(ctx, state, null, totalSize);
1948
+ addTotalSize(ctx, null, totalSize);
1776
1949
  }
1777
1950
  }
1778
1951
  }
@@ -1782,43 +1955,45 @@ function updateTotalSize(ctx, state) {
1782
1955
  // src/utils/getScrollVelocity.ts
1783
1956
  var getScrollVelocity = (state) => {
1784
1957
  const { scrollHistory } = state;
1785
- let velocity = 0;
1786
- if (scrollHistory.length >= 1) {
1787
- const newest = scrollHistory[scrollHistory.length - 1];
1788
- let oldest;
1789
- let start = 0;
1790
- const now = Date.now();
1791
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1792
- const entry = scrollHistory[i];
1793
- const nextEntry = scrollHistory[i + 1];
1794
- if (i > 0) {
1795
- const prevEntry = scrollHistory[i - 1];
1796
- const prevDirection = entry.scroll - prevEntry.scroll;
1797
- const currentDirection = nextEntry.scroll - entry.scroll;
1798
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1799
- start = i;
1800
- break;
1801
- }
1802
- }
1958
+ const newestIndex = scrollHistory.length - 1;
1959
+ if (newestIndex < 1) {
1960
+ return 0;
1961
+ }
1962
+ const newest = scrollHistory[newestIndex];
1963
+ const now = Date.now();
1964
+ let direction = 0;
1965
+ for (let i = newestIndex; i > 0; i--) {
1966
+ const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
1967
+ if (delta !== 0) {
1968
+ direction = Math.sign(delta);
1969
+ break;
1803
1970
  }
1804
- for (let i = start; i < scrollHistory.length - 1; i++) {
1805
- const entry = scrollHistory[i];
1806
- if (now - entry.time <= 1e3) {
1807
- oldest = entry;
1808
- break;
1809
- }
1971
+ }
1972
+ if (direction === 0) {
1973
+ return 0;
1974
+ }
1975
+ let oldest = newest;
1976
+ for (let i = newestIndex - 1; i >= 0; i--) {
1977
+ const current = scrollHistory[i];
1978
+ const next = scrollHistory[i + 1];
1979
+ const delta = next.scroll - current.scroll;
1980
+ const deltaSign = Math.sign(delta);
1981
+ if (deltaSign !== 0 && deltaSign !== direction) {
1982
+ break;
1810
1983
  }
1811
- if (oldest && oldest !== newest) {
1812
- const scrollDiff = newest.scroll - oldest.scroll;
1813
- const timeDiff = newest.time - oldest.time;
1814
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1984
+ if (now - current.time > 1e3) {
1985
+ break;
1815
1986
  }
1987
+ oldest = current;
1816
1988
  }
1817
- return velocity;
1989
+ const scrollDiff = newest.scroll - oldest.scroll;
1990
+ const timeDiff = newest.time - oldest.time;
1991
+ return timeDiff > 0 ? scrollDiff / timeDiff : 0;
1818
1992
  };
1819
1993
 
1820
1994
  // src/utils/updateSnapToOffsets.ts
1821
- function updateSnapToOffsets(ctx, state) {
1995
+ function updateSnapToOffsets(ctx) {
1996
+ const state = ctx.state;
1822
1997
  const {
1823
1998
  positions,
1824
1999
  props: { snapToIndices }
@@ -1833,30 +2008,32 @@ function updateSnapToOffsets(ctx, state) {
1833
2008
  }
1834
2009
 
1835
2010
  // src/core/updateItemPositions.ts
1836
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
2011
+ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1837
2012
  doMVCP: false,
1838
2013
  forceFullUpdate: false,
1839
2014
  scrollBottomBuffered: -1,
1840
2015
  startIndex: 0
1841
2016
  }) {
1842
2017
  var _a3, _b, _c, _d, _e;
2018
+ const state = ctx.state;
1843
2019
  const {
1844
2020
  columns,
1845
2021
  indexByKey,
1846
2022
  positions,
1847
2023
  idCache,
1848
2024
  sizesKnown,
1849
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
2025
+ props: { data, getEstimatedItemSize, snapToIndices },
2026
+ scrollingTo
1850
2027
  } = state;
1851
- const data = state.props.data;
1852
2028
  const dataLength = data.length;
1853
2029
  const numColumns = peek$(ctx, "numColumns");
1854
- const scrollingTo = peek$(ctx, "scrollingTo");
1855
2030
  const hasColumns = numColumns > 1;
1856
2031
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1857
- const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
2032
+ const lastScrollDelta = state.lastScrollDelta;
2033
+ const velocity = getScrollVelocity(state);
2034
+ const shouldOptimize = !forceFullUpdate && !dataChanged && (Math.abs(velocity) > 0 || state.scrollLength > 0 && lastScrollDelta > state.scrollLength);
1858
2035
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1859
- const useAverageSize = enableAverages && !getEstimatedItemSize;
2036
+ const useAverageSize = !getEstimatedItemSize;
1860
2037
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1861
2038
  let currentRowTop = 0;
1862
2039
  let column = 1;
@@ -1865,7 +2042,6 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1865
2042
  if (hasColumns) {
1866
2043
  const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1867
2044
  ctx,
1868
- state,
1869
2045
  startIndex,
1870
2046
  useAverageSize
1871
2047
  );
@@ -1875,7 +2051,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1875
2051
  const prevIndex = startIndex - 1;
1876
2052
  const prevId = getId(state, prevIndex);
1877
2053
  const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1878
- const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
2054
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1879
2055
  currentRowTop = prevPosition + prevSize;
1880
2056
  }
1881
2057
  }
@@ -1892,7 +2068,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1892
2068
  breakAt = i + itemsPerRow + 10;
1893
2069
  }
1894
2070
  const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1895
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
2071
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
1896
2072
  if (IS_DEV && needsIndexByKey) {
1897
2073
  if (indexByKeyForChecking.has(id)) {
1898
2074
  console.error(
@@ -1901,7 +2077,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1901
2077
  }
1902
2078
  indexByKeyForChecking.set(id, i);
1903
2079
  }
1904
- positions.set(id, currentRowTop);
2080
+ if (currentRowTop !== positions.get(id)) {
2081
+ positions.set(id, currentRowTop);
2082
+ notifyPosition$(ctx, id, currentRowTop);
2083
+ }
1905
2084
  if (needsIndexByKey) {
1906
2085
  indexByKey.set(id, i);
1907
2086
  }
@@ -1921,10 +2100,10 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1921
2100
  }
1922
2101
  }
1923
2102
  if (!didBreakEarly) {
1924
- updateTotalSize(ctx, state);
2103
+ updateTotalSize(ctx);
1925
2104
  }
1926
2105
  if (snapToIndices) {
1927
- updateSnapToOffsets(ctx, state);
2106
+ updateSnapToOffsets(ctx);
1928
2107
  }
1929
2108
  }
1930
2109
 
@@ -2002,7 +2181,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
2002
2181
  if (previousViewableItems) {
2003
2182
  for (const viewToken of previousViewableItems) {
2004
2183
  const containerId = findContainerId(ctx, viewToken.key);
2005
- if (!isViewable(
2184
+ if (!checkIsViewable(
2006
2185
  state,
2007
2186
  ctx,
2008
2187
  viewabilityConfig,
@@ -2023,7 +2202,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
2023
2202
  if (item) {
2024
2203
  const key = getId(state, i);
2025
2204
  const containerId = findContainerId(ctx, key);
2026
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2205
+ if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
2027
2206
  const viewToken = {
2028
2207
  containerId,
2029
2208
  index: i,
@@ -2083,11 +2262,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2083
2262
  const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
2084
2263
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
2085
2264
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
2086
- const isViewable2 = percent >= viewablePercentThreshold;
2265
+ const isViewable = percent >= viewablePercentThreshold;
2087
2266
  const value = {
2088
2267
  containerId,
2089
2268
  index,
2090
- isViewable: isViewable2,
2269
+ isViewable,
2091
2270
  item,
2092
2271
  key,
2093
2272
  percentOfScroller,
@@ -2106,8 +2285,11 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
2106
2285
  }
2107
2286
  return value;
2108
2287
  }
2109
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2110
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2288
+ function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2289
+ let value = ctx.mapViewabilityAmountValues.get(containerId);
2290
+ if (!value || value.key !== key) {
2291
+ value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
2292
+ }
2111
2293
  return value.isViewable;
2112
2294
  }
2113
2295
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
@@ -2135,8 +2317,9 @@ function checkAllSizesKnown(state) {
2135
2317
  }
2136
2318
 
2137
2319
  // src/utils/findAvailableContainers.ts
2138
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2320
+ function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2139
2321
  const numContainers = peek$(ctx, "numContainers");
2322
+ const state = ctx.state;
2140
2323
  const { stickyContainerPool, containerItemTypes } = state;
2141
2324
  const result = [];
2142
2325
  const availableContainers = [];
@@ -2256,21 +2439,26 @@ function comparatorByDistance(a, b) {
2256
2439
  }
2257
2440
 
2258
2441
  // src/core/scrollToIndex.ts
2259
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2260
- if (index >= state.props.data.length) {
2261
- index = state.props.data.length - 1;
2442
+ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPosition }) {
2443
+ const state = ctx.state;
2444
+ const { data } = state.props;
2445
+ if (index >= data.length) {
2446
+ index = data.length - 1;
2262
2447
  } else if (index < 0) {
2263
2448
  index = 0;
2264
2449
  }
2265
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2266
- const isLast = index === state.props.data.length - 1;
2450
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2451
+ const isLast = index === data.length - 1;
2267
2452
  if (isLast && viewPosition === void 0) {
2268
2453
  viewPosition = 1;
2269
2454
  }
2270
2455
  state.scrollForNextCalculateItemsInView = void 0;
2271
- scrollTo(ctx, state, {
2456
+ const targetId = getId(state, index);
2457
+ const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
2458
+ scrollTo(ctx, {
2272
2459
  animated,
2273
2460
  index,
2461
+ itemSize,
2274
2462
  offset: firstIndexOffset,
2275
2463
  viewOffset,
2276
2464
  viewPosition: viewPosition != null ? viewPosition : 0
@@ -2278,23 +2466,28 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
2278
2466
  }
2279
2467
 
2280
2468
  // src/utils/setDidLayout.ts
2281
- function setDidLayout(ctx, state) {
2469
+ function setDidLayout(ctx) {
2470
+ const state = ctx.state;
2282
2471
  const {
2283
2472
  loadStartTime,
2284
2473
  initialScroll,
2285
2474
  props: { onLoad }
2286
2475
  } = state;
2287
2476
  state.queuedInitialLayout = true;
2288
- checkAtBottom(ctx, state);
2477
+ checkAtBottom(ctx);
2289
2478
  const setIt = () => {
2290
- set$(ctx, "containersDidLayout", true);
2479
+ setInitialRenderState(ctx, { didLayout: true });
2291
2480
  if (onLoad) {
2292
2481
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2293
2482
  }
2294
2483
  };
2295
- {
2296
- setIt();
2484
+ if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
2485
+ const target = initialScroll;
2486
+ const runScroll = () => scrollToIndex(ctx, { ...target, animated: false });
2487
+ runScroll();
2488
+ requestAnimationFrame(runScroll);
2297
2489
  }
2490
+ setIt();
2298
2491
  }
2299
2492
 
2300
2493
  // src/core/calculateItemsInView.ts
@@ -2312,15 +2505,17 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
2312
2505
  }
2313
2506
  return -1;
2314
2507
  }
2315
- function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
2508
+ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2509
+ const state = ctx.state;
2316
2510
  return new Set(
2317
2511
  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))
2318
2512
  );
2319
2513
  }
2320
- function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2514
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2321
2515
  var _a3;
2322
- const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2323
- state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
2516
+ const state = ctx.state;
2517
+ const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
2518
+ set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
2324
2519
  for (let offset = 0; offset <= 1; offset++) {
2325
2520
  const idx = currentStickyIdx - offset;
2326
2521
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -2331,8 +2526,9 @@ function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, cu
2331
2526
  }
2332
2527
  }
2333
2528
  }
2334
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2529
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2335
2530
  var _a3, _b, _c;
2531
+ const state = ctx.state;
2336
2532
  for (const containerIndex of state.stickyContainerPool) {
2337
2533
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2338
2534
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
@@ -2356,7 +2552,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2356
2552
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2357
2553
  if (currentId) {
2358
2554
  const currentPos = state.positions.get(currentId);
2359
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2555
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2360
2556
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2361
2557
  }
2362
2558
  }
@@ -2365,7 +2561,8 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2365
2561
  }
2366
2562
  }
2367
2563
  }
2368
- function calculateItemsInView(ctx, state, params = {}) {
2564
+ function calculateItemsInView(ctx, params = {}) {
2565
+ const state = ctx.state;
2369
2566
  unstable_batchedUpdates(() => {
2370
2567
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2371
2568
  const {
@@ -2389,9 +2586,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2389
2586
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2390
2587
  const prevNumContainers = peek$(ctx, "numContainers");
2391
2588
  if (!data || scrollLength === 0 || !prevNumContainers) {
2392
- if (state.initialAnchor) {
2393
- ensureInitialAnchor(ctx, state);
2394
- }
2395
2589
  return;
2396
2590
  }
2397
2591
  const totalSize = getContentSize(ctx);
@@ -2405,15 +2599,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2405
2599
  if (!queuedInitialLayout && initialScroll) {
2406
2600
  const updatedOffset = calculateOffsetWithOffsetPosition(
2407
2601
  ctx,
2408
- state,
2409
- calculateOffsetForIndex(ctx, state, initialScroll.index),
2602
+ calculateOffsetForIndex(ctx, initialScroll.index),
2410
2603
  initialScroll
2411
2604
  );
2412
2605
  scrollState = updatedOffset;
2413
2606
  }
2414
2607
  const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2415
2608
  const scrollAdjustPad = scrollAdjustPending - topPad;
2416
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
2609
+ let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
2417
2610
  if (scroll + scrollLength > totalSize) {
2418
2611
  scroll = Math.max(0, totalSize - scrollLength);
2419
2612
  }
@@ -2421,11 +2614,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2421
2614
  set$(ctx, "debugRawScroll", scrollState);
2422
2615
  set$(ctx, "debugComputedScroll", scroll);
2423
2616
  }
2424
- const previousStickyIndex = state.activeStickyIndex;
2617
+ const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2425
2618
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2426
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2427
- state.activeStickyIndex = nextActiveStickyIndex;
2428
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2619
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2620
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2621
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2622
+ }
2429
2623
  let scrollBufferTop = scrollBuffer;
2430
2624
  let scrollBufferBottom = scrollBuffer;
2431
2625
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2438,23 +2632,22 @@ function calculateItemsInView(ctx, state, params = {}) {
2438
2632
  const scrollTopBuffered = scroll - scrollBufferTop;
2439
2633
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2440
2634
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2441
- if (!dataChanged && scrollForNextCalculateItemsInView) {
2635
+ if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
2442
2636
  const { top, bottom } = scrollForNextCalculateItemsInView;
2443
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2444
- if (state.initialAnchor) {
2445
- ensureInitialAnchor(ctx, state);
2446
- }
2637
+ if (top === null && bottom === null) {
2638
+ state.scrollForNextCalculateItemsInView = void 0;
2639
+ } else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2447
2640
  return;
2448
2641
  }
2449
2642
  }
2450
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2643
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
2451
2644
  if (dataChanged) {
2452
2645
  indexByKey.clear();
2453
2646
  idCache.length = 0;
2454
2647
  positions.clear();
2455
2648
  }
2456
- const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2457
- updateItemPositions(ctx, state, dataChanged, {
2649
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2650
+ updateItemPositions(ctx, dataChanged, {
2458
2651
  doMVCP,
2459
2652
  forceFullUpdate: !!forceFullItemPositions,
2460
2653
  scrollBottomBuffered,
@@ -2473,9 +2666,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2473
2666
  for (let i = loopStart; i >= 0; i--) {
2474
2667
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2475
2668
  const top = positions.get(id);
2476
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2669
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2477
2670
  const bottom = top + size;
2478
- if (bottom > scroll - scrollBuffer) {
2671
+ if (bottom > scroll - scrollBufferTop) {
2479
2672
  loopStart = i;
2480
2673
  } else {
2481
2674
  break;
@@ -2500,7 +2693,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2500
2693
  const dataLength = data.length;
2501
2694
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2502
2695
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2503
- const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2696
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
2504
2697
  const top = positions.get(id);
2505
2698
  if (!foundEnd) {
2506
2699
  if (startNoBuffer === null && top + size > scroll) {
@@ -2512,7 +2705,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2512
2705
  if (startBuffered === null && top + size > scrollTopBuffered) {
2513
2706
  startBuffered = i;
2514
2707
  startBufferedId = id;
2515
- nextTop = top;
2708
+ if (scrollTopBuffered < 0) {
2709
+ nextTop = null;
2710
+ } else {
2711
+ nextTop = top;
2712
+ }
2516
2713
  }
2517
2714
  if (startNoBuffer !== null) {
2518
2715
  if (top <= scrollBottom) {
@@ -2520,7 +2717,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2520
2717
  }
2521
2718
  if (top <= scrollBottomBuffered) {
2522
2719
  endBuffered = i;
2523
- nextBottom = top + size;
2720
+ if (scrollBottomBuffered > totalSize) {
2721
+ nextBottom = null;
2722
+ } else {
2723
+ nextBottom = top + size;
2724
+ }
2524
2725
  } else {
2525
2726
  foundEnd = true;
2526
2727
  }
@@ -2542,12 +2743,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2542
2743
  startNoBuffer
2543
2744
  });
2544
2745
  if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
2545
- state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
2746
+ state.scrollForNextCalculateItemsInView = isNullOrUndefined(nextTop) && isNullOrUndefined(nextBottom) ? void 0 : {
2546
2747
  bottom: nextBottom,
2547
2748
  top: nextTop
2548
- } : void 0;
2749
+ };
2549
2750
  }
2550
- const numContainers = peek$(ctx, "numContainers");
2751
+ let numContainers = prevNumContainers;
2551
2752
  const pendingRemoval = [];
2552
2753
  if (dataChanged) {
2553
2754
  for (let i = 0; i < numContainers; i++) {
@@ -2558,7 +2759,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2558
2759
  }
2559
2760
  }
2560
2761
  if (startBuffered !== null && endBuffered !== null) {
2561
- let numContainers2 = prevNumContainers;
2562
2762
  const needNewContainers = [];
2563
2763
  for (let i = startBuffered; i <= endBuffered; i++) {
2564
2764
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
@@ -2569,7 +2769,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2569
2769
  if (stickyIndicesArr.length > 0) {
2570
2770
  handleStickyActivation(
2571
2771
  ctx,
2572
- state,
2573
2772
  stickyIndicesSet,
2574
2773
  stickyIndicesArr,
2575
2774
  currentStickyIdx,
@@ -2577,18 +2776,16 @@ function calculateItemsInView(ctx, state, params = {}) {
2577
2776
  startBuffered,
2578
2777
  endBuffered
2579
2778
  );
2580
- } else {
2581
- state.activeStickyIndex = void 0;
2582
- set$(ctx, "activeStickyIndex", void 0);
2779
+ } else if (previousStickyIndex !== -1) {
2780
+ set$(ctx, "activeStickyIndex", -1);
2583
2781
  }
2584
2782
  if (needNewContainers.length > 0) {
2585
2783
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2586
2784
  const itemType = getItemType(data[i], i);
2587
- return itemType ? String(itemType) : "";
2785
+ return itemType !== void 0 ? String(itemType) : "";
2588
2786
  }) : void 0;
2589
2787
  const availableContainers = findAvailableContainers(
2590
2788
  ctx,
2591
- state,
2592
2789
  needNewContainers.length,
2593
2790
  startBuffered,
2594
2791
  endBuffered,
@@ -2609,30 +2806,31 @@ function calculateItemsInView(ctx, state, params = {}) {
2609
2806
  if (requiredItemTypes) {
2610
2807
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2611
2808
  }
2612
- containerItemKeys.add(id);
2809
+ containerItemKeys.set(id, containerIndex);
2810
+ const containerSticky = `containerSticky${containerIndex}`;
2613
2811
  if (stickyIndicesSet.has(i)) {
2614
- set$(ctx, `containerSticky${containerIndex}`, true);
2812
+ set$(ctx, containerSticky, true);
2615
2813
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2616
2814
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2617
2815
  state.stickyContainerPool.add(containerIndex);
2618
- } else {
2619
- set$(ctx, `containerSticky${containerIndex}`, false);
2816
+ } else if (peek$(ctx, containerSticky)) {
2817
+ set$(ctx, containerSticky, false);
2620
2818
  state.stickyContainerPool.delete(containerIndex);
2621
2819
  }
2622
- if (containerIndex >= numContainers2) {
2623
- numContainers2 = containerIndex + 1;
2820
+ if (containerIndex >= numContainers) {
2821
+ numContainers = containerIndex + 1;
2624
2822
  }
2625
2823
  }
2626
- if (numContainers2 !== prevNumContainers) {
2627
- set$(ctx, "numContainers", numContainers2);
2628
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2629
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
2824
+ if (numContainers !== prevNumContainers) {
2825
+ set$(ctx, "numContainers", numContainers);
2826
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
2827
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2630
2828
  }
2631
2829
  }
2632
2830
  }
2633
2831
  }
2634
2832
  if (stickyIndicesArr.length > 0) {
2635
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2833
+ handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2636
2834
  }
2637
2835
  let didChangePositions = false;
2638
2836
  for (let i = 0; i < numContainers; i++) {
@@ -2684,7 +2882,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2684
2882
  }
2685
2883
  if (!queuedInitialLayout && endBuffered !== null) {
2686
2884
  if (checkAllSizesKnown(state)) {
2687
- setDidLayout(ctx, state);
2885
+ setDidLayout(ctx);
2688
2886
  }
2689
2887
  }
2690
2888
  if (viewabilityConfigCallbackPairs) {
@@ -2697,9 +2895,6 @@ function calculateItemsInView(ctx, state, params = {}) {
2697
2895
  }
2698
2896
  }
2699
2897
  });
2700
- if (state.initialAnchor) {
2701
- ensureInitialAnchor(ctx, state);
2702
- }
2703
2898
  }
2704
2899
 
2705
2900
  // src/core/checkActualChange.ts
@@ -2722,20 +2917,69 @@ function checkActualChange(state, dataProp, previousData) {
2722
2917
  return false;
2723
2918
  }
2724
2919
 
2920
+ // src/core/checkFinishedScroll.ts
2921
+ function checkFinishedScroll(ctx) {
2922
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2923
+ }
2924
+ function checkFinishedScrollFrame(ctx) {
2925
+ const scrollingTo = ctx.state.scrollingTo;
2926
+ if (scrollingTo) {
2927
+ const { state } = ctx;
2928
+ state.animFrameCheckFinishedScroll = void 0;
2929
+ const scroll = state.scrollPending;
2930
+ const adjust = state.scrollAdjustHandler.getAdjust();
2931
+ const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
2932
+ const maxOffset = clampScrollOffset(ctx, scroll);
2933
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
2934
+ const diff2 = Math.abs(diff1 - adjust);
2935
+ const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
2936
+ if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
2937
+ finishScrollTo(ctx);
2938
+ }
2939
+ }
2940
+ }
2941
+ function checkFinishedScrollFallback(ctx) {
2942
+ const state = ctx.state;
2943
+ const scrollingTo = state.scrollingTo;
2944
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || !state.didContainersLayout;
2945
+ state.timeoutCheckFinishedScrollFallback = setTimeout(
2946
+ () => {
2947
+ let numChecks = 0;
2948
+ const checkHasScrolled = () => {
2949
+ state.timeoutCheckFinishedScrollFallback = void 0;
2950
+ const isStillScrollingTo = state.scrollingTo;
2951
+ if (isStillScrollingTo) {
2952
+ numChecks++;
2953
+ if (state.hasScrolled || numChecks > 5) {
2954
+ finishScrollTo(ctx);
2955
+ } else {
2956
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
2957
+ }
2958
+ }
2959
+ };
2960
+ checkHasScrolled();
2961
+ },
2962
+ slowTimeout ? 500 : 100
2963
+ );
2964
+ }
2965
+
2725
2966
  // src/core/doMaintainScrollAtEnd.ts
2726
- function doMaintainScrollAtEnd(ctx, state, animated) {
2967
+ function doMaintainScrollAtEnd(ctx, animated) {
2968
+ const state = ctx.state;
2727
2969
  const {
2970
+ didContainersLayout,
2971
+ isAtEnd,
2728
2972
  refScroller,
2729
2973
  props: { maintainScrollAtEnd }
2730
2974
  } = state;
2731
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2975
+ if (isAtEnd && maintainScrollAtEnd && didContainersLayout) {
2732
2976
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2733
2977
  if (paddingTop > 0) {
2734
2978
  state.scroll = 0;
2735
2979
  }
2736
2980
  requestAnimationFrame(() => {
2737
2981
  var _a3;
2738
- if (state == null ? void 0 : state.isAtEnd) {
2982
+ if (state.isAtEnd) {
2739
2983
  state.maintainingScrollAtEnd = true;
2740
2984
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2741
2985
  animated
@@ -2806,28 +3050,30 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2806
3050
  }
2807
3051
 
2808
3052
  // src/core/checkResetContainers.ts
2809
- function checkResetContainers(ctx, state, dataProp) {
3053
+ function checkResetContainers(ctx, dataProp) {
3054
+ const state = ctx.state;
2810
3055
  const { previousData } = state;
2811
3056
  if (previousData) {
2812
3057
  updateAveragesOnDataChange(state, previousData, dataProp);
2813
3058
  }
2814
3059
  const { maintainScrollAtEnd } = state.props;
2815
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
3060
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2816
3061
  const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2817
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
3062
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, false);
2818
3063
  if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2819
3064
  state.isEndReached = false;
2820
3065
  }
2821
3066
  if (!didMaintainScrollAtEnd) {
2822
3067
  checkAtTop(state);
2823
- checkAtBottom(ctx, state);
3068
+ checkAtBottom(ctx);
2824
3069
  }
2825
3070
  delete state.previousData;
2826
3071
  }
2827
3072
 
2828
3073
  // src/core/doInitialAllocateContainers.ts
2829
- function doInitialAllocateContainers(ctx, state) {
3074
+ function doInitialAllocateContainers(ctx) {
2830
3075
  var _a3, _b, _c;
3076
+ const state = ctx.state;
2831
3077
  const {
2832
3078
  scrollLength,
2833
3079
  props: {
@@ -2848,8 +3094,10 @@ function doInitialAllocateContainers(ctx, state) {
2848
3094
  const num = Math.min(20, data.length);
2849
3095
  for (let i = 0; i < num; i++) {
2850
3096
  const item = data[i];
2851
- const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2852
- totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
3097
+ if (item !== void 0) {
3098
+ const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
3099
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(item, i, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(item, i, itemType)) != null ? _c : estimatedItemSize;
3100
+ }
2853
3101
  }
2854
3102
  averageItemSize = totalSize / num;
2855
3103
  } else {
@@ -2865,10 +3113,10 @@ function doInitialAllocateContainers(ctx, state) {
2865
3113
  if (state.lastLayout) {
2866
3114
  if (state.initialScroll) {
2867
3115
  requestAnimationFrame(() => {
2868
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
3116
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2869
3117
  });
2870
3118
  } else {
2871
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
3119
+ calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
2872
3120
  }
2873
3121
  }
2874
3122
  return true;
@@ -2876,7 +3124,8 @@ function doInitialAllocateContainers(ctx, state) {
2876
3124
  }
2877
3125
 
2878
3126
  // src/core/handleLayout.ts
2879
- function handleLayout(ctx, state, layout, setCanRender) {
3127
+ function handleLayout(ctx, layout, setCanRender) {
3128
+ const state = ctx.state;
2880
3129
  const { maintainScrollAtEnd } = state.props;
2881
3130
  const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2882
3131
  const previousLength = state.scrollLength;
@@ -2892,19 +3141,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2892
3141
  state.lastBatchingAction = Date.now();
2893
3142
  state.scrollForNextCalculateItemsInView = void 0;
2894
3143
  if (scrollLength > 0) {
2895
- doInitialAllocateContainers(ctx, state);
3144
+ doInitialAllocateContainers(ctx);
2896
3145
  }
2897
3146
  if (needsCalculate) {
2898
- calculateItemsInView(ctx, state, { doMVCP: true });
3147
+ calculateItemsInView(ctx, { doMVCP: true });
2899
3148
  }
2900
3149
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2901
3150
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2902
3151
  }
2903
3152
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2904
- doMaintainScrollAtEnd(ctx, state, false);
3153
+ doMaintainScrollAtEnd(ctx, false);
2905
3154
  }
2906
- updateAlignItemsPaddingTop(ctx, state);
2907
- checkAtBottom(ctx, state);
3155
+ updateAlignItemsPaddingTop(ctx);
3156
+ checkAtBottom(ctx);
2908
3157
  checkAtTop(state);
2909
3158
  if (state) {
2910
3159
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
@@ -2920,8 +3169,9 @@ function handleLayout(ctx, state, layout, setCanRender) {
2920
3169
  }
2921
3170
 
2922
3171
  // src/core/onScroll.ts
2923
- function onScroll(ctx, state, event) {
3172
+ function onScroll(ctx, event) {
2924
3173
  var _a3, _b, _c;
3174
+ const state = ctx.state;
2925
3175
  const {
2926
3176
  scrollProcessingEnabled,
2927
3177
  props: { onScroll: onScrollProp }
@@ -2932,9 +3182,25 @@ function onScroll(ctx, state, event) {
2932
3182
  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) {
2933
3183
  return;
2934
3184
  }
2935
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3185
+ let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3186
+ if (state.scrollingTo) {
3187
+ const maxOffset = clampScrollOffset(ctx, newScroll);
3188
+ if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3189
+ newScroll = maxOffset;
3190
+ scrollTo(ctx, {
3191
+ forceScroll: true,
3192
+ isInitialScroll: true,
3193
+ noScrollingTo: true,
3194
+ offset: newScroll
3195
+ });
3196
+ return;
3197
+ }
3198
+ }
2936
3199
  state.scrollPending = newScroll;
2937
- updateScroll(ctx, state, newScroll);
3200
+ updateScroll(ctx, newScroll);
3201
+ if (state.scrollingTo) {
3202
+ checkFinishedScroll(ctx);
3203
+ }
2938
3204
  onScrollProp == null ? void 0 : onScrollProp(event);
2939
3205
  }
2940
3206
 
@@ -2943,51 +3209,58 @@ var ScrollAdjustHandler = class {
2943
3209
  constructor(ctx) {
2944
3210
  this.appliedAdjust = 0;
2945
3211
  this.pendingAdjust = 0;
2946
- this.mounted = false;
2947
- this.context = ctx;
2948
- {
2949
- const commitPendingAdjust = () => {
2950
- const state = this.context.internalState;
2951
- const pending = this.pendingAdjust;
2952
- if (pending !== 0) {
2953
- this.pendingAdjust = 0;
2954
- this.appliedAdjust += pending;
2955
- state.scroll += pending;
2956
- state.scrollForNextCalculateItemsInView = void 0;
2957
- set$(this.context, "scrollAdjustPending", 0);
2958
- set$(this.context, "scrollAdjust", this.appliedAdjust);
2959
- calculateItemsInView(this.context, this.context.internalState);
2960
- }
2961
- };
2962
- listen$(this.context, "scrollingTo", (value) => {
2963
- if (value === void 0) {
2964
- commitPendingAdjust();
2965
- }
2966
- });
2967
- }
3212
+ this.ctx = ctx;
2968
3213
  }
2969
3214
  requestAdjust(add) {
2970
- const scrollingTo = peek$(this.context, "scrollingTo");
3215
+ const scrollingTo = this.ctx.state.scrollingTo;
2971
3216
  if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2972
3217
  this.pendingAdjust += add;
2973
- set$(this.context, "scrollAdjustPending", this.pendingAdjust);
3218
+ set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2974
3219
  } else {
2975
3220
  this.appliedAdjust += add;
2976
- set$(this.context, "scrollAdjust", this.appliedAdjust);
3221
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3222
+ }
3223
+ if (this.ctx.state.scrollingTo) {
3224
+ checkFinishedScroll(this.ctx);
2977
3225
  }
2978
- }
2979
- setMounted() {
2980
- this.mounted = true;
2981
3226
  }
2982
3227
  getAdjust() {
2983
3228
  return this.appliedAdjust;
2984
3229
  }
3230
+ commitPendingAdjust(scrollTarget) {
3231
+ {
3232
+ const state = this.ctx.state;
3233
+ const pending = this.pendingAdjust;
3234
+ this.pendingAdjust = 0;
3235
+ if (pending !== 0) {
3236
+ let targetScroll;
3237
+ if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3238
+ const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3239
+ targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3240
+ targetScroll = clampScrollOffset(this.ctx, targetScroll);
3241
+ } else {
3242
+ targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3243
+ }
3244
+ const adjustment = targetScroll - state.scroll;
3245
+ if (Math.abs(adjustment) > 0.1 || Math.abs(pending) > 0.1) {
3246
+ this.appliedAdjust += adjustment;
3247
+ state.scroll = targetScroll;
3248
+ state.scrollForNextCalculateItemsInView = void 0;
3249
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3250
+ }
3251
+ set$(this.ctx, "scrollAdjustPending", 0);
3252
+ calculateItemsInView(this.ctx);
3253
+ }
3254
+ }
3255
+ }
2985
3256
  };
2986
3257
 
2987
3258
  // src/core/updateItemSize.ts
2988
- function updateItemSize(ctx, state, itemKey, sizeObj) {
3259
+ function updateItemSize(ctx, itemKey, sizeObj) {
2989
3260
  var _a3;
3261
+ const state = ctx.state;
2990
3262
  const {
3263
+ didContainersLayout,
2991
3264
  sizesKnown,
2992
3265
  props: {
2993
3266
  getFixedItemSize,
@@ -3010,31 +3283,24 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
3010
3283
  return;
3011
3284
  }
3012
3285
  const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
3013
- const size2 = getFixedItemSize(index, itemData, type);
3286
+ const size2 = getFixedItemSize(itemData, index, type);
3014
3287
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
3015
3288
  return;
3016
3289
  }
3017
3290
  }
3018
- const containersDidLayout = peek$(ctx, "containersDidLayout");
3019
- let needsRecalculate = !containersDidLayout;
3291
+ let needsRecalculate = !didContainersLayout;
3020
3292
  let shouldMaintainScrollAtEnd = false;
3021
3293
  let minIndexSizeChanged;
3022
3294
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
3023
3295
  const prevSizeKnown = state.sizesKnown.get(itemKey);
3024
- const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3296
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj);
3025
3297
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
3026
3298
  if (diff !== 0) {
3027
3299
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
3028
3300
  const { startBuffered, endBuffered } = state;
3029
3301
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
3030
- if (!needsRecalculate) {
3031
- const numContainers = ctx.values.get("numContainers");
3032
- for (let i = 0; i < numContainers; i++) {
3033
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
3034
- needsRecalculate = true;
3035
- break;
3036
- }
3037
- }
3302
+ if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
3303
+ needsRecalculate = true;
3038
3304
  }
3039
3305
  if (state.needsOtherAxisSize) {
3040
3306
  const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
@@ -3070,22 +3336,22 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
3070
3336
  if (!cur || maxOtherAxisSize > cur) {
3071
3337
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
3072
3338
  }
3073
- if (containersDidLayout || checkAllSizesKnown(state)) {
3339
+ if (didContainersLayout || checkAllSizesKnown(state)) {
3074
3340
  if (needsRecalculate) {
3075
3341
  state.scrollForNextCalculateItemsInView = void 0;
3076
- calculateItemsInView(ctx, state, { doMVCP: true });
3342
+ calculateItemsInView(ctx, { doMVCP: true });
3077
3343
  }
3078
3344
  if (shouldMaintainScrollAtEnd) {
3079
3345
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
3080
- doMaintainScrollAtEnd(ctx, state, false);
3346
+ doMaintainScrollAtEnd(ctx, false);
3081
3347
  }
3082
3348
  }
3083
3349
  }
3084
3350
  }
3085
- function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3351
+ function updateOneItemSize(ctx, itemKey, sizeObj) {
3086
3352
  var _a3;
3353
+ const state = ctx.state;
3087
3354
  const {
3088
- sizes,
3089
3355
  indexByKey,
3090
3356
  sizesKnown,
3091
3357
  averageSizes,
@@ -3093,9 +3359,10 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3093
3359
  } = state;
3094
3360
  if (!data) return 0;
3095
3361
  const index = indexByKey.get(itemKey);
3096
- const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
3362
+ const prevSize = getItemSize(ctx, itemKey, index, data[index]);
3097
3363
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
3098
3364
  const size = Math.round(rawSize) ;
3365
+ const prevSizeKnown = sizesKnown.get(itemKey);
3099
3366
  sizesKnown.set(itemKey, size);
3100
3367
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
3101
3368
  const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
@@ -3103,15 +3370,25 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3103
3370
  if (!averages) {
3104
3371
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3105
3372
  }
3106
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3107
- averages.num++;
3373
+ if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3374
+ averages.avg += (size - prevSizeKnown) / averages.num;
3375
+ } else {
3376
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
3377
+ averages.num++;
3378
+ }
3108
3379
  }
3109
3380
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
3110
- setSize(ctx, state, itemKey, size);
3381
+ setSize(ctx, itemKey, size);
3111
3382
  return size - prevSize;
3112
3383
  }
3113
3384
  return 0;
3114
3385
  }
3386
+ function useWrapIfItem(fn) {
3387
+ return useMemo(
3388
+ () => fn ? (arg1, arg2, arg3) => arg1 !== void 0 && arg2 !== void 0 ? fn(arg1, arg2, arg3) : void 0 : void 0,
3389
+ [fn]
3390
+ );
3391
+ }
3115
3392
  var useCombinedRef = (...refs) => {
3116
3393
  const callback = useCallback((element) => {
3117
3394
  for (const ref of refs) {
@@ -3154,14 +3431,15 @@ function createColumnWrapperStyle(contentContainerStyle) {
3154
3431
  }
3155
3432
 
3156
3433
  // src/utils/createImperativeHandle.ts
3157
- function createImperativeHandle(ctx, state) {
3434
+ function createImperativeHandle(ctx) {
3435
+ const state = ctx.state;
3158
3436
  const scrollIndexIntoView = (options) => {
3159
3437
  if (state) {
3160
3438
  const { index, ...rest } = options;
3161
3439
  const { startNoBuffer, endNoBuffer } = state;
3162
3440
  if (index < startNoBuffer || index > endNoBuffer) {
3163
3441
  const viewPosition = index < startNoBuffer ? 0 : 1;
3164
- scrollToIndex(ctx, state, {
3442
+ scrollToIndex(ctx, {
3165
3443
  ...rest,
3166
3444
  index,
3167
3445
  viewPosition
@@ -3176,7 +3454,7 @@ function createImperativeHandle(ctx, state) {
3176
3454
  getScrollableNode: () => refScroller.current.getScrollableNode(),
3177
3455
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3178
3456
  getState: () => ({
3179
- activeStickyIndex: state.activeStickyIndex,
3457
+ activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3180
3458
  contentLength: state.totalSize,
3181
3459
  data: state.props.data,
3182
3460
  elementAtIndex: (index) => {
@@ -3187,6 +3465,8 @@ function createImperativeHandle(ctx, state) {
3187
3465
  endBuffered: state.endBuffered,
3188
3466
  isAtEnd: state.isAtEnd,
3189
3467
  isAtStart: state.isAtStart,
3468
+ listen: (signalName, cb) => listen$(ctx, signalName, cb),
3469
+ listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3190
3470
  positionAtIndex: (index) => state.positions.get(getId(state, index)),
3191
3471
  positions: state.positions,
3192
3472
  scroll: state.scroll,
@@ -3211,23 +3491,23 @@ function createImperativeHandle(ctx, state) {
3211
3491
  if (index !== -1) {
3212
3492
  const paddingBottom = stylePaddingBottom || 0;
3213
3493
  const footerSize = peek$(ctx, "footerSize") || 0;
3214
- scrollToIndex(ctx, state, {
3494
+ scrollToIndex(ctx, {
3495
+ ...options,
3215
3496
  index,
3216
3497
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3217
- viewPosition: 1,
3218
- ...options
3498
+ viewPosition: 1
3219
3499
  });
3220
3500
  }
3221
3501
  },
3222
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3502
+ scrollToIndex: (params) => scrollToIndex(ctx, params),
3223
3503
  scrollToItem: ({ item, ...props }) => {
3224
3504
  const data = state.props.data;
3225
3505
  const index = data.indexOf(item);
3226
3506
  if (index !== -1) {
3227
- scrollToIndex(ctx, state, { index, ...props });
3507
+ scrollToIndex(ctx, { index, ...props });
3228
3508
  }
3229
3509
  },
3230
- scrollToOffset: (params) => scrollTo(ctx, state, params),
3510
+ scrollToOffset: (params) => scrollTo(ctx, params),
3231
3511
  setScrollProcessingEnabled: (enabled) => {
3232
3512
  state.scrollProcessingEnabled = enabled;
3233
3513
  },
@@ -3237,8 +3517,9 @@ function createImperativeHandle(ctx, state) {
3237
3517
  }
3238
3518
  };
3239
3519
  }
3240
- function getRenderedItem(ctx, state, key) {
3520
+ function getRenderedItem(ctx, key) {
3241
3521
  var _a3;
3522
+ const state = ctx.state;
3242
3523
  if (!state) {
3243
3524
  return null;
3244
3525
  }
@@ -3265,6 +3546,25 @@ function getRenderedItem(ctx, state, key) {
3265
3546
  }
3266
3547
  return { index, item: data[index], renderedItem };
3267
3548
  }
3549
+
3550
+ // src/utils/normalizeMaintainVisibleContentPosition.ts
3551
+ function normalizeMaintainVisibleContentPosition(value) {
3552
+ var _a3, _b;
3553
+ if (value === true) {
3554
+ return { data: true, size: true };
3555
+ }
3556
+ if (value && typeof value === "object") {
3557
+ return {
3558
+ data: (_a3 = value.data) != null ? _a3 : false,
3559
+ size: (_b = value.size) != null ? _b : true,
3560
+ shouldRestorePosition: value.shouldRestorePosition
3561
+ };
3562
+ }
3563
+ if (value === false) {
3564
+ return { data: false, size: false };
3565
+ }
3566
+ return { data: false, size: true };
3567
+ }
3268
3568
  function useThrottleDebounce(mode) {
3269
3569
  const timeoutRef = useRef(null);
3270
3570
  const lastCallTimeRef = useRef(0);
@@ -3315,6 +3615,7 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3315
3615
  var DEFAULT_DRAW_DISTANCE = 250;
3316
3616
  var DEFAULT_ITEM_SIZE = 100;
3317
3617
  var LegendList = typedMemo(
3618
+ // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3318
3619
  typedForwardRef(function LegendList2(props, forwardedRef) {
3319
3620
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
3320
3621
  const isChildrenMode = children !== void 0 && dataProp === void 0;
@@ -3337,10 +3638,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3337
3638
  alignItemsAtEnd = false,
3338
3639
  columnWrapperStyle,
3339
3640
  contentContainerStyle: contentContainerStyleProp,
3641
+ contentInset,
3340
3642
  data: dataProp = [],
3341
3643
  dataVersion,
3342
3644
  drawDistance = 250,
3343
- enableAverages = true,
3344
3645
  estimatedItemSize: estimatedItemSizeProp,
3345
3646
  estimatedListSize,
3346
3647
  extraData,
@@ -3358,7 +3659,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3358
3659
  ListHeaderComponent,
3359
3660
  maintainScrollAtEnd = false,
3360
3661
  maintainScrollAtEndThreshold = 0.1,
3361
- maintainVisibleContentPosition = false,
3662
+ maintainVisibleContentPosition: maintainVisibleContentPositionProp,
3362
3663
  numColumns: numColumnsProp = 1,
3363
3664
  onEndReached,
3364
3665
  onEndReachedThreshold = 0.5,
@@ -3382,20 +3683,26 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3382
3683
  snapToIndices,
3383
3684
  stickyHeaderIndices: stickyHeaderIndicesProp,
3384
3685
  stickyIndices: stickyIndicesDeprecated,
3686
+ // TODOV3: Remove from v3 release
3385
3687
  style: styleProp,
3386
3688
  suggestEstimatedItemSize,
3387
3689
  viewabilityConfig,
3388
3690
  viewabilityConfigCallbackPairs,
3389
3691
  waitForInitialLayout = true,
3692
+ stickyHeaderConfig,
3390
3693
  ...rest
3391
3694
  } = props;
3695
+ const animatedPropsInternal = props.animatedPropsInternal;
3392
3696
  const { childrenMode } = rest;
3393
3697
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3394
3698
  const style = { ...StyleSheet.flatten(styleProp) };
3395
3699
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
3396
3700
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
3701
+ const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
3702
+ maintainVisibleContentPositionProp
3703
+ );
3397
3704
  const [renderNum, setRenderNum] = useState(0);
3398
- 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;
3705
+ 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;
3399
3706
  const [canRender, setCanRender] = React3.useState(!IsNewArchitecture);
3400
3707
  const ctx = useStateContext();
3401
3708
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
@@ -3413,13 +3720,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3413
3720
  }
3414
3721
  const refState = useRef();
3415
3722
  if (!refState.current) {
3416
- if (!ctx.internalState) {
3723
+ if (!ctx.state) {
3417
3724
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
3418
- ctx.internalState = {
3419
- activeStickyIndex: void 0,
3725
+ ctx.state = {
3726
+ activeStickyIndex: -1,
3420
3727
  averageSizes: {},
3421
3728
  columns: /* @__PURE__ */ new Map(),
3422
- containerItemKeys: /* @__PURE__ */ new Set(),
3729
+ containerItemKeys: /* @__PURE__ */ new Map(),
3423
3730
  containerItemTypes: /* @__PURE__ */ new Map(),
3424
3731
  dataChangeNeedsScrollUpdate: false,
3425
3732
  didColumnsChange: false,
@@ -3442,11 +3749,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3442
3749
  initialScroll: initialScrollProp,
3443
3750
  isAtEnd: false,
3444
3751
  isAtStart: false,
3445
- isEndReached: false,
3752
+ isEndReached: null,
3446
3753
  isFirst: true,
3447
- isStartReached: false,
3754
+ isStartReached: null,
3448
3755
  lastBatchingAction: Date.now(),
3449
3756
  lastLayout: void 0,
3757
+ lastScrollDelta: 0,
3450
3758
  loadStartTime: Date.now(),
3451
3759
  minIndexSizeChanged: 0,
3452
3760
  nativeMarginTop: 0,
@@ -3476,12 +3784,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3476
3784
  totalSize: 0,
3477
3785
  viewabilityConfigCallbackPairs: void 0
3478
3786
  };
3479
- const internalState = ctx.internalState;
3480
- internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3481
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3787
+ const internalState = ctx.state;
3788
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3789
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
3482
3790
  set$(ctx, "extraData", extraData);
3483
3791
  }
3484
- refState.current = ctx.internalState;
3792
+ refState.current = ctx.state;
3485
3793
  }
3486
3794
  const state = refState.current;
3487
3795
  const isFirstLocal = state.isFirst;
@@ -3495,20 +3803,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3495
3803
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3496
3804
  state.props = {
3497
3805
  alignItemsAtEnd,
3806
+ animatedProps: animatedPropsInternal,
3807
+ contentInset,
3498
3808
  data: dataProp,
3499
3809
  dataVersion,
3500
- enableAverages,
3501
3810
  estimatedItemSize,
3502
- getEstimatedItemSize,
3503
- getFixedItemSize,
3504
- getItemType,
3811
+ getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3812
+ getFixedItemSize: useWrapIfItem(getFixedItemSize),
3813
+ getItemType: useWrapIfItem(getItemType),
3505
3814
  horizontal: !!horizontal,
3506
3815
  initialContainerPoolRatio,
3507
3816
  itemsAreEqual,
3508
- keyExtractor,
3817
+ keyExtractor: useWrapIfItem(keyExtractor),
3509
3818
  maintainScrollAtEnd,
3510
3819
  maintainScrollAtEndThreshold,
3511
- maintainVisibleContentPosition,
3820
+ maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
3512
3821
  numColumns: numColumnsProp,
3513
3822
  onEndReached,
3514
3823
  onEndReachedThreshold,
@@ -3540,57 +3849,47 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3540
3849
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3541
3850
  set$(ctx, "numColumns", numColumnsProp);
3542
3851
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
3543
- setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3852
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3544
3853
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3545
3854
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3546
- if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3855
+ if (maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3547
3856
  if (state.scroll < 0) {
3548
3857
  paddingDiff += state.scroll;
3549
3858
  }
3550
- requestAdjust(ctx, state, paddingDiff);
3859
+ requestAdjust(ctx, paddingDiff);
3551
3860
  }
3552
3861
  };
3553
3862
  if (isFirstLocal) {
3554
3863
  initializeStateVars();
3555
3864
  updateItemPositions(
3556
3865
  ctx,
3557
- state,
3558
3866
  /*dataChanged*/
3559
3867
  true
3560
3868
  );
3561
3869
  }
3562
3870
  const initialContentOffset = useMemo(() => {
3563
- var _a4, _b2;
3564
- const { initialScroll } = refState.current;
3565
- if (!initialScroll) {
3871
+ let value;
3872
+ const { initialScroll, initialAnchor } = refState.current;
3873
+ if (initialScroll) {
3874
+ if (initialScroll.contentOffset !== void 0) {
3875
+ value = initialScroll.contentOffset;
3876
+ } else {
3877
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3878
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3879
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
3880
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3881
+ refState.current.initialScroll = updatedInitialScroll;
3882
+ state.initialScroll = updatedInitialScroll;
3883
+ value = clampedOffset;
3884
+ }
3885
+ } else {
3566
3886
  refState.current.initialAnchor = void 0;
3567
- return 0;
3568
- }
3569
- if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3570
- refState.current.initialAnchor = {
3571
- attempts: 0,
3572
- index: initialScroll.index,
3573
- settledTicks: 0,
3574
- viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3575
- viewPosition: initialScroll.viewPosition
3576
- };
3887
+ value = 0;
3888
+ }
3889
+ if (!value) {
3890
+ setInitialRenderState(ctx, { didInitialScroll: true });
3577
3891
  }
3578
- if (initialScroll.contentOffset !== void 0) {
3579
- return initialScroll.contentOffset;
3580
- }
3581
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3582
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3583
- let clampedOffset = resolvedOffset;
3584
- if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3585
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3586
- clampedOffset = Math.min(clampedOffset, maxOffset);
3587
- }
3588
- clampedOffset = Math.max(0, clampedOffset);
3589
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3590
- refState.current.initialScroll = updatedInitialScroll;
3591
- state.initialScroll = updatedInitialScroll;
3592
- refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3593
- return clampedOffset;
3892
+ return value;
3594
3893
  }, [renderNum]);
3595
3894
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3596
3895
  refState.current.lastBatchingAction = Date.now();
@@ -3618,12 +3917,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3618
3917
  }
3619
3918
  }, []);
3620
3919
  const doInitialScroll = useCallback(() => {
3621
- var _a4;
3622
- const initialScroll = state.initialScroll;
3623
- if (initialScroll) {
3624
- scrollTo(ctx, state, {
3920
+ const { initialScroll, didFinishInitialScroll, queuedInitialLayout, scrollingTo } = state;
3921
+ if (initialScroll && !queuedInitialLayout && !didFinishInitialScroll && !scrollingTo) {
3922
+ scrollTo(ctx, {
3625
3923
  animated: false,
3626
- index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3924
+ index: initialScroll == null ? void 0 : initialScroll.index,
3627
3925
  isInitialScroll: true,
3628
3926
  offset: initialContentOffset,
3629
3927
  precomputedWithViewOffset: true
@@ -3632,7 +3930,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3632
3930
  }, [initialContentOffset]);
3633
3931
  const onLayoutChange = useCallback((layout) => {
3634
3932
  doInitialScroll();
3635
- handleLayout(ctx, state, layout, setCanRender);
3933
+ handleLayout(ctx, layout, setCanRender);
3636
3934
  }, []);
3637
3935
  const { onLayout } = useOnLayoutSync({
3638
3936
  onLayoutChange,
@@ -3642,7 +3940,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3642
3940
  });
3643
3941
  useLayoutEffect(() => {
3644
3942
  if (snapToIndices) {
3645
- updateSnapToOffsets(ctx, state);
3943
+ updateSnapToOffsets(ctx);
3646
3944
  }
3647
3945
  }, [snapToIndices]);
3648
3946
  useLayoutEffect(() => {
@@ -3652,9 +3950,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3652
3950
  isFirst,
3653
3951
  props: { data }
3654
3952
  } = state;
3655
- const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3953
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
3656
3954
  if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3657
- checkResetContainers(ctx, state, data);
3955
+ checkResetContainers(ctx, data);
3658
3956
  }
3659
3957
  state.didColumnsChange = false;
3660
3958
  state.didDataChange = false;
@@ -3679,15 +3977,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3679
3977
  state.viewabilityConfigCallbackPairs = viewability;
3680
3978
  state.enableScrollForNextCalculateItemsInView = !viewability;
3681
3979
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3682
- useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3980
+ useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
3683
3981
  {
3684
3982
  useEffect(doInitialScroll, []);
3685
3983
  }
3686
3984
  const fns = useMemo(
3687
3985
  () => ({
3688
- getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3689
- onScroll: (event) => onScroll(ctx, state, event),
3690
- updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3986
+ getRenderedItem: (key) => getRenderedItem(ctx, key),
3987
+ onMomentumScrollEnd: (event) => {
3988
+ checkFinishedScrollFallback(ctx);
3989
+ if (onMomentumScrollEnd) {
3990
+ onMomentumScrollEnd(event);
3991
+ }
3992
+ },
3993
+ onScroll: (event) => onScroll(ctx, event),
3994
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
3691
3995
  }),
3692
3996
  []
3693
3997
  );
@@ -3699,24 +4003,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3699
4003
  alignItemsAtEnd,
3700
4004
  canRender,
3701
4005
  contentContainerStyle,
4006
+ contentInset,
3702
4007
  getRenderedItem: fns.getRenderedItem,
3703
4008
  horizontal,
3704
4009
  initialContentOffset,
3705
4010
  ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
3706
4011
  ListHeaderComponent,
3707
- maintainVisibleContentPosition,
3708
4012
  onLayout,
3709
4013
  onLayoutHeader,
3710
- onMomentumScrollEnd: (event) => {
3711
- {
3712
- requestAnimationFrame(() => {
3713
- finishScrollTo(ctx, refState.current);
3714
- });
3715
- }
3716
- if (onMomentumScrollEnd) {
3717
- onMomentumScrollEnd(event);
3718
- }
3719
- },
4014
+ onMomentumScrollEnd: fns.onMomentumScrollEnd,
3720
4015
  onScroll: onScrollHandler,
3721
4016
  recycleItems,
3722
4017
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
@@ -3731,8 +4026,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3731
4026
  ),
3732
4027
  refScrollView: combinedRef,
3733
4028
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3734
- scrollEventThrottle: 16 ,
4029
+ scrollEventThrottle: 0,
3735
4030
  snapToIndices,
4031
+ stickyHeaderConfig,
3736
4032
  stickyHeaderIndices,
3737
4033
  style,
3738
4034
  updateItemSize: fns.updateItemSize,
@@ -3741,4 +4037,4 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3741
4037
  ), IS_DEV && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3.createElement(DebugView, { state: refState.current }));
3742
4038
  });
3743
4039
 
3744
- export { LegendList, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
4040
+ export { LegendList, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };