@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.js CHANGED
@@ -42,7 +42,7 @@ function getContentInsetEnd(state) {
42
42
  const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
43
43
  const overrideInset = (_a3 = state.contentInsetOverride) != null ? _a3 : void 0;
44
44
  if (overrideInset) {
45
- const mergedInset = { bottom: 0, left: 0, right: 0, top: 0, ...baseInset, ...overrideInset };
45
+ const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
46
46
  return (horizontal ? mergedInset.right : mergedInset.bottom) || 0;
47
47
  }
48
48
  if (baseInset) {
@@ -193,7 +193,7 @@ function useSelector$(signalName, selector) {
193
193
  var DebugRow = ({ children }) => {
194
194
  return /* @__PURE__ */ React3__namespace.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
195
195
  };
196
- var DebugView = React3__namespace.memo(function DebugView2({ state }) {
196
+ React3__namespace.memo(function DebugView2({ state }) {
197
197
  const ctx = useStateContext();
198
198
  const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
199
199
  "totalSize",
@@ -245,7 +245,7 @@ var _a;
245
245
  var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
246
246
  var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
247
247
  var _a2;
248
- var IS_DEV = (_a2 = metroDev != null ? metroDev : processDev) != null ? _a2 : false;
248
+ var IS_DEV = (_a2 = processDev != null ? processDev : metroDev) != null ? _a2 : false;
249
249
 
250
250
  // src/constants.ts
251
251
  var POSITION_OUT_OF_VIEW = -1e7;
@@ -328,7 +328,10 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
328
328
  children,
329
329
  ...rest
330
330
  }) {
331
- const [position = POSITION_OUT_OF_VIEW, activeStickyIndex] = useArr$([`containerPosition${id}`, "activeStickyIndex"]);
331
+ const [position = POSITION_OUT_OF_VIEW, activeStickyIndex] = useArr$([
332
+ `containerPosition${id}`,
333
+ "activeStickyIndex"
334
+ ]);
332
335
  const base = {
333
336
  contain: "paint layout style"
334
337
  };
@@ -358,9 +361,6 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
358
361
  return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
359
362
  });
360
363
  var PositionView = PositionViewState;
361
-
362
- // src/constants-platform.ts
363
- var IsNewArchitecture = true;
364
364
  function useInit(cb) {
365
365
  React3.useState(() => cb());
366
366
  }
@@ -571,7 +571,8 @@ function createResizeObserver(element, callback) {
571
571
  function useOnLayoutSync({
572
572
  ref,
573
573
  onLayoutProp,
574
- onLayoutChange
574
+ onLayoutChange,
575
+ webLayoutResync
575
576
  }, deps) {
576
577
  React3.useLayoutEffect(() => {
577
578
  var _a3, _b;
@@ -595,7 +596,9 @@ function useOnLayoutSync({
595
596
  var _a4;
596
597
  const target = entry.target instanceof HTMLElement ? entry.target : void 0;
597
598
  const rectObserved = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
598
- if (rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height) {
599
+ const didSizeChange = rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height;
600
+ const shouldResyncLayout = !!(webLayoutResync == null ? void 0 : webLayoutResync());
601
+ if (didSizeChange || shouldResyncLayout) {
599
602
  prevRect = rectObserved;
600
603
  emit(toLayout(rectObserved), false);
601
604
  }
@@ -621,6 +624,15 @@ var Platform = {
621
624
  OS: "web"
622
625
  };
623
626
 
627
+ // src/utils/isInMVCPActiveMode.ts
628
+ function isInMVCPActiveMode(state) {
629
+ const lock = state.mvcpAnchorLock;
630
+ if (lock && Date.now() > lock.expiresAt) {
631
+ state.mvcpAnchorLock = void 0;
632
+ }
633
+ return state.dataChangeNeedsScrollUpdate || !!state.mvcpAnchorLock;
634
+ }
635
+
624
636
  // src/components/Container.tsx
625
637
  var Container = typedMemo(function Container2({
626
638
  id,
@@ -633,6 +645,7 @@ var Container = typedMemo(function Container2({
633
645
  }) {
634
646
  const ctx = useStateContext();
635
647
  const { columnWrapperStyle, animatedScrollY } = ctx;
648
+ const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
636
649
  const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
637
650
  `containerColumn${id}`,
638
651
  `containerSpan${id}`,
@@ -728,7 +741,8 @@ var Container = typedMemo(function Container2({
728
741
  updateItemSizeFn(currentItemKey, layout);
729
742
  itemLayoutRef.current.didLayout = true;
730
743
  };
731
- if (prevSize !== void 0 && size + 1 < prevSize) {
744
+ const shouldDeferWebShrinkLayoutUpdate = !isInMVCPActiveMode(ctx.state) && prevSize !== void 0 && size + 1 < prevSize;
745
+ if (shouldDeferWebShrinkLayoutUpdate) {
732
746
  const token = pendingShrinkToken + 1;
733
747
  itemLayoutRef.current.pendingShrinkToken = token;
734
748
  requestAnimationFrame(() => {
@@ -752,11 +766,12 @@ var Container = typedMemo(function Container2({
752
766
  const { onLayout } = useOnLayoutSync(
753
767
  {
754
768
  onLayoutChange,
755
- ref
769
+ ref,
770
+ webLayoutResync: () => isInMVCPActiveMode(ctx.state)
756
771
  },
757
772
  [itemKey, layoutRenderCount]
758
773
  );
759
- const PositionComponent = isSticky ? PositionViewSticky : PositionView;
774
+ const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : PositionView;
760
775
  return /* @__PURE__ */ React3__namespace.createElement(
761
776
  PositionComponent,
762
777
  {
@@ -944,25 +959,6 @@ var Containers = typedMemo(function Containers2({
944
959
  }
945
960
  return /* @__PURE__ */ React3__namespace.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
946
961
  });
947
- function DevNumbers() {
948
- return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
949
- React3__namespace.memo(function DevNumbers2() {
950
- return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3__namespace.createElement(
951
- "div",
952
- {
953
- key: index,
954
- style: {
955
- height: 100,
956
- pointerEvents: "none",
957
- position: "absolute",
958
- top: index * 100,
959
- width: "100%"
960
- }
961
- },
962
- /* @__PURE__ */ React3__namespace.createElement("div", { style: { color: "red" } }, index * 100)
963
- ));
964
- });
965
- }
966
962
 
967
963
  // src/platform/StyleSheet.tsx
968
964
  function flattenStyles(styles) {
@@ -1137,6 +1133,7 @@ function useValueListener$(key, callback) {
1137
1133
  function ScrollAdjust() {
1138
1134
  const ctx = useStateContext();
1139
1135
  const lastScrollOffsetRef = React3__namespace.useRef(0);
1136
+ const resetPaddingRafRef = React3__namespace.useRef(void 0);
1140
1137
  const callback = React3__namespace.useCallback(() => {
1141
1138
  var _a3;
1142
1139
  const scrollAdjust = peek$(ctx, "scrollAdjust");
@@ -1151,13 +1148,17 @@ function ScrollAdjust() {
1151
1148
  const nextScroll = prevScroll + scrollDelta;
1152
1149
  const totalSize = el.scrollHeight;
1153
1150
  if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1151
+ const paddingBottom = ctx.state.props.stylePaddingBottom || 0;
1154
1152
  const child = el.firstElementChild;
1155
1153
  const pad = (nextScroll + el.clientHeight - totalSize) * 2;
1156
1154
  child.style.paddingBottom = `${pad}px`;
1157
1155
  void el.offsetHeight;
1158
1156
  scrollView.scrollBy(0, scrollDelta);
1159
- requestAnimationFrame(() => {
1160
- const paddingBottom = ctx.state.props.stylePaddingBottom;
1157
+ if (resetPaddingRafRef.current !== void 0) {
1158
+ cancelAnimationFrame(resetPaddingRafRef.current);
1159
+ }
1160
+ resetPaddingRafRef.current = requestAnimationFrame(() => {
1161
+ resetPaddingRafRef.current = void 0;
1161
1162
  child.style.paddingBottom = paddingBottom ? `${paddingBottom}px` : "0";
1162
1163
  });
1163
1164
  } else {
@@ -1222,7 +1223,9 @@ var ListComponent = typedMemo(function ListComponent2({
1222
1223
  const ctx = useStateContext();
1223
1224
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1224
1225
  const ScrollComponent = renderScrollComponent ? React3.useMemo(
1225
- () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1226
+ () => React3__namespace.forwardRef(
1227
+ (props, ref) => renderScrollComponent({ ...props, ref })
1228
+ ),
1226
1229
  [renderScrollComponent]
1227
1230
  ) : ListComponentScrollView;
1228
1231
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
@@ -1279,7 +1282,7 @@ var ListComponent = typedMemo(function ListComponent2({
1279
1282
  },
1280
1283
  getComponent(ListFooterComponent)
1281
1284
  ),
1282
- IS_DEV && ENABLE_DEVMODE && /* @__PURE__ */ React3__namespace.createElement(DevNumbers, null)
1285
+ IS_DEV && ENABLE_DEVMODE
1283
1286
  );
1284
1287
  });
1285
1288
 
@@ -1413,12 +1416,15 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1413
1416
  }
1414
1417
 
1415
1418
  // src/core/clampScrollOffset.ts
1416
- function clampScrollOffset(ctx, offset) {
1419
+ function clampScrollOffset(ctx, offset, scrollTarget) {
1417
1420
  const state = ctx.state;
1418
1421
  const contentSize = getContentSize(ctx);
1419
1422
  let clampedOffset = offset;
1420
1423
  if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android")) {
1421
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1424
+ const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
1425
+ const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
1426
+ const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
1427
+ const maxOffset = baseMaxOffset + extraEndOffset;
1422
1428
  clampedOffset = Math.min(offset, maxOffset);
1423
1429
  }
1424
1430
  clampedOffset = Math.max(0, clampedOffset);
@@ -1513,7 +1519,7 @@ function checkAtBottom(ctx) {
1513
1519
  function checkAtTop(ctx) {
1514
1520
  var _a3;
1515
1521
  const state = ctx == null ? void 0 : ctx.state;
1516
- if (!state || state.initialScroll) {
1522
+ if (!state || state.initialScroll || state.scrollingTo) {
1517
1523
  return;
1518
1524
  }
1519
1525
  const {
@@ -1557,14 +1563,22 @@ function setInitialRenderState(ctx, {
1557
1563
  didInitialScroll
1558
1564
  }) {
1559
1565
  const { state } = ctx;
1566
+ const {
1567
+ loadStartTime,
1568
+ props: { onLoad }
1569
+ } = state;
1560
1570
  if (didLayout) {
1561
1571
  state.didContainersLayout = true;
1562
1572
  }
1563
1573
  if (didInitialScroll) {
1564
1574
  state.didFinishInitialScroll = true;
1565
1575
  }
1566
- if (state.didContainersLayout && state.didFinishInitialScroll) {
1576
+ const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
1577
+ if (isReadyToRender && !peek$(ctx, "readyToRender")) {
1567
1578
  set$(ctx, "readyToRender", true);
1579
+ if (onLoad) {
1580
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1581
+ }
1568
1582
  }
1569
1583
  }
1570
1584
 
@@ -1596,6 +1610,7 @@ function finishScrollTo(ctx) {
1596
1610
  var SCROLL_END_IDLE_MS = 80;
1597
1611
  var SCROLL_END_MAX_MS = 1500;
1598
1612
  var SMOOTH_SCROLL_DURATION_MS = 320;
1613
+ var SCROLL_END_TARGET_EPSILON = 1;
1599
1614
  function doScrollTo(ctx, params) {
1600
1615
  const state = ctx.state;
1601
1616
  const { animated, horizontal, offset } = params;
@@ -1606,7 +1621,10 @@ function doScrollTo(ctx, params) {
1606
1621
  const top = horizontal ? 0 : offset;
1607
1622
  node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1608
1623
  if (animated) {
1609
- listenForScrollEnd(ctx, node);
1624
+ listenForScrollEnd(ctx, node, {
1625
+ horizontal: !!horizontal,
1626
+ targetOffset: offset
1627
+ });
1610
1628
  } else {
1611
1629
  state.scroll = offset;
1612
1630
  setTimeout(() => {
@@ -1615,31 +1633,17 @@ function doScrollTo(ctx, params) {
1615
1633
  }
1616
1634
  }
1617
1635
  }
1618
- function listenForScrollEnd(ctx, node) {
1636
+ function listenForScrollEnd(ctx, node, params) {
1637
+ const { horizontal, targetOffset } = params;
1619
1638
  const supportsScrollEnd = "onscrollend" in node;
1620
1639
  let idleTimeout;
1621
1640
  let maxTimeout;
1622
1641
  let settled = false;
1623
1642
  const targetToken = ctx.state.scrollingTo;
1624
- const finish = () => {
1625
- if (settled) return;
1626
- settled = true;
1627
- cleanup();
1628
- if (targetToken === ctx.state.scrollingTo) {
1629
- finishScrollTo(ctx);
1630
- }
1631
- };
1632
- const onScroll2 = () => {
1633
- if (idleTimeout) {
1634
- clearTimeout(idleTimeout);
1635
- }
1636
- idleTimeout = setTimeout(finish, SCROLL_END_IDLE_MS);
1637
- };
1638
1643
  const cleanup = () => {
1644
+ node.removeEventListener("scroll", onScroll2);
1639
1645
  if (supportsScrollEnd) {
1640
- node.removeEventListener("scrollend", finish);
1641
- } else {
1642
- node.removeEventListener("scroll", onScroll2);
1646
+ node.removeEventListener("scrollend", onScrollEnd);
1643
1647
  }
1644
1648
  if (idleTimeout) {
1645
1649
  clearTimeout(idleTimeout);
@@ -1648,14 +1652,37 @@ function listenForScrollEnd(ctx, node) {
1648
1652
  clearTimeout(maxTimeout);
1649
1653
  }
1650
1654
  };
1655
+ const finish = (reason) => {
1656
+ if (settled) return;
1657
+ if (targetToken !== ctx.state.scrollingTo) {
1658
+ settled = true;
1659
+ cleanup();
1660
+ return;
1661
+ }
1662
+ const currentOffset = horizontal ? node.scrollLeft : node.scrollTop;
1663
+ const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
1664
+ if (reason === "scrollend" && !isNearTarget) {
1665
+ return;
1666
+ }
1667
+ settled = true;
1668
+ cleanup();
1669
+ finishScrollTo(ctx);
1670
+ };
1671
+ const onScroll2 = () => {
1672
+ if (idleTimeout) {
1673
+ clearTimeout(idleTimeout);
1674
+ }
1675
+ idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
1676
+ };
1677
+ const onScrollEnd = () => finish("scrollend");
1678
+ node.addEventListener("scroll", onScroll2);
1651
1679
  if (supportsScrollEnd) {
1652
- node.addEventListener("scrollend", finish, { once: true });
1680
+ node.addEventListener("scrollend", onScrollEnd);
1681
+ maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1653
1682
  } else {
1654
- node.addEventListener("scroll", onScroll2);
1655
- idleTimeout = setTimeout(finish, SMOOTH_SCROLL_DURATION_MS);
1656
- maxTimeout = setTimeout(finish, SCROLL_END_MAX_MS);
1683
+ idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1684
+ maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1657
1685
  }
1658
- return cleanup;
1659
1686
  }
1660
1687
 
1661
1688
  // src/core/scrollTo.ts
@@ -1673,14 +1700,14 @@ function scrollTo(ctx, params) {
1673
1700
  clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1674
1701
  }
1675
1702
  let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1676
- offset = clampScrollOffset(ctx, offset);
1703
+ offset = clampScrollOffset(ctx, offset, scrollTarget);
1677
1704
  state.scrollHistory.length = 0;
1678
1705
  if (!noScrollingTo) {
1679
1706
  state.scrollingTo = scrollTarget;
1680
1707
  }
1681
1708
  state.scrollPending = offset;
1682
1709
  if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1683
- doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1710
+ doScrollTo(ctx, { animated, horizontal, offset });
1684
1711
  } else {
1685
1712
  state.scroll = offset;
1686
1713
  }
@@ -1723,7 +1750,8 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1723
1750
  const scrollDelta = Math.abs(newScroll - prevScroll);
1724
1751
  const scrollLength = state.scrollLength;
1725
1752
  const lastCalculated = state.scrollLastCalculate;
1726
- const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1753
+ const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
1754
+ const shouldUpdate = useAggressiveItemRecalculation || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1727
1755
  if (shouldUpdate) {
1728
1756
  state.scrollLastCalculate = state.scroll;
1729
1757
  state.ignoreScrollFromMVCPIgnored = false;
@@ -1768,43 +1796,106 @@ function requestAdjust(ctx, positionDiff, dataChanged) {
1768
1796
  }
1769
1797
 
1770
1798
  // src/core/mvcp.ts
1799
+ var MVCP_POSITION_EPSILON = 0.1;
1800
+ var MVCP_ANCHOR_LOCK_TTL_MS = 300;
1801
+ var MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE = 2;
1802
+ function resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) {
1803
+ if (!enableMVCPAnchorLock) {
1804
+ state.mvcpAnchorLock = void 0;
1805
+ return void 0;
1806
+ }
1807
+ const lock = state.mvcpAnchorLock;
1808
+ if (!lock) {
1809
+ return void 0;
1810
+ }
1811
+ const isExpired = now > lock.expiresAt;
1812
+ const isMissing = state.indexByKey.get(lock.id) === void 0;
1813
+ if (isExpired || isMissing || !mvcpData) {
1814
+ state.mvcpAnchorLock = void 0;
1815
+ return void 0;
1816
+ }
1817
+ return lock;
1818
+ }
1819
+ function updateAnchorLock(state, params) {
1820
+ {
1821
+ const { anchorId, anchorPosition, dataChanged, now, positionDiff } = params;
1822
+ const enableMVCPAnchorLock = !!dataChanged || !!state.mvcpAnchorLock;
1823
+ const mvcpData = state.props.maintainVisibleContentPosition.data;
1824
+ if (!enableMVCPAnchorLock || !mvcpData || state.scrollingTo || !anchorId || anchorPosition === void 0) {
1825
+ return;
1826
+ }
1827
+ const existingLock = state.mvcpAnchorLock;
1828
+ const quietPasses = !dataChanged && Math.abs(positionDiff) <= MVCP_POSITION_EPSILON && (existingLock == null ? void 0 : existingLock.id) === anchorId ? existingLock.quietPasses + 1 : 0;
1829
+ if (!dataChanged && quietPasses >= MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE) {
1830
+ state.mvcpAnchorLock = void 0;
1831
+ return;
1832
+ }
1833
+ state.mvcpAnchorLock = {
1834
+ expiresAt: now + MVCP_ANCHOR_LOCK_TTL_MS,
1835
+ id: anchorId,
1836
+ position: anchorPosition,
1837
+ quietPasses
1838
+ };
1839
+ }
1840
+ }
1771
1841
  function prepareMVCP(ctx, dataChanged) {
1772
1842
  const state = ctx.state;
1773
1843
  const { idsInView, positions, props } = state;
1774
1844
  const {
1775
1845
  maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll, shouldRestorePosition }
1776
1846
  } = props;
1847
+ const now = Date.now();
1848
+ const enableMVCPAnchorLock = (!!dataChanged || !!state.mvcpAnchorLock);
1777
1849
  const scrollingTo = state.scrollingTo;
1850
+ const anchorLock = resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) ;
1778
1851
  let prevPosition;
1779
1852
  let targetId;
1780
1853
  const idsInViewWithPositions = [];
1781
1854
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1782
1855
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1856
+ const isEndAnchoredScrollTarget = scrollTarget !== void 0 && state.props.data.length > 0 && scrollTarget >= state.props.data.length - 1 && (scrollingToViewPosition != null ? scrollingToViewPosition : 0) > 0;
1783
1857
  const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1784
1858
  const indexByKey = state.indexByKey;
1785
1859
  if (shouldMVCP) {
1786
- if (scrollTarget !== void 0) {
1860
+ if (anchorLock && scrollTarget === void 0) {
1861
+ targetId = anchorLock.id;
1862
+ prevPosition = anchorLock.position;
1863
+ } else if (scrollTarget !== void 0) {
1787
1864
  targetId = getId(state, scrollTarget);
1788
- } else if (idsInView.length > 0 && state.didContainersLayout) {
1789
- if (dataChanged) {
1790
- for (let i = 0; i < idsInView.length; i++) {
1791
- const id = idsInView[i];
1792
- const index = indexByKey.get(id);
1793
- if (index !== void 0) {
1794
- idsInViewWithPositions.push({ id, position: positions.get(id) });
1795
- }
1865
+ } else if (idsInView.length > 0 && state.didContainersLayout && !dataChanged) {
1866
+ targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
1867
+ }
1868
+ if (dataChanged && idsInView.length > 0 && state.didContainersLayout) {
1869
+ for (let i = 0; i < idsInView.length; i++) {
1870
+ const id = idsInView[i];
1871
+ const index = indexByKey.get(id);
1872
+ if (index !== void 0) {
1873
+ idsInViewWithPositions.push({ id, position: positions.get(id) });
1796
1874
  }
1797
- } else {
1798
- targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
1799
1875
  }
1800
1876
  }
1801
- if (targetId !== void 0) {
1877
+ if (targetId !== void 0 && prevPosition === void 0) {
1802
1878
  prevPosition = positions.get(targetId);
1803
1879
  }
1804
1880
  return () => {
1805
1881
  let positionDiff = 0;
1806
- if (dataChanged && targetId === void 0 && mvcpData) {
1807
- const data = state.props.data;
1882
+ let anchorIdForLock = anchorLock == null ? void 0 : anchorLock.id;
1883
+ let anchorPositionForLock;
1884
+ let skipTargetAnchor = false;
1885
+ const data = state.props.data;
1886
+ const shouldValidateLockedAnchor = dataChanged && mvcpData && scrollTarget === void 0 && targetId !== void 0 && (anchorLock == null ? void 0 : anchorLock.id) === targetId && shouldRestorePosition !== void 0;
1887
+ if (shouldValidateLockedAnchor && targetId !== void 0) {
1888
+ const index = indexByKey.get(targetId);
1889
+ if (index !== void 0) {
1890
+ const item = data[index];
1891
+ skipTargetAnchor = item === void 0 || !shouldRestorePosition(item, index, data);
1892
+ if (skipTargetAnchor && (anchorLock == null ? void 0 : anchorLock.id) === targetId) {
1893
+ state.mvcpAnchorLock = void 0;
1894
+ }
1895
+ }
1896
+ }
1897
+ const shouldUseFallbackVisibleAnchor = dataChanged && mvcpData && scrollTarget === void 0 && (targetId === void 0 || positions.get(targetId) === void 0 || skipTargetAnchor);
1898
+ if (shouldUseFallbackVisibleAnchor) {
1808
1899
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1809
1900
  const { id, position } = idsInViewWithPositions[i];
1810
1901
  const index = indexByKey.get(id);
@@ -1817,16 +1908,18 @@ function prepareMVCP(ctx, dataChanged) {
1817
1908
  const newPosition = positions.get(id);
1818
1909
  if (newPosition !== void 0) {
1819
1910
  positionDiff = newPosition - position;
1911
+ anchorIdForLock = id;
1912
+ anchorPositionForLock = newPosition;
1820
1913
  break;
1821
1914
  }
1822
1915
  }
1823
1916
  }
1824
- if (targetId !== void 0 && prevPosition !== void 0) {
1917
+ if (!skipTargetAnchor && targetId !== void 0 && prevPosition !== void 0) {
1825
1918
  const newPosition = positions.get(targetId);
1826
1919
  if (newPosition !== void 0) {
1827
1920
  const totalSize = getContentSize(ctx);
1828
1921
  let diff = newPosition - prevPosition;
1829
- if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1922
+ if (diff !== 0 && isEndAnchoredScrollTarget && state.scroll + state.scrollLength > totalSize) {
1830
1923
  if (diff > 0) {
1831
1924
  diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
1832
1925
  } else {
@@ -1834,20 +1927,29 @@ function prepareMVCP(ctx, dataChanged) {
1834
1927
  }
1835
1928
  }
1836
1929
  positionDiff = diff;
1930
+ anchorIdForLock = targetId;
1931
+ anchorPositionForLock = newPosition;
1837
1932
  }
1838
1933
  }
1839
1934
  if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1840
1935
  const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1841
1936
  const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1842
- if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1937
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== prevSize) {
1843
1938
  const diff = newSize - prevSize;
1844
1939
  if (diff !== 0) {
1845
- positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1940
+ positionDiff += diff * scrollingToViewPosition;
1846
1941
  scrollingTo.itemSize = newSize;
1847
1942
  }
1848
1943
  }
1849
1944
  }
1850
- if (Math.abs(positionDiff) > 0.1) {
1945
+ updateAnchorLock(state, {
1946
+ anchorId: anchorIdForLock,
1947
+ anchorPosition: anchorPositionForLock,
1948
+ dataChanged,
1949
+ now,
1950
+ positionDiff
1951
+ });
1952
+ if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
1851
1953
  requestAdjust(ctx, positionDiff);
1852
1954
  }
1853
1955
  };
@@ -2502,26 +2604,16 @@ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPositi
2502
2604
  // src/utils/setDidLayout.ts
2503
2605
  function setDidLayout(ctx) {
2504
2606
  const state = ctx.state;
2505
- const {
2506
- loadStartTime,
2507
- initialScroll,
2508
- props: { onLoad }
2509
- } = state;
2607
+ const { initialScroll } = state;
2510
2608
  state.queuedInitialLayout = true;
2511
2609
  checkAtBottom(ctx);
2512
- const setIt = () => {
2513
- setInitialRenderState(ctx, { didLayout: true });
2514
- if (onLoad) {
2515
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2516
- }
2517
- };
2518
2610
  if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
2519
2611
  const target = initialScroll;
2520
2612
  const runScroll = () => scrollToIndex(ctx, { ...target, animated: false });
2521
2613
  runScroll();
2522
2614
  requestAnimationFrame(runScroll);
2523
2615
  }
2524
- setIt();
2616
+ setInitialRenderState(ctx, { didLayout: true });
2525
2617
  }
2526
2618
 
2527
2619
  // src/core/calculateItemsInView.ts
@@ -2561,7 +2653,7 @@ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentSt
2561
2653
  }
2562
2654
  }
2563
2655
  }
2564
- function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2656
+ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2565
2657
  var _a3, _b, _c;
2566
2658
  const state = ctx.state;
2567
2659
  for (const containerIndex of state.stickyContainerPool) {
@@ -2582,13 +2674,13 @@ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentSt
2582
2674
  if (nextIndex) {
2583
2675
  const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
2584
2676
  const nextPos = nextId ? state.positions.get(nextId) : void 0;
2585
- shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
2677
+ shouldRecycle = nextPos !== void 0 && scroll > nextPos + drawDistance * 2;
2586
2678
  } else {
2587
2679
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2588
2680
  if (currentId) {
2589
2681
  const currentPos = state.positions.get(currentId);
2590
2682
  const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2591
- shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2683
+ shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + drawDistance * 3;
2592
2684
  }
2593
2685
  }
2594
2686
  if (shouldRecycle) {
@@ -2613,11 +2705,11 @@ function calculateItemsInView(ctx, params = {}) {
2613
2705
  props: {
2614
2706
  alwaysRenderIndicesArr,
2615
2707
  alwaysRenderIndicesSet,
2708
+ drawDistance,
2616
2709
  getItemType,
2617
2710
  itemsAreEqual,
2618
2711
  keyExtractor,
2619
- onStickyHeaderChange,
2620
- scrollBuffer
2712
+ onStickyHeaderChange
2621
2713
  },
2622
2714
  scrollForNextCalculateItemsInView,
2623
2715
  scrollLength,
@@ -2630,6 +2722,7 @@ function calculateItemsInView(ctx, params = {}) {
2630
2722
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2631
2723
  const alwaysRenderArr = alwaysRenderIndicesArr || [];
2632
2724
  const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
2725
+ const { dataChanged, doMVCP, forceFullItemPositions } = params;
2633
2726
  const prevNumContainers = peek$(ctx, "numContainers");
2634
2727
  if (!data || scrollLength === 0 || !prevNumContainers) {
2635
2728
  return;
@@ -2637,7 +2730,6 @@ function calculateItemsInView(ctx, params = {}) {
2637
2730
  const totalSize = getContentSize(ctx);
2638
2731
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
2639
2732
  const numColumns = peek$(ctx, "numColumns");
2640
- const { dataChanged, doMVCP, forceFullItemPositions } = params;
2641
2733
  const speed = getScrollVelocity(state);
2642
2734
  const scrollExtra = 0;
2643
2735
  const { queuedInitialLayout } = state;
@@ -2656,24 +2748,20 @@ function calculateItemsInView(ctx, params = {}) {
2656
2748
  if (scroll + scrollLength > totalSize) {
2657
2749
  scroll = Math.max(0, totalSize - scrollLength);
2658
2750
  }
2659
- if (ENABLE_DEBUG_VIEW) {
2660
- set$(ctx, "debugRawScroll", scrollState);
2661
- set$(ctx, "debugComputedScroll", scroll);
2662
- }
2663
2751
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2664
2752
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2665
2753
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2666
2754
  if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2667
2755
  set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2668
2756
  }
2669
- let scrollBufferTop = scrollBuffer;
2670
- let scrollBufferBottom = scrollBuffer;
2671
- if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
2672
- scrollBufferTop = scrollBuffer * 0.5;
2673
- scrollBufferBottom = scrollBuffer * 1.5;
2757
+ let scrollBufferTop = drawDistance;
2758
+ let scrollBufferBottom = drawDistance;
2759
+ if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
2760
+ scrollBufferTop = drawDistance * 0.5;
2761
+ scrollBufferBottom = drawDistance * 1.5;
2674
2762
  } else {
2675
- scrollBufferTop = scrollBuffer * 1.5;
2676
- scrollBufferBottom = scrollBuffer * 0.5;
2763
+ scrollBufferTop = drawDistance * 1.5;
2764
+ scrollBufferBottom = drawDistance * 0.5;
2677
2765
  }
2678
2766
  const scrollTopBuffered = scroll - scrollBufferTop;
2679
2767
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
@@ -2683,7 +2771,9 @@ function calculateItemsInView(ctx, params = {}) {
2683
2771
  if (top === null && bottom === null) {
2684
2772
  state.scrollForNextCalculateItemsInView = void 0;
2685
2773
  } else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
2686
- return;
2774
+ if (!isInMVCPActiveMode(state)) {
2775
+ return;
2776
+ }
2687
2777
  }
2688
2778
  }
2689
2779
  const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
@@ -2915,7 +3005,7 @@ function calculateItemsInView(ctx, params = {}) {
2915
3005
  ctx,
2916
3006
  stickyIndicesArr,
2917
3007
  scroll,
2918
- scrollBuffer,
3008
+ drawDistance,
2919
3009
  currentStickyIdx,
2920
3010
  pendingRemoval,
2921
3011
  alwaysRenderSet
@@ -3022,12 +3112,17 @@ function checkFinishedScrollFrame(ctx) {
3022
3112
  state.animFrameCheckFinishedScroll = void 0;
3023
3113
  const scroll = state.scrollPending;
3024
3114
  const adjust = state.scrollAdjustHandler.getAdjust();
3025
- const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
3026
- const maxOffset = clampScrollOffset(ctx, scroll);
3115
+ const clampedTargetOffset = clampScrollOffset(
3116
+ ctx,
3117
+ scrollingTo.offset - (scrollingTo.viewOffset || 0),
3118
+ scrollingTo
3119
+ );
3120
+ const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
3027
3121
  const diff1 = Math.abs(scroll - clampedTargetOffset);
3028
3122
  const diff2 = Math.abs(diff1 - adjust);
3029
3123
  const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
3030
- if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
3124
+ const isAtTarget = diff1 < 1 || !scrollingTo.animated && diff2 < 1;
3125
+ if (isNotOverscrolled && isAtTarget) {
3031
3126
  finishScrollTo(ctx);
3032
3127
  }
3033
3128
  }
@@ -3171,10 +3266,10 @@ function doInitialAllocateContainers(ctx) {
3171
3266
  scrollLength,
3172
3267
  props: {
3173
3268
  data,
3269
+ drawDistance,
3174
3270
  getEstimatedItemSize,
3175
3271
  getFixedItemSize,
3176
3272
  getItemType,
3177
- scrollBuffer,
3178
3273
  numColumns,
3179
3274
  estimatedItemSize
3180
3275
  }
@@ -3196,7 +3291,7 @@ function doInitialAllocateContainers(ctx) {
3196
3291
  } else {
3197
3292
  averageItemSize = estimatedItemSize;
3198
3293
  }
3199
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize * numColumns);
3294
+ const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
3200
3295
  for (let i = 0; i < numContainers; i++) {
3201
3296
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
3202
3297
  set$(ctx, `containerColumn${i}`, -1);
@@ -3284,8 +3379,8 @@ function onScroll(ctx, event) {
3284
3379
  }
3285
3380
  }
3286
3381
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3287
- if (state.scrollingTo) {
3288
- const maxOffset = clampScrollOffset(ctx, newScroll);
3382
+ if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
3383
+ const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
3289
3384
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3290
3385
  newScroll = maxOffset;
3291
3386
  scrollTo(ctx, {
@@ -3338,7 +3433,7 @@ var ScrollAdjustHandler = class {
3338
3433
  if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3339
3434
  const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3340
3435
  targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3341
- targetScroll = clampScrollOffset(this.ctx, targetScroll);
3436
+ targetScroll = clampScrollOffset(this.ctx, targetScroll, scrollTarget);
3342
3437
  } else {
3343
3438
  targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3344
3439
  }
@@ -3357,6 +3452,26 @@ var ScrollAdjustHandler = class {
3357
3452
  };
3358
3453
 
3359
3454
  // src/core/updateItemSize.ts
3455
+ function runOrScheduleMVCPRecalculate(ctx) {
3456
+ const state = ctx.state;
3457
+ {
3458
+ if (!state.mvcpAnchorLock) {
3459
+ if (state.queuedMVCPRecalculate !== void 0) {
3460
+ cancelAnimationFrame(state.queuedMVCPRecalculate);
3461
+ state.queuedMVCPRecalculate = void 0;
3462
+ }
3463
+ calculateItemsInView(ctx, { doMVCP: true });
3464
+ return;
3465
+ }
3466
+ if (state.queuedMVCPRecalculate !== void 0) {
3467
+ return;
3468
+ }
3469
+ state.queuedMVCPRecalculate = requestAnimationFrame(() => {
3470
+ state.queuedMVCPRecalculate = void 0;
3471
+ calculateItemsInView(ctx, { doMVCP: true });
3472
+ });
3473
+ }
3474
+ }
3360
3475
  function updateItemSize(ctx, itemKey, sizeObj) {
3361
3476
  var _a3;
3362
3477
  const state = ctx.state;
@@ -3440,7 +3555,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
3440
3555
  if (didContainersLayout || checkAllSizesKnown(state)) {
3441
3556
  if (needsRecalculate) {
3442
3557
  state.scrollForNextCalculateItemsInView = void 0;
3443
- calculateItemsInView(ctx, { doMVCP: true });
3558
+ runOrScheduleMVCPRecalculate(ctx);
3444
3559
  }
3445
3560
  if (shouldMaintainScrollAtEnd) {
3446
3561
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
@@ -3552,7 +3667,30 @@ function createImperativeHandle(ctx) {
3552
3667
  }
3553
3668
  };
3554
3669
  const refScroller = state.refScroller;
3670
+ const clearCaches = (options) => {
3671
+ var _a3, _b;
3672
+ const mode = (_a3 = options == null ? void 0 : options.mode) != null ? _a3 : "sizes";
3673
+ state.sizes.clear();
3674
+ state.sizesKnown.clear();
3675
+ for (const key in state.averageSizes) {
3676
+ delete state.averageSizes[key];
3677
+ }
3678
+ state.minIndexSizeChanged = 0;
3679
+ state.scrollForNextCalculateItemsInView = void 0;
3680
+ state.pendingTotalSize = void 0;
3681
+ state.totalSize = 0;
3682
+ set$(ctx, "totalSize", 0);
3683
+ if (mode === "full") {
3684
+ state.indexByKey.clear();
3685
+ state.idCache.length = 0;
3686
+ state.positions.clear();
3687
+ state.columns.clear();
3688
+ state.columnSpans.clear();
3689
+ }
3690
+ (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
3691
+ };
3555
3692
  return {
3693
+ clearCaches,
3556
3694
  flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3557
3695
  getNativeScrollRef: () => refScroller.current,
3558
3696
  getScrollableNode: () => refScroller.current.getScrollableNode(),
@@ -3713,8 +3851,8 @@ function normalizeMaintainVisibleContentPosition(value) {
3713
3851
  if (value && typeof value === "object") {
3714
3852
  return {
3715
3853
  data: (_a3 = value.data) != null ? _a3 : false,
3716
- size: (_b = value.size) != null ? _b : true,
3717
- shouldRestorePosition: value.shouldRestorePosition
3854
+ shouldRestorePosition: value.shouldRestorePosition,
3855
+ size: (_b = value.size) != null ? _b : true
3718
3856
  };
3719
3857
  }
3720
3858
  if (value === false) {
@@ -3786,8 +3924,6 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3786
3924
  }
3787
3925
 
3788
3926
  // src/components/LegendList.tsx
3789
- var DEFAULT_DRAW_DISTANCE = 250;
3790
- var DEFAULT_ITEM_SIZE = 100;
3791
3927
  var LegendList = typedMemo(
3792
3928
  // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3793
3929
  typedForwardRef(function LegendList2(props, forwardedRef) {
@@ -3817,7 +3953,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3817
3953
  data: dataProp = [],
3818
3954
  dataVersion,
3819
3955
  drawDistance = 250,
3820
- estimatedItemSize: estimatedItemSizeProp,
3956
+ estimatedItemSize = 100,
3821
3957
  estimatedListSize,
3822
3958
  extraData,
3823
3959
  getEstimatedItemSize,
@@ -3869,7 +4005,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3869
4005
  ...rest
3870
4006
  } = props;
3871
4007
  const animatedPropsInternal = props.animatedPropsInternal;
3872
- const { childrenMode } = rest;
4008
+ const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
4009
+ const {
4010
+ childrenMode,
4011
+ stickyPositionComponentInternal: _stickyPositionComponentInternal,
4012
+ ...restProps
4013
+ } = rest;
3873
4014
  const contentContainerStyleBase = StyleSheet.flatten(contentContainerStyleProp);
3874
4015
  const shouldFlexGrow = alignItemsAtEnd && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
3875
4016
  const contentContainerStyle = {
@@ -3896,14 +4037,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3896
4037
  index: initialScrollIndexProp || 0,
3897
4038
  viewOffset: initialScrollOffsetProp || 0
3898
4039
  } : void 0;
3899
- const [canRender, setCanRender] = React3__namespace.useState(!IsNewArchitecture);
4040
+ const [canRender, setCanRender] = React3__namespace.useState(false);
3900
4041
  const ctx = useStateContext();
3901
4042
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
3902
4043
  const refScroller = React3.useRef(null);
3903
4044
  const combinedRef = useCombinedRef(refScroller, refScrollView);
3904
- const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
3905
- const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
3906
- const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
4045
+ const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
3907
4046
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
3908
4047
  const alwaysRenderIndices = React3.useMemo(() => {
3909
4048
  const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor);
@@ -3932,8 +4071,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3932
4071
  ctx.state = {
3933
4072
  activeStickyIndex: -1,
3934
4073
  averageSizes: {},
3935
- columns: /* @__PURE__ */ new Map(),
3936
4074
  columnSpans: /* @__PURE__ */ new Map(),
4075
+ columns: /* @__PURE__ */ new Map(),
3937
4076
  containerItemKeys: /* @__PURE__ */ new Map(),
3938
4077
  containerItemTypes: /* @__PURE__ */ new Map(),
3939
4078
  contentInsetOverride: void 0,
@@ -4020,6 +4159,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4020
4159
  contentInset,
4021
4160
  data: dataProp,
4022
4161
  dataVersion,
4162
+ drawDistance,
4023
4163
  estimatedItemSize,
4024
4164
  getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
4025
4165
  getFixedItemSize: useWrapIfItem(getFixedItemSize),
@@ -4043,10 +4183,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4043
4183
  overrideItemLayout,
4044
4184
  recycleItems: !!recycleItems,
4045
4185
  renderItem,
4046
- scrollBuffer,
4047
4186
  snapToIndices,
4048
4187
  stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
4049
4188
  stickyIndicesSet: React3.useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
4189
+ stickyPositionComponentInternal,
4050
4190
  stylePaddingBottom: stylePaddingBottomState,
4051
4191
  stylePaddingTop: stylePaddingTopState,
4052
4192
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
@@ -4066,12 +4206,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4066
4206
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
4067
4207
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
4068
4208
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
4069
- if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
4070
- if (state.scroll < 0) {
4071
- paddingDiff += state.scroll;
4072
- }
4073
- requestAdjust(ctx, paddingDiff);
4074
- }
4209
+ if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") ;
4075
4210
  };
4076
4211
  if (isFirstLocal) {
4077
4212
  initializeStateVars(false);
@@ -4090,7 +4225,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4090
4225
  } else {
4091
4226
  const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
4092
4227
  const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
4093
- const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
4228
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset, initialScroll);
4094
4229
  const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
4095
4230
  refState.current.initialScroll = updatedInitialScroll;
4096
4231
  state.initialScroll = updatedInitialScroll;
@@ -4239,7 +4374,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4239
4374
  return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(
4240
4375
  ListComponent,
4241
4376
  {
4242
- ...rest,
4377
+ ...restProps,
4243
4378
  alignItemsAtEnd,
4244
4379
  canRender,
4245
4380
  contentContainerStyle,
@@ -4273,10 +4408,18 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4273
4408
  updateItemSize: fns.updateItemSize,
4274
4409
  waitForInitialLayout
4275
4410
  }
4276
- ), IS_DEV && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3__namespace.createElement(DebugView, { state: refState.current }));
4411
+ ), IS_DEV && ENABLE_DEBUG_VIEW);
4277
4412
  });
4278
4413
 
4279
- exports.LegendList = LegendList;
4414
+ // src/index.ts
4415
+ var LegendList3 = LegendList;
4416
+ if (IS_DEV) {
4417
+ console.warn(
4418
+ "[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."
4419
+ );
4420
+ }
4421
+
4422
+ exports.LegendList = LegendList3;
4280
4423
  exports.typedForwardRef = typedForwardRef;
4281
4424
  exports.typedMemo = typedMemo;
4282
4425
  exports.useIsLastItem = useIsLastItem;