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

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