@legendapp/list 3.0.0-beta.31 → 3.0.0-beta.33

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 (55) hide show
  1. package/.DS_Store +0 -0
  2. package/README.md +7 -1
  3. package/animated.d.ts +600 -6
  4. package/animated.js +2 -2
  5. package/animated.mjs +1 -1
  6. package/index.d.ts +462 -109
  7. package/index.js +290 -147
  8. package/index.mjs +290 -147
  9. package/index.native.js +245 -122
  10. package/index.native.mjs +246 -123
  11. package/keyboard-controller.d.ts +611 -6
  12. package/keyboard-controller.js +2 -2
  13. package/keyboard-controller.mjs +1 -1
  14. package/keyboard.d.ts +204 -8
  15. package/keyboard.js +66 -52
  16. package/keyboard.mjs +69 -54
  17. package/{index.d.mts → list-react-native.d.ts} +103 -33
  18. package/list-react-native.js +4234 -0
  19. package/list-react-native.mjs +4204 -0
  20. package/{index.native.d.mts → list-react.d.ts} +363 -41
  21. package/list-react.js +4426 -0
  22. package/list-react.mjs +4396 -0
  23. package/package.json +52 -1
  24. package/reanimated.d.ts +595 -7
  25. package/reanimated.js +156 -11
  26. package/reanimated.mjs +153 -8
  27. package/section-list.d.ts +610 -14
  28. package/section-list.js +6 -6
  29. package/section-list.mjs +1 -1
  30. package/animated.d.mts +0 -9
  31. package/animated.native.d.mts +0 -9
  32. package/animated.native.d.ts +0 -9
  33. package/animated.native.js +0 -9
  34. package/animated.native.mjs +0 -7
  35. package/index.native.d.ts +0 -810
  36. package/keyboard-controller.d.mts +0 -12
  37. package/keyboard-controller.native.d.mts +0 -12
  38. package/keyboard-controller.native.d.ts +0 -12
  39. package/keyboard-controller.native.js +0 -69
  40. package/keyboard-controller.native.mjs +0 -48
  41. package/keyboard.d.mts +0 -13
  42. package/keyboard.native.d.mts +0 -13
  43. package/keyboard.native.d.ts +0 -13
  44. package/keyboard.native.js +0 -399
  45. package/keyboard.native.mjs +0 -377
  46. package/reanimated.d.mts +0 -18
  47. package/reanimated.native.d.mts +0 -18
  48. package/reanimated.native.d.ts +0 -18
  49. package/reanimated.native.js +0 -89
  50. package/reanimated.native.mjs +0 -65
  51. package/section-list.d.mts +0 -112
  52. package/section-list.native.d.mts +0 -112
  53. package/section-list.native.d.ts +0 -112
  54. package/section-list.native.js +0 -293
  55. package/section-list.native.mjs +0 -271
package/index.mjs CHANGED
@@ -21,7 +21,7 @@ function getContentInsetEnd(state) {
21
21
  const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
22
22
  const overrideInset = (_a3 = state.contentInsetOverride) != null ? _a3 : void 0;
23
23
  if (overrideInset) {
24
- const mergedInset = { bottom: 0, left: 0, right: 0, top: 0, ...baseInset, ...overrideInset };
24
+ const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
25
25
  return (horizontal ? mergedInset.right : mergedInset.bottom) || 0;
26
26
  }
27
27
  if (baseInset) {
@@ -172,7 +172,7 @@ function useSelector$(signalName, selector) {
172
172
  var DebugRow = ({ children }) => {
173
173
  return /* @__PURE__ */ React3.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
174
174
  };
175
- var DebugView = React3.memo(function DebugView2({ state }) {
175
+ React3.memo(function DebugView2({ state }) {
176
176
  const ctx = useStateContext();
177
177
  const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
178
178
  "totalSize",
@@ -224,7 +224,7 @@ var _a;
224
224
  var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
225
225
  var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
226
226
  var _a2;
227
- var IS_DEV = (_a2 = metroDev != null ? metroDev : processDev) != null ? _a2 : false;
227
+ var IS_DEV = (_a2 = processDev != null ? processDev : metroDev) != null ? _a2 : false;
228
228
 
229
229
  // src/constants.ts
230
230
  var POSITION_OUT_OF_VIEW = -1e7;
@@ -307,7 +307,10 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
307
307
  children,
308
308
  ...rest
309
309
  }) {
310
- const [position = POSITION_OUT_OF_VIEW, activeStickyIndex] = useArr$([`containerPosition${id}`, "activeStickyIndex"]);
310
+ const [position = POSITION_OUT_OF_VIEW, activeStickyIndex] = useArr$([
311
+ `containerPosition${id}`,
312
+ "activeStickyIndex"
313
+ ]);
311
314
  const base = {
312
315
  contain: "paint layout style"
313
316
  };
@@ -337,9 +340,6 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
337
340
  return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
338
341
  });
339
342
  var PositionView = PositionViewState;
340
-
341
- // src/constants-platform.ts
342
- var IsNewArchitecture = true;
343
343
  function useInit(cb) {
344
344
  useState(() => cb());
345
345
  }
@@ -550,7 +550,8 @@ function createResizeObserver(element, callback) {
550
550
  function useOnLayoutSync({
551
551
  ref,
552
552
  onLayoutProp,
553
- onLayoutChange
553
+ onLayoutChange,
554
+ webLayoutResync
554
555
  }, deps) {
555
556
  useLayoutEffect(() => {
556
557
  var _a3, _b;
@@ -574,7 +575,9 @@ function useOnLayoutSync({
574
575
  var _a4;
575
576
  const target = entry.target instanceof HTMLElement ? entry.target : void 0;
576
577
  const rectObserved = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
577
- if (rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height) {
578
+ const didSizeChange = rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height;
579
+ const shouldResyncLayout = !!(webLayoutResync == null ? void 0 : webLayoutResync());
580
+ if (didSizeChange || shouldResyncLayout) {
578
581
  prevRect = rectObserved;
579
582
  emit(toLayout(rectObserved), false);
580
583
  }
@@ -600,6 +603,15 @@ var Platform = {
600
603
  OS: "web"
601
604
  };
602
605
 
606
+ // src/utils/isInMVCPActiveMode.ts
607
+ function isInMVCPActiveMode(state) {
608
+ const lock = state.mvcpAnchorLock;
609
+ if (lock && Date.now() > lock.expiresAt) {
610
+ state.mvcpAnchorLock = void 0;
611
+ }
612
+ return state.dataChangeNeedsScrollUpdate || !!state.mvcpAnchorLock;
613
+ }
614
+
603
615
  // src/components/Container.tsx
604
616
  var Container = typedMemo(function Container2({
605
617
  id,
@@ -612,6 +624,7 @@ var Container = typedMemo(function Container2({
612
624
  }) {
613
625
  const ctx = useStateContext();
614
626
  const { columnWrapperStyle, animatedScrollY } = ctx;
627
+ const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
615
628
  const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
616
629
  `containerColumn${id}`,
617
630
  `containerSpan${id}`,
@@ -707,7 +720,8 @@ var Container = typedMemo(function Container2({
707
720
  updateItemSizeFn(currentItemKey, layout);
708
721
  itemLayoutRef.current.didLayout = true;
709
722
  };
710
- if (prevSize !== void 0 && size + 1 < prevSize) {
723
+ const shouldDeferWebShrinkLayoutUpdate = !isInMVCPActiveMode(ctx.state) && prevSize !== void 0 && size + 1 < prevSize;
724
+ if (shouldDeferWebShrinkLayoutUpdate) {
711
725
  const token = pendingShrinkToken + 1;
712
726
  itemLayoutRef.current.pendingShrinkToken = token;
713
727
  requestAnimationFrame(() => {
@@ -731,11 +745,12 @@ var Container = typedMemo(function Container2({
731
745
  const { onLayout } = useOnLayoutSync(
732
746
  {
733
747
  onLayoutChange,
734
- ref
748
+ ref,
749
+ webLayoutResync: () => isInMVCPActiveMode(ctx.state)
735
750
  },
736
751
  [itemKey, layoutRenderCount]
737
752
  );
738
- const PositionComponent = isSticky ? PositionViewSticky : PositionView;
753
+ const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : PositionView;
739
754
  return /* @__PURE__ */ React3.createElement(
740
755
  PositionComponent,
741
756
  {
@@ -923,25 +938,6 @@ var Containers = typedMemo(function Containers2({
923
938
  }
924
939
  return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
925
940
  });
926
- function DevNumbers() {
927
- return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
928
- React3.memo(function DevNumbers2() {
929
- return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3.createElement(
930
- "div",
931
- {
932
- key: index,
933
- style: {
934
- height: 100,
935
- pointerEvents: "none",
936
- position: "absolute",
937
- top: index * 100,
938
- width: "100%"
939
- }
940
- },
941
- /* @__PURE__ */ React3.createElement("div", { style: { color: "red" } }, index * 100)
942
- ));
943
- });
944
- }
945
941
 
946
942
  // src/platform/StyleSheet.tsx
947
943
  function flattenStyles(styles) {
@@ -1116,6 +1112,7 @@ function useValueListener$(key, callback) {
1116
1112
  function ScrollAdjust() {
1117
1113
  const ctx = useStateContext();
1118
1114
  const lastScrollOffsetRef = React3.useRef(0);
1115
+ const resetPaddingRafRef = React3.useRef(void 0);
1119
1116
  const callback = React3.useCallback(() => {
1120
1117
  var _a3;
1121
1118
  const scrollAdjust = peek$(ctx, "scrollAdjust");
@@ -1130,13 +1127,17 @@ function ScrollAdjust() {
1130
1127
  const nextScroll = prevScroll + scrollDelta;
1131
1128
  const totalSize = el.scrollHeight;
1132
1129
  if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1130
+ const paddingBottom = ctx.state.props.stylePaddingBottom || 0;
1133
1131
  const child = el.firstElementChild;
1134
1132
  const pad = (nextScroll + el.clientHeight - totalSize) * 2;
1135
1133
  child.style.paddingBottom = `${pad}px`;
1136
1134
  void el.offsetHeight;
1137
1135
  scrollView.scrollBy(0, scrollDelta);
1138
- requestAnimationFrame(() => {
1139
- const paddingBottom = ctx.state.props.stylePaddingBottom;
1136
+ if (resetPaddingRafRef.current !== void 0) {
1137
+ cancelAnimationFrame(resetPaddingRafRef.current);
1138
+ }
1139
+ resetPaddingRafRef.current = requestAnimationFrame(() => {
1140
+ resetPaddingRafRef.current = void 0;
1140
1141
  child.style.paddingBottom = paddingBottom ? `${paddingBottom}px` : "0";
1141
1142
  });
1142
1143
  } else {
@@ -1201,7 +1202,9 @@ var ListComponent = typedMemo(function ListComponent2({
1201
1202
  const ctx = useStateContext();
1202
1203
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1203
1204
  const ScrollComponent = renderScrollComponent ? useMemo(
1204
- () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1205
+ () => React3.forwardRef(
1206
+ (props, ref) => renderScrollComponent({ ...props, ref })
1207
+ ),
1205
1208
  [renderScrollComponent]
1206
1209
  ) : ListComponentScrollView;
1207
1210
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
@@ -1258,7 +1261,7 @@ var ListComponent = typedMemo(function ListComponent2({
1258
1261
  },
1259
1262
  getComponent(ListFooterComponent)
1260
1263
  ),
1261
- IS_DEV && ENABLE_DEVMODE && /* @__PURE__ */ React3.createElement(DevNumbers, null)
1264
+ IS_DEV && ENABLE_DEVMODE
1262
1265
  );
1263
1266
  });
1264
1267
 
@@ -1392,12 +1395,15 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1392
1395
  }
1393
1396
 
1394
1397
  // src/core/clampScrollOffset.ts
1395
- function clampScrollOffset(ctx, offset) {
1398
+ function clampScrollOffset(ctx, offset, scrollTarget) {
1396
1399
  const state = ctx.state;
1397
1400
  const contentSize = getContentSize(ctx);
1398
1401
  let clampedOffset = offset;
1399
1402
  if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android")) {
1400
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1403
+ const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
1404
+ const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
1405
+ const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
1406
+ const maxOffset = baseMaxOffset + extraEndOffset;
1401
1407
  clampedOffset = Math.min(offset, maxOffset);
1402
1408
  }
1403
1409
  clampedOffset = Math.max(0, clampedOffset);
@@ -1492,7 +1498,7 @@ function checkAtBottom(ctx) {
1492
1498
  function checkAtTop(ctx) {
1493
1499
  var _a3;
1494
1500
  const state = ctx == null ? void 0 : ctx.state;
1495
- if (!state || state.initialScroll) {
1501
+ if (!state || state.initialScroll || state.scrollingTo) {
1496
1502
  return;
1497
1503
  }
1498
1504
  const {
@@ -1536,14 +1542,22 @@ function setInitialRenderState(ctx, {
1536
1542
  didInitialScroll
1537
1543
  }) {
1538
1544
  const { state } = ctx;
1545
+ const {
1546
+ loadStartTime,
1547
+ props: { onLoad }
1548
+ } = state;
1539
1549
  if (didLayout) {
1540
1550
  state.didContainersLayout = true;
1541
1551
  }
1542
1552
  if (didInitialScroll) {
1543
1553
  state.didFinishInitialScroll = true;
1544
1554
  }
1545
- if (state.didContainersLayout && state.didFinishInitialScroll) {
1555
+ const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
1556
+ if (isReadyToRender && !peek$(ctx, "readyToRender")) {
1546
1557
  set$(ctx, "readyToRender", true);
1558
+ if (onLoad) {
1559
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1560
+ }
1547
1561
  }
1548
1562
  }
1549
1563
 
@@ -1575,6 +1589,7 @@ function finishScrollTo(ctx) {
1575
1589
  var SCROLL_END_IDLE_MS = 80;
1576
1590
  var SCROLL_END_MAX_MS = 1500;
1577
1591
  var SMOOTH_SCROLL_DURATION_MS = 320;
1592
+ var SCROLL_END_TARGET_EPSILON = 1;
1578
1593
  function doScrollTo(ctx, params) {
1579
1594
  const state = ctx.state;
1580
1595
  const { animated, horizontal, offset } = params;
@@ -1585,7 +1600,10 @@ function doScrollTo(ctx, params) {
1585
1600
  const top = horizontal ? 0 : offset;
1586
1601
  node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1587
1602
  if (animated) {
1588
- listenForScrollEnd(ctx, node);
1603
+ listenForScrollEnd(ctx, node, {
1604
+ horizontal: !!horizontal,
1605
+ targetOffset: offset
1606
+ });
1589
1607
  } else {
1590
1608
  state.scroll = offset;
1591
1609
  setTimeout(() => {
@@ -1594,31 +1612,17 @@ function doScrollTo(ctx, params) {
1594
1612
  }
1595
1613
  }
1596
1614
  }
1597
- function listenForScrollEnd(ctx, node) {
1615
+ function listenForScrollEnd(ctx, node, params) {
1616
+ const { horizontal, targetOffset } = params;
1598
1617
  const supportsScrollEnd = "onscrollend" in node;
1599
1618
  let idleTimeout;
1600
1619
  let maxTimeout;
1601
1620
  let settled = false;
1602
1621
  const targetToken = ctx.state.scrollingTo;
1603
- const finish = () => {
1604
- if (settled) return;
1605
- settled = true;
1606
- cleanup();
1607
- if (targetToken === ctx.state.scrollingTo) {
1608
- finishScrollTo(ctx);
1609
- }
1610
- };
1611
- const onScroll2 = () => {
1612
- if (idleTimeout) {
1613
- clearTimeout(idleTimeout);
1614
- }
1615
- idleTimeout = setTimeout(finish, SCROLL_END_IDLE_MS);
1616
- };
1617
1622
  const cleanup = () => {
1623
+ node.removeEventListener("scroll", onScroll2);
1618
1624
  if (supportsScrollEnd) {
1619
- node.removeEventListener("scrollend", finish);
1620
- } else {
1621
- node.removeEventListener("scroll", onScroll2);
1625
+ node.removeEventListener("scrollend", onScrollEnd);
1622
1626
  }
1623
1627
  if (idleTimeout) {
1624
1628
  clearTimeout(idleTimeout);
@@ -1627,14 +1631,37 @@ function listenForScrollEnd(ctx, node) {
1627
1631
  clearTimeout(maxTimeout);
1628
1632
  }
1629
1633
  };
1634
+ const finish = (reason) => {
1635
+ if (settled) return;
1636
+ if (targetToken !== ctx.state.scrollingTo) {
1637
+ settled = true;
1638
+ cleanup();
1639
+ return;
1640
+ }
1641
+ const currentOffset = horizontal ? node.scrollLeft : node.scrollTop;
1642
+ const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
1643
+ if (reason === "scrollend" && !isNearTarget) {
1644
+ return;
1645
+ }
1646
+ settled = true;
1647
+ cleanup();
1648
+ finishScrollTo(ctx);
1649
+ };
1650
+ const onScroll2 = () => {
1651
+ if (idleTimeout) {
1652
+ clearTimeout(idleTimeout);
1653
+ }
1654
+ idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
1655
+ };
1656
+ const onScrollEnd = () => finish("scrollend");
1657
+ node.addEventListener("scroll", onScroll2);
1630
1658
  if (supportsScrollEnd) {
1631
- node.addEventListener("scrollend", finish, { once: true });
1659
+ node.addEventListener("scrollend", onScrollEnd);
1660
+ maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1632
1661
  } else {
1633
- node.addEventListener("scroll", onScroll2);
1634
- idleTimeout = setTimeout(finish, SMOOTH_SCROLL_DURATION_MS);
1635
- maxTimeout = setTimeout(finish, SCROLL_END_MAX_MS);
1662
+ idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1663
+ maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1636
1664
  }
1637
- return cleanup;
1638
1665
  }
1639
1666
 
1640
1667
  // src/core/scrollTo.ts
@@ -1652,14 +1679,14 @@ function scrollTo(ctx, params) {
1652
1679
  clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1653
1680
  }
1654
1681
  let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1655
- offset = clampScrollOffset(ctx, offset);
1682
+ offset = clampScrollOffset(ctx, offset, scrollTarget);
1656
1683
  state.scrollHistory.length = 0;
1657
1684
  if (!noScrollingTo) {
1658
1685
  state.scrollingTo = scrollTarget;
1659
1686
  }
1660
1687
  state.scrollPending = offset;
1661
1688
  if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1662
- doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1689
+ doScrollTo(ctx, { animated, horizontal, offset });
1663
1690
  } else {
1664
1691
  state.scroll = offset;
1665
1692
  }
@@ -1702,7 +1729,8 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1702
1729
  const scrollDelta = Math.abs(newScroll - prevScroll);
1703
1730
  const scrollLength = state.scrollLength;
1704
1731
  const lastCalculated = state.scrollLastCalculate;
1705
- const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1732
+ const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
1733
+ const shouldUpdate = useAggressiveItemRecalculation || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1706
1734
  if (shouldUpdate) {
1707
1735
  state.scrollLastCalculate = state.scroll;
1708
1736
  state.ignoreScrollFromMVCPIgnored = false;
@@ -1747,43 +1775,106 @@ function requestAdjust(ctx, positionDiff, dataChanged) {
1747
1775
  }
1748
1776
 
1749
1777
  // src/core/mvcp.ts
1778
+ var MVCP_POSITION_EPSILON = 0.1;
1779
+ var MVCP_ANCHOR_LOCK_TTL_MS = 300;
1780
+ var MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE = 2;
1781
+ function resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) {
1782
+ if (!enableMVCPAnchorLock) {
1783
+ state.mvcpAnchorLock = void 0;
1784
+ return void 0;
1785
+ }
1786
+ const lock = state.mvcpAnchorLock;
1787
+ if (!lock) {
1788
+ return void 0;
1789
+ }
1790
+ const isExpired = now > lock.expiresAt;
1791
+ const isMissing = state.indexByKey.get(lock.id) === void 0;
1792
+ if (isExpired || isMissing || !mvcpData) {
1793
+ state.mvcpAnchorLock = void 0;
1794
+ return void 0;
1795
+ }
1796
+ return lock;
1797
+ }
1798
+ function updateAnchorLock(state, params) {
1799
+ {
1800
+ const { anchorId, anchorPosition, dataChanged, now, positionDiff } = params;
1801
+ const enableMVCPAnchorLock = !!dataChanged || !!state.mvcpAnchorLock;
1802
+ const mvcpData = state.props.maintainVisibleContentPosition.data;
1803
+ if (!enableMVCPAnchorLock || !mvcpData || state.scrollingTo || !anchorId || anchorPosition === void 0) {
1804
+ return;
1805
+ }
1806
+ const existingLock = state.mvcpAnchorLock;
1807
+ const quietPasses = !dataChanged && Math.abs(positionDiff) <= MVCP_POSITION_EPSILON && (existingLock == null ? void 0 : existingLock.id) === anchorId ? existingLock.quietPasses + 1 : 0;
1808
+ if (!dataChanged && quietPasses >= MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE) {
1809
+ state.mvcpAnchorLock = void 0;
1810
+ return;
1811
+ }
1812
+ state.mvcpAnchorLock = {
1813
+ expiresAt: now + MVCP_ANCHOR_LOCK_TTL_MS,
1814
+ id: anchorId,
1815
+ position: anchorPosition,
1816
+ quietPasses
1817
+ };
1818
+ }
1819
+ }
1750
1820
  function prepareMVCP(ctx, dataChanged) {
1751
1821
  const state = ctx.state;
1752
1822
  const { idsInView, positions, props } = state;
1753
1823
  const {
1754
1824
  maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll, shouldRestorePosition }
1755
1825
  } = props;
1826
+ const now = Date.now();
1827
+ const enableMVCPAnchorLock = (!!dataChanged || !!state.mvcpAnchorLock);
1756
1828
  const scrollingTo = state.scrollingTo;
1829
+ const anchorLock = resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) ;
1757
1830
  let prevPosition;
1758
1831
  let targetId;
1759
1832
  const idsInViewWithPositions = [];
1760
1833
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1761
1834
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1835
+ const isEndAnchoredScrollTarget = scrollTarget !== void 0 && state.props.data.length > 0 && scrollTarget >= state.props.data.length - 1 && (scrollingToViewPosition != null ? scrollingToViewPosition : 0) > 0;
1762
1836
  const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1763
1837
  const indexByKey = state.indexByKey;
1764
1838
  if (shouldMVCP) {
1765
- if (scrollTarget !== void 0) {
1839
+ if (anchorLock && scrollTarget === void 0) {
1840
+ targetId = anchorLock.id;
1841
+ prevPosition = anchorLock.position;
1842
+ } else if (scrollTarget !== void 0) {
1766
1843
  targetId = getId(state, scrollTarget);
1767
- } else if (idsInView.length > 0 && state.didContainersLayout) {
1768
- if (dataChanged) {
1769
- for (let i = 0; i < idsInView.length; i++) {
1770
- const id = idsInView[i];
1771
- const index = indexByKey.get(id);
1772
- if (index !== void 0) {
1773
- idsInViewWithPositions.push({ id, position: positions.get(id) });
1774
- }
1844
+ } else if (idsInView.length > 0 && state.didContainersLayout && !dataChanged) {
1845
+ targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
1846
+ }
1847
+ if (dataChanged && idsInView.length > 0 && state.didContainersLayout) {
1848
+ for (let i = 0; i < idsInView.length; i++) {
1849
+ const id = idsInView[i];
1850
+ const index = indexByKey.get(id);
1851
+ if (index !== void 0) {
1852
+ idsInViewWithPositions.push({ id, position: positions.get(id) });
1775
1853
  }
1776
- } else {
1777
- targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
1778
1854
  }
1779
1855
  }
1780
- if (targetId !== void 0) {
1856
+ if (targetId !== void 0 && prevPosition === void 0) {
1781
1857
  prevPosition = positions.get(targetId);
1782
1858
  }
1783
1859
  return () => {
1784
1860
  let positionDiff = 0;
1785
- if (dataChanged && targetId === void 0 && mvcpData) {
1786
- const data = state.props.data;
1861
+ let anchorIdForLock = anchorLock == null ? void 0 : anchorLock.id;
1862
+ let anchorPositionForLock;
1863
+ let skipTargetAnchor = false;
1864
+ const data = state.props.data;
1865
+ const shouldValidateLockedAnchor = dataChanged && mvcpData && scrollTarget === void 0 && targetId !== void 0 && (anchorLock == null ? void 0 : anchorLock.id) === targetId && shouldRestorePosition !== void 0;
1866
+ if (shouldValidateLockedAnchor && targetId !== void 0) {
1867
+ const index = indexByKey.get(targetId);
1868
+ if (index !== void 0) {
1869
+ const item = data[index];
1870
+ skipTargetAnchor = item === void 0 || !shouldRestorePosition(item, index, data);
1871
+ if (skipTargetAnchor && (anchorLock == null ? void 0 : anchorLock.id) === targetId) {
1872
+ state.mvcpAnchorLock = void 0;
1873
+ }
1874
+ }
1875
+ }
1876
+ const shouldUseFallbackVisibleAnchor = dataChanged && mvcpData && scrollTarget === void 0 && (targetId === void 0 || positions.get(targetId) === void 0 || skipTargetAnchor);
1877
+ if (shouldUseFallbackVisibleAnchor) {
1787
1878
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1788
1879
  const { id, position } = idsInViewWithPositions[i];
1789
1880
  const index = indexByKey.get(id);
@@ -1796,16 +1887,18 @@ function prepareMVCP(ctx, dataChanged) {
1796
1887
  const newPosition = positions.get(id);
1797
1888
  if (newPosition !== void 0) {
1798
1889
  positionDiff = newPosition - position;
1890
+ anchorIdForLock = id;
1891
+ anchorPositionForLock = newPosition;
1799
1892
  break;
1800
1893
  }
1801
1894
  }
1802
1895
  }
1803
- if (targetId !== void 0 && prevPosition !== void 0) {
1896
+ if (!skipTargetAnchor && targetId !== void 0 && prevPosition !== void 0) {
1804
1897
  const newPosition = positions.get(targetId);
1805
1898
  if (newPosition !== void 0) {
1806
1899
  const totalSize = getContentSize(ctx);
1807
1900
  let diff = newPosition - prevPosition;
1808
- if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1901
+ if (diff !== 0 && isEndAnchoredScrollTarget && state.scroll + state.scrollLength > totalSize) {
1809
1902
  if (diff > 0) {
1810
1903
  diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
1811
1904
  } else {
@@ -1813,20 +1906,29 @@ function prepareMVCP(ctx, dataChanged) {
1813
1906
  }
1814
1907
  }
1815
1908
  positionDiff = diff;
1909
+ anchorIdForLock = targetId;
1910
+ anchorPositionForLock = newPosition;
1816
1911
  }
1817
1912
  }
1818
1913
  if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1819
1914
  const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1820
1915
  const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1821
- if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1916
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== prevSize) {
1822
1917
  const diff = newSize - prevSize;
1823
1918
  if (diff !== 0) {
1824
- positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1919
+ positionDiff += diff * scrollingToViewPosition;
1825
1920
  scrollingTo.itemSize = newSize;
1826
1921
  }
1827
1922
  }
1828
1923
  }
1829
- if (Math.abs(positionDiff) > 0.1) {
1924
+ updateAnchorLock(state, {
1925
+ anchorId: anchorIdForLock,
1926
+ anchorPosition: anchorPositionForLock,
1927
+ dataChanged,
1928
+ now,
1929
+ positionDiff
1930
+ });
1931
+ if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
1830
1932
  requestAdjust(ctx, positionDiff);
1831
1933
  }
1832
1934
  };
@@ -2481,26 +2583,16 @@ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPositi
2481
2583
  // src/utils/setDidLayout.ts
2482
2584
  function setDidLayout(ctx) {
2483
2585
  const state = ctx.state;
2484
- const {
2485
- loadStartTime,
2486
- initialScroll,
2487
- props: { onLoad }
2488
- } = state;
2586
+ const { initialScroll } = state;
2489
2587
  state.queuedInitialLayout = true;
2490
2588
  checkAtBottom(ctx);
2491
- const setIt = () => {
2492
- setInitialRenderState(ctx, { didLayout: true });
2493
- if (onLoad) {
2494
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2495
- }
2496
- };
2497
2589
  if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
2498
2590
  const target = initialScroll;
2499
2591
  const runScroll = () => scrollToIndex(ctx, { ...target, animated: false });
2500
2592
  runScroll();
2501
2593
  requestAnimationFrame(runScroll);
2502
2594
  }
2503
- setIt();
2595
+ setInitialRenderState(ctx, { didLayout: true });
2504
2596
  }
2505
2597
 
2506
2598
  // src/core/calculateItemsInView.ts
@@ -2540,7 +2632,7 @@ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentSt
2540
2632
  }
2541
2633
  }
2542
2634
  }
2543
- function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2635
+ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2544
2636
  var _a3, _b, _c;
2545
2637
  const state = ctx.state;
2546
2638
  for (const containerIndex of state.stickyContainerPool) {
@@ -2561,13 +2653,13 @@ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentSt
2561
2653
  if (nextIndex) {
2562
2654
  const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
2563
2655
  const nextPos = nextId ? state.positions.get(nextId) : void 0;
2564
- shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
2656
+ shouldRecycle = nextPos !== void 0 && scroll > nextPos + drawDistance * 2;
2565
2657
  } else {
2566
2658
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2567
2659
  if (currentId) {
2568
2660
  const currentPos = state.positions.get(currentId);
2569
2661
  const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2570
- shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2662
+ shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + drawDistance * 3;
2571
2663
  }
2572
2664
  }
2573
2665
  if (shouldRecycle) {
@@ -2592,11 +2684,11 @@ function calculateItemsInView(ctx, params = {}) {
2592
2684
  props: {
2593
2685
  alwaysRenderIndicesArr,
2594
2686
  alwaysRenderIndicesSet,
2687
+ drawDistance,
2595
2688
  getItemType,
2596
2689
  itemsAreEqual,
2597
2690
  keyExtractor,
2598
- onStickyHeaderChange,
2599
- scrollBuffer
2691
+ onStickyHeaderChange
2600
2692
  },
2601
2693
  scrollForNextCalculateItemsInView,
2602
2694
  scrollLength,
@@ -2609,6 +2701,7 @@ function calculateItemsInView(ctx, params = {}) {
2609
2701
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2610
2702
  const alwaysRenderArr = alwaysRenderIndicesArr || [];
2611
2703
  const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
2704
+ const { dataChanged, doMVCP, forceFullItemPositions } = params;
2612
2705
  const prevNumContainers = peek$(ctx, "numContainers");
2613
2706
  if (!data || scrollLength === 0 || !prevNumContainers) {
2614
2707
  return;
@@ -2616,7 +2709,6 @@ function calculateItemsInView(ctx, params = {}) {
2616
2709
  const totalSize = getContentSize(ctx);
2617
2710
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
2618
2711
  const numColumns = peek$(ctx, "numColumns");
2619
- const { dataChanged, doMVCP, forceFullItemPositions } = params;
2620
2712
  const speed = getScrollVelocity(state);
2621
2713
  const scrollExtra = 0;
2622
2714
  const { queuedInitialLayout } = state;
@@ -2635,24 +2727,20 @@ function calculateItemsInView(ctx, params = {}) {
2635
2727
  if (scroll + scrollLength > totalSize) {
2636
2728
  scroll = Math.max(0, totalSize - scrollLength);
2637
2729
  }
2638
- if (ENABLE_DEBUG_VIEW) {
2639
- set$(ctx, "debugRawScroll", scrollState);
2640
- set$(ctx, "debugComputedScroll", scroll);
2641
- }
2642
2730
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2643
2731
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2644
2732
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2645
2733
  if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2646
2734
  set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2647
2735
  }
2648
- let scrollBufferTop = scrollBuffer;
2649
- let scrollBufferBottom = scrollBuffer;
2650
- if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
2651
- scrollBufferTop = scrollBuffer * 0.5;
2652
- scrollBufferBottom = scrollBuffer * 1.5;
2736
+ let scrollBufferTop = drawDistance;
2737
+ let scrollBufferBottom = drawDistance;
2738
+ if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
2739
+ scrollBufferTop = drawDistance * 0.5;
2740
+ scrollBufferBottom = drawDistance * 1.5;
2653
2741
  } else {
2654
- scrollBufferTop = scrollBuffer * 1.5;
2655
- scrollBufferBottom = scrollBuffer * 0.5;
2742
+ scrollBufferTop = drawDistance * 1.5;
2743
+ scrollBufferBottom = drawDistance * 0.5;
2656
2744
  }
2657
2745
  const scrollTopBuffered = scroll - scrollBufferTop;
2658
2746
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
@@ -2662,7 +2750,9 @@ function calculateItemsInView(ctx, params = {}) {
2662
2750
  if (top === null && bottom === null) {
2663
2751
  state.scrollForNextCalculateItemsInView = void 0;
2664
2752
  } else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2665
- return;
2753
+ if (!isInMVCPActiveMode(state)) {
2754
+ return;
2755
+ }
2666
2756
  }
2667
2757
  }
2668
2758
  const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
@@ -2894,7 +2984,7 @@ function calculateItemsInView(ctx, params = {}) {
2894
2984
  ctx,
2895
2985
  stickyIndicesArr,
2896
2986
  scroll,
2897
- scrollBuffer,
2987
+ drawDistance,
2898
2988
  currentStickyIdx,
2899
2989
  pendingRemoval,
2900
2990
  alwaysRenderSet
@@ -3001,12 +3091,17 @@ function checkFinishedScrollFrame(ctx) {
3001
3091
  state.animFrameCheckFinishedScroll = void 0;
3002
3092
  const scroll = state.scrollPending;
3003
3093
  const adjust = state.scrollAdjustHandler.getAdjust();
3004
- const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
3005
- const maxOffset = clampScrollOffset(ctx, scroll);
3094
+ const clampedTargetOffset = clampScrollOffset(
3095
+ ctx,
3096
+ scrollingTo.offset - (scrollingTo.viewOffset || 0),
3097
+ scrollingTo
3098
+ );
3099
+ const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
3006
3100
  const diff1 = Math.abs(scroll - clampedTargetOffset);
3007
3101
  const diff2 = Math.abs(diff1 - adjust);
3008
3102
  const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
3009
- if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
3103
+ const isAtTarget = diff1 < 1 || !scrollingTo.animated && diff2 < 1;
3104
+ if (isNotOverscrolled && isAtTarget) {
3010
3105
  finishScrollTo(ctx);
3011
3106
  }
3012
3107
  }
@@ -3150,10 +3245,10 @@ function doInitialAllocateContainers(ctx) {
3150
3245
  scrollLength,
3151
3246
  props: {
3152
3247
  data,
3248
+ drawDistance,
3153
3249
  getEstimatedItemSize,
3154
3250
  getFixedItemSize,
3155
3251
  getItemType,
3156
- scrollBuffer,
3157
3252
  numColumns,
3158
3253
  estimatedItemSize
3159
3254
  }
@@ -3175,7 +3270,7 @@ function doInitialAllocateContainers(ctx) {
3175
3270
  } else {
3176
3271
  averageItemSize = estimatedItemSize;
3177
3272
  }
3178
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize * numColumns);
3273
+ const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
3179
3274
  for (let i = 0; i < numContainers; i++) {
3180
3275
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
3181
3276
  set$(ctx, `containerColumn${i}`, -1);
@@ -3263,8 +3358,8 @@ function onScroll(ctx, event) {
3263
3358
  }
3264
3359
  }
3265
3360
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3266
- if (state.scrollingTo) {
3267
- const maxOffset = clampScrollOffset(ctx, newScroll);
3361
+ if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
3362
+ const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
3268
3363
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3269
3364
  newScroll = maxOffset;
3270
3365
  scrollTo(ctx, {
@@ -3317,7 +3412,7 @@ var ScrollAdjustHandler = class {
3317
3412
  if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3318
3413
  const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3319
3414
  targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3320
- targetScroll = clampScrollOffset(this.ctx, targetScroll);
3415
+ targetScroll = clampScrollOffset(this.ctx, targetScroll, scrollTarget);
3321
3416
  } else {
3322
3417
  targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3323
3418
  }
@@ -3336,6 +3431,26 @@ var ScrollAdjustHandler = class {
3336
3431
  };
3337
3432
 
3338
3433
  // src/core/updateItemSize.ts
3434
+ function runOrScheduleMVCPRecalculate(ctx) {
3435
+ const state = ctx.state;
3436
+ {
3437
+ if (!state.mvcpAnchorLock) {
3438
+ if (state.queuedMVCPRecalculate !== void 0) {
3439
+ cancelAnimationFrame(state.queuedMVCPRecalculate);
3440
+ state.queuedMVCPRecalculate = void 0;
3441
+ }
3442
+ calculateItemsInView(ctx, { doMVCP: true });
3443
+ return;
3444
+ }
3445
+ if (state.queuedMVCPRecalculate !== void 0) {
3446
+ return;
3447
+ }
3448
+ state.queuedMVCPRecalculate = requestAnimationFrame(() => {
3449
+ state.queuedMVCPRecalculate = void 0;
3450
+ calculateItemsInView(ctx, { doMVCP: true });
3451
+ });
3452
+ }
3453
+ }
3339
3454
  function updateItemSize(ctx, itemKey, sizeObj) {
3340
3455
  var _a3;
3341
3456
  const state = ctx.state;
@@ -3419,7 +3534,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
3419
3534
  if (didContainersLayout || checkAllSizesKnown(state)) {
3420
3535
  if (needsRecalculate) {
3421
3536
  state.scrollForNextCalculateItemsInView = void 0;
3422
- calculateItemsInView(ctx, { doMVCP: true });
3537
+ runOrScheduleMVCPRecalculate(ctx);
3423
3538
  }
3424
3539
  if (shouldMaintainScrollAtEnd) {
3425
3540
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
@@ -3531,7 +3646,30 @@ function createImperativeHandle(ctx) {
3531
3646
  }
3532
3647
  };
3533
3648
  const refScroller = state.refScroller;
3649
+ const clearCaches = (options) => {
3650
+ var _a3, _b;
3651
+ const mode = (_a3 = options == null ? void 0 : options.mode) != null ? _a3 : "sizes";
3652
+ state.sizes.clear();
3653
+ state.sizesKnown.clear();
3654
+ for (const key in state.averageSizes) {
3655
+ delete state.averageSizes[key];
3656
+ }
3657
+ state.minIndexSizeChanged = 0;
3658
+ state.scrollForNextCalculateItemsInView = void 0;
3659
+ state.pendingTotalSize = void 0;
3660
+ state.totalSize = 0;
3661
+ set$(ctx, "totalSize", 0);
3662
+ if (mode === "full") {
3663
+ state.indexByKey.clear();
3664
+ state.idCache.length = 0;
3665
+ state.positions.clear();
3666
+ state.columns.clear();
3667
+ state.columnSpans.clear();
3668
+ }
3669
+ (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
3670
+ };
3534
3671
  return {
3672
+ clearCaches,
3535
3673
  flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3536
3674
  getNativeScrollRef: () => refScroller.current,
3537
3675
  getScrollableNode: () => refScroller.current.getScrollableNode(),
@@ -3692,8 +3830,8 @@ function normalizeMaintainVisibleContentPosition(value) {
3692
3830
  if (value && typeof value === "object") {
3693
3831
  return {
3694
3832
  data: (_a3 = value.data) != null ? _a3 : false,
3695
- size: (_b = value.size) != null ? _b : true,
3696
- shouldRestorePosition: value.shouldRestorePosition
3833
+ shouldRestorePosition: value.shouldRestorePosition,
3834
+ size: (_b = value.size) != null ? _b : true
3697
3835
  };
3698
3836
  }
3699
3837
  if (value === false) {
@@ -3765,8 +3903,6 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3765
3903
  }
3766
3904
 
3767
3905
  // src/components/LegendList.tsx
3768
- var DEFAULT_DRAW_DISTANCE = 250;
3769
- var DEFAULT_ITEM_SIZE = 100;
3770
3906
  var LegendList = typedMemo(
3771
3907
  // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3772
3908
  typedForwardRef(function LegendList2(props, forwardedRef) {
@@ -3796,7 +3932,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3796
3932
  data: dataProp = [],
3797
3933
  dataVersion,
3798
3934
  drawDistance = 250,
3799
- estimatedItemSize: estimatedItemSizeProp,
3935
+ estimatedItemSize = 100,
3800
3936
  estimatedListSize,
3801
3937
  extraData,
3802
3938
  getEstimatedItemSize,
@@ -3848,7 +3984,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3848
3984
  ...rest
3849
3985
  } = props;
3850
3986
  const animatedPropsInternal = props.animatedPropsInternal;
3851
- const { childrenMode } = rest;
3987
+ const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
3988
+ const {
3989
+ childrenMode,
3990
+ stickyPositionComponentInternal: _stickyPositionComponentInternal,
3991
+ ...restProps
3992
+ } = rest;
3852
3993
  const contentContainerStyleBase = StyleSheet.flatten(contentContainerStyleProp);
3853
3994
  const shouldFlexGrow = alignItemsAtEnd && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
3854
3995
  const contentContainerStyle = {
@@ -3875,14 +4016,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3875
4016
  index: initialScrollIndexProp || 0,
3876
4017
  viewOffset: initialScrollOffsetProp || 0
3877
4018
  } : void 0;
3878
- const [canRender, setCanRender] = React3.useState(!IsNewArchitecture);
4019
+ const [canRender, setCanRender] = React3.useState(false);
3879
4020
  const ctx = useStateContext();
3880
4021
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
3881
4022
  const refScroller = useRef(null);
3882
4023
  const combinedRef = useCombinedRef(refScroller, refScrollView);
3883
- const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
3884
- const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
3885
- const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
4024
+ const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
3886
4025
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
3887
4026
  const alwaysRenderIndices = useMemo(() => {
3888
4027
  const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor);
@@ -3911,8 +4050,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3911
4050
  ctx.state = {
3912
4051
  activeStickyIndex: -1,
3913
4052
  averageSizes: {},
3914
- columns: /* @__PURE__ */ new Map(),
3915
4053
  columnSpans: /* @__PURE__ */ new Map(),
4054
+ columns: /* @__PURE__ */ new Map(),
3916
4055
  containerItemKeys: /* @__PURE__ */ new Map(),
3917
4056
  containerItemTypes: /* @__PURE__ */ new Map(),
3918
4057
  contentInsetOverride: void 0,
@@ -3999,6 +4138,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3999
4138
  contentInset,
4000
4139
  data: dataProp,
4001
4140
  dataVersion,
4141
+ drawDistance,
4002
4142
  estimatedItemSize,
4003
4143
  getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
4004
4144
  getFixedItemSize: useWrapIfItem(getFixedItemSize),
@@ -4022,10 +4162,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4022
4162
  overrideItemLayout,
4023
4163
  recycleItems: !!recycleItems,
4024
4164
  renderItem,
4025
- scrollBuffer,
4026
4165
  snapToIndices,
4027
4166
  stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
4028
4167
  stickyIndicesSet: useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
4168
+ stickyPositionComponentInternal,
4029
4169
  stylePaddingBottom: stylePaddingBottomState,
4030
4170
  stylePaddingTop: stylePaddingTopState,
4031
4171
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
@@ -4045,12 +4185,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4045
4185
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
4046
4186
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
4047
4187
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
4048
- if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
4049
- if (state.scroll < 0) {
4050
- paddingDiff += state.scroll;
4051
- }
4052
- requestAdjust(ctx, paddingDiff);
4053
- }
4188
+ if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") ;
4054
4189
  };
4055
4190
  if (isFirstLocal) {
4056
4191
  initializeStateVars(false);
@@ -4069,7 +4204,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4069
4204
  } else {
4070
4205
  const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
4071
4206
  const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
4072
- const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
4207
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset, initialScroll);
4073
4208
  const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
4074
4209
  refState.current.initialScroll = updatedInitialScroll;
4075
4210
  state.initialScroll = updatedInitialScroll;
@@ -4218,7 +4353,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4218
4353
  return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
4219
4354
  ListComponent,
4220
4355
  {
4221
- ...rest,
4356
+ ...restProps,
4222
4357
  alignItemsAtEnd,
4223
4358
  canRender,
4224
4359
  contentContainerStyle,
@@ -4252,7 +4387,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4252
4387
  updateItemSize: fns.updateItemSize,
4253
4388
  waitForInitialLayout
4254
4389
  }
4255
- ), IS_DEV && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3.createElement(DebugView, { state: refState.current }));
4390
+ ), IS_DEV && ENABLE_DEBUG_VIEW);
4256
4391
  });
4257
4392
 
4258
- export { LegendList, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
4393
+ // src/index.ts
4394
+ var LegendList3 = LegendList;
4395
+ if (IS_DEV) {
4396
+ console.warn(
4397
+ "[legend-list] Legend List 3.0 deprecates the root import (@legendapp/list) because it now supports both react and react-native. The root import is fully functional, but please switch to platform-specific imports for strict platform types:\n - React Native: @legendapp/list/react-native\n - React: @legendapp/list/react\nSee README for details."
4398
+ );
4399
+ }
4400
+
4401
+ export { LegendList3 as LegendList, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };