@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.native.js CHANGED
@@ -38,7 +38,7 @@ function getContentInsetEnd(state) {
38
38
  const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
39
39
  const overrideInset = (_a3 = state.contentInsetOverride) != null ? _a3 : void 0;
40
40
  if (overrideInset) {
41
- const mergedInset = { bottom: 0, left: 0, right: 0, top: 0, ...baseInset, ...overrideInset };
41
+ const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
42
42
  return (horizontal ? mergedInset.right : mergedInset.bottom) || 0;
43
43
  }
44
44
  if (baseInset) {
@@ -187,7 +187,7 @@ function useSelector$(signalName, selector) {
187
187
  var DebugRow = ({ children }) => {
188
188
  return /* @__PURE__ */ React2__namespace.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
189
189
  };
190
- var DebugView = React2__namespace.memo(function DebugView2({ state }) {
190
+ React2__namespace.memo(function DebugView2({ state }) {
191
191
  const ctx = useStateContext();
192
192
  const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
193
193
  "totalSize",
@@ -239,7 +239,7 @@ var _a;
239
239
  var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
240
240
  var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
241
241
  var _a2;
242
- var IS_DEV = (_a2 = metroDev != null ? metroDev : processDev) != null ? _a2 : false;
242
+ var IS_DEV = (_a2 = processDev != null ? processDev : metroDev) != null ? _a2 : false;
243
243
 
244
244
  // src/constants.ts
245
245
  var POSITION_OUT_OF_VIEW = -1e7;
@@ -312,7 +312,7 @@ function useValue$(key, params) {
312
312
  React2.useMemo(() => {
313
313
  let prevValue;
314
314
  let didQueueTask = false;
315
- listen$(ctx, key, (v) => {
315
+ listen$(ctx, key, () => {
316
316
  const newValue = getNewValue();
317
317
  if (delay !== void 0) {
318
318
  const fn = () => {
@@ -341,7 +341,6 @@ function useValue$(key, params) {
341
341
  }, []);
342
342
  return animValue;
343
343
  }
344
- var typedForwardRef = React2.forwardRef;
345
344
  var typedMemo = React2.memo;
346
345
  var getComponent = (Component) => {
347
346
  if (React2__namespace.isValidElement(Component)) {
@@ -416,10 +415,7 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
416
415
  const stickyPosition = animatedScrollY.interpolate({
417
416
  extrapolateLeft: "clamp",
418
417
  extrapolateRight: "extend",
419
- inputRange: [
420
- stickyStart,
421
- stickyStart + 5e3
422
- ],
418
+ inputRange: [stickyStart, stickyStart + 5e3],
423
419
  outputRange: [position, position + 5e3]
424
420
  });
425
421
  return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
@@ -637,9 +633,16 @@ function useOnLayoutSync({
637
633
  }
638
634
  var Platform2 = reactNative.Platform;
639
635
  var PlatformAdjustBreaksScroll = Platform2.OS === "android";
636
+ var typedForwardRef = React2.forwardRef;
637
+ var typedMemo2 = React2.memo;
638
+
639
+ // src/utils/isInMVCPActiveMode.native.ts
640
+ function isInMVCPActiveMode(state) {
641
+ return state.dataChangeNeedsScrollUpdate;
642
+ }
640
643
 
641
644
  // src/components/Container.tsx
642
- var Container = typedMemo(function Container2({
645
+ var Container = typedMemo2(function Container2({
643
646
  id,
644
647
  recycleItems,
645
648
  horizontal,
@@ -650,6 +653,7 @@ var Container = typedMemo(function Container2({
650
653
  }) {
651
654
  const ctx = useStateContext();
652
655
  const { columnWrapperStyle, animatedScrollY } = ctx;
656
+ const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
653
657
  const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
654
658
  `containerColumn${id}`,
655
659
  `containerSpan${id}`,
@@ -746,7 +750,8 @@ var Container = typedMemo(function Container2({
746
750
  updateItemSizeFn(currentItemKey, layout);
747
751
  itemLayoutRef.current.didLayout = true;
748
752
  };
749
- if (Platform2.OS === "web" && prevSize !== void 0 && size + 1 < prevSize) {
753
+ const shouldDeferWebShrinkLayoutUpdate = Platform2.OS === "web" && !isInMVCPActiveMode(ctx.state) && prevSize !== void 0 && size + 1 < prevSize;
754
+ if (shouldDeferWebShrinkLayoutUpdate) {
750
755
  const token = pendingShrinkToken + 1;
751
756
  itemLayoutRef.current.pendingShrinkToken = token;
752
757
  requestAnimationFrame(() => {
@@ -775,8 +780,7 @@ var Container = typedMemo(function Container2({
775
780
  const { onLayout } = useOnLayoutSync(
776
781
  {
777
782
  onLayoutChange,
778
- ref
779
- },
783
+ ref},
780
784
  [itemKey, layoutRenderCount]
781
785
  );
782
786
  if (!IsNewArchitecture) {
@@ -802,7 +806,7 @@ var Container = typedMemo(function Container2({
802
806
  }
803
807
  }, [itemKey]);
804
808
  }
805
- const PositionComponent = isSticky ? PositionViewSticky : PositionView;
809
+ const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : PositionView;
806
810
  return /* @__PURE__ */ React2__namespace.createElement(
807
811
  PositionComponent,
808
812
  {
@@ -884,25 +888,6 @@ var Containers = typedMemo(function Containers2({
884
888
  }
885
889
  return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { style }, containers);
886
890
  });
887
- function DevNumbers() {
888
- return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
889
- React2__namespace.memo(function DevNumbers2() {
890
- return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React2__namespace.createElement(
891
- reactNative.View,
892
- {
893
- key: index,
894
- style: {
895
- height: 100,
896
- pointerEvents: "none",
897
- position: "absolute",
898
- top: index * 100,
899
- width: "100%"
900
- }
901
- },
902
- /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, { style: { color: "red" } }, index * 100)
903
- ));
904
- });
905
- }
906
891
  var ListComponentScrollView = reactNative.Animated.ScrollView;
907
892
  function ScrollAdjust() {
908
893
  const bias = 1e7;
@@ -932,7 +917,7 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
932
917
  };
933
918
 
934
919
  // src/components/ListComponent.tsx
935
- var ListComponent = typedMemo(function ListComponent2({
920
+ var ListComponent = typedMemo2(function ListComponent2({
936
921
  canRender,
937
922
  style,
938
923
  contentContainerStyle,
@@ -963,7 +948,9 @@ var ListComponent = typedMemo(function ListComponent2({
963
948
  const ctx = useStateContext();
964
949
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
965
950
  const ScrollComponent = renderScrollComponent ? React2.useMemo(
966
- () => React2__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
951
+ () => React2__namespace.forwardRef(
952
+ (props, ref) => renderScrollComponent({ ...props, ref })
953
+ ),
967
954
  [renderScrollComponent]
968
955
  ) : ListComponentScrollView;
969
956
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
@@ -1020,7 +1007,7 @@ var ListComponent = typedMemo(function ListComponent2({
1020
1007
  },
1021
1008
  getComponent(ListFooterComponent)
1022
1009
  ),
1023
- IS_DEV && ENABLE_DEVMODE && /* @__PURE__ */ React2__namespace.createElement(DevNumbers, null)
1010
+ IS_DEV && ENABLE_DEVMODE
1024
1011
  );
1025
1012
  });
1026
1013
 
@@ -1156,12 +1143,15 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1156
1143
  }
1157
1144
 
1158
1145
  // src/core/clampScrollOffset.ts
1159
- function clampScrollOffset(ctx, offset) {
1146
+ function clampScrollOffset(ctx, offset, scrollTarget) {
1160
1147
  const state = ctx.state;
1161
1148
  const contentSize = getContentSize(ctx);
1162
1149
  let clampedOffset = offset;
1163
1150
  if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform2.OS !== "android" || state.lastLayout)) {
1164
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1151
+ const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
1152
+ const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
1153
+ const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
1154
+ const maxOffset = baseMaxOffset + extraEndOffset;
1165
1155
  clampedOffset = Math.min(offset, maxOffset);
1166
1156
  }
1167
1157
  clampedOffset = Math.max(0, clampedOffset);
@@ -1256,7 +1246,7 @@ function checkAtBottom(ctx) {
1256
1246
  function checkAtTop(ctx) {
1257
1247
  var _a3;
1258
1248
  const state = ctx == null ? void 0 : ctx.state;
1259
- if (!state || state.initialScroll) {
1249
+ if (!state || state.initialScroll || state.scrollingTo) {
1260
1250
  return;
1261
1251
  }
1262
1252
  const {
@@ -1300,14 +1290,22 @@ function setInitialRenderState(ctx, {
1300
1290
  didInitialScroll
1301
1291
  }) {
1302
1292
  const { state } = ctx;
1293
+ const {
1294
+ loadStartTime,
1295
+ props: { onLoad }
1296
+ } = state;
1303
1297
  if (didLayout) {
1304
1298
  state.didContainersLayout = true;
1305
1299
  }
1306
1300
  if (didInitialScroll) {
1307
1301
  state.didFinishInitialScroll = true;
1308
1302
  }
1309
- if (state.didContainersLayout && state.didFinishInitialScroll) {
1303
+ const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
1304
+ if (isReadyToRender && !peek$(ctx, "readyToRender")) {
1310
1305
  set$(ctx, "readyToRender", true);
1306
+ if (onLoad) {
1307
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1308
+ }
1311
1309
  }
1312
1310
  }
1313
1311
 
@@ -1346,12 +1344,17 @@ function checkFinishedScrollFrame(ctx) {
1346
1344
  state.animFrameCheckFinishedScroll = void 0;
1347
1345
  const scroll = state.scrollPending;
1348
1346
  const adjust = state.scrollAdjustHandler.getAdjust();
1349
- const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
1350
- const maxOffset = clampScrollOffset(ctx, scroll);
1347
+ const clampedTargetOffset = clampScrollOffset(
1348
+ ctx,
1349
+ scrollingTo.offset - (scrollingTo.viewOffset || 0),
1350
+ scrollingTo
1351
+ );
1352
+ const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
1351
1353
  const diff1 = Math.abs(scroll - clampedTargetOffset);
1352
1354
  const diff2 = Math.abs(diff1 - adjust);
1353
1355
  const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
1354
- if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
1356
+ const isAtTarget = diff1 < 1 || !scrollingTo.animated && diff2 < 1;
1357
+ if (isNotOverscrolled && isAtTarget) {
1355
1358
  finishScrollTo(ctx);
1356
1359
  }
1357
1360
  }
@@ -1413,14 +1416,14 @@ function scrollTo(ctx, params) {
1413
1416
  clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1414
1417
  }
1415
1418
  let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1416
- offset = clampScrollOffset(ctx, offset);
1419
+ offset = clampScrollOffset(ctx, offset, scrollTarget);
1417
1420
  state.scrollHistory.length = 0;
1418
1421
  if (!noScrollingTo) {
1419
1422
  state.scrollingTo = scrollTarget;
1420
1423
  }
1421
1424
  state.scrollPending = offset;
1422
1425
  if (forceScroll || !isInitialScroll || Platform2.OS === "android") {
1423
- doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1426
+ doScrollTo(ctx, { animated, horizontal, offset });
1424
1427
  } else {
1425
1428
  state.scroll = offset;
1426
1429
  }
@@ -1468,7 +1471,8 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1468
1471
  const scrollDelta = Math.abs(newScroll - prevScroll);
1469
1472
  const scrollLength = state.scrollLength;
1470
1473
  const lastCalculated = state.scrollLastCalculate;
1471
- const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1474
+ const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
1475
+ const shouldUpdate = useAggressiveItemRecalculation || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1472
1476
  if (shouldUpdate) {
1473
1477
  state.scrollLastCalculate = state.scroll;
1474
1478
  state.ignoreScrollFromMVCPIgnored = false;
@@ -1565,7 +1569,7 @@ function ensureInitialAnchor(ctx) {
1565
1569
  }
1566
1570
  const availableSpace = Math.max(0, scrollLength - size);
1567
1571
  const desiredOffset = calculateOffsetForIndex(ctx, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1568
- const clampedDesiredOffset = clampScrollOffset(ctx, desiredOffset);
1572
+ const clampedDesiredOffset = clampScrollOffset(ctx, desiredOffset, anchor);
1569
1573
  const delta = clampedDesiredOffset - scroll;
1570
1574
  if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1571
1575
  const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
@@ -1594,46 +1598,110 @@ function ensureInitialAnchor(ctx) {
1594
1598
  }
1595
1599
 
1596
1600
  // src/core/mvcp.ts
1601
+ var MVCP_POSITION_EPSILON = 0.1;
1602
+ var MVCP_ANCHOR_LOCK_TTL_MS = 300;
1603
+ var MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE = 2;
1604
+ function resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) {
1605
+ if (!enableMVCPAnchorLock) {
1606
+ state.mvcpAnchorLock = void 0;
1607
+ return void 0;
1608
+ }
1609
+ const lock = state.mvcpAnchorLock;
1610
+ if (!lock) {
1611
+ return void 0;
1612
+ }
1613
+ const isExpired = now > lock.expiresAt;
1614
+ const isMissing = state.indexByKey.get(lock.id) === void 0;
1615
+ if (isExpired || isMissing || !mvcpData) {
1616
+ state.mvcpAnchorLock = void 0;
1617
+ return void 0;
1618
+ }
1619
+ return lock;
1620
+ }
1621
+ function updateAnchorLock(state, params) {
1622
+ if (Platform2.OS === "web") {
1623
+ const { anchorId, anchorPosition, dataChanged, now, positionDiff } = params;
1624
+ const enableMVCPAnchorLock = !!dataChanged || !!state.mvcpAnchorLock;
1625
+ const mvcpData = state.props.maintainVisibleContentPosition.data;
1626
+ if (!enableMVCPAnchorLock || !mvcpData || state.scrollingTo || !anchorId || anchorPosition === void 0) {
1627
+ return;
1628
+ }
1629
+ const existingLock = state.mvcpAnchorLock;
1630
+ const quietPasses = !dataChanged && Math.abs(positionDiff) <= MVCP_POSITION_EPSILON && (existingLock == null ? void 0 : existingLock.id) === anchorId ? existingLock.quietPasses + 1 : 0;
1631
+ if (!dataChanged && quietPasses >= MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE) {
1632
+ state.mvcpAnchorLock = void 0;
1633
+ return;
1634
+ }
1635
+ state.mvcpAnchorLock = {
1636
+ expiresAt: now + MVCP_ANCHOR_LOCK_TTL_MS,
1637
+ id: anchorId,
1638
+ position: anchorPosition,
1639
+ quietPasses
1640
+ };
1641
+ }
1642
+ }
1597
1643
  function prepareMVCP(ctx, dataChanged) {
1598
1644
  const state = ctx.state;
1599
1645
  const { idsInView, positions, props } = state;
1600
1646
  const {
1601
1647
  maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll, shouldRestorePosition }
1602
1648
  } = props;
1649
+ const isWeb = Platform2.OS === "web";
1650
+ const now = Date.now();
1651
+ const enableMVCPAnchorLock = isWeb && (!!dataChanged || !!state.mvcpAnchorLock);
1603
1652
  const scrollingTo = state.scrollingTo;
1653
+ const anchorLock = isWeb ? resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) : void 0;
1604
1654
  let prevPosition;
1605
1655
  let targetId;
1606
1656
  const idsInViewWithPositions = [];
1607
1657
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1608
1658
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1659
+ const isEndAnchoredScrollTarget = scrollTarget !== void 0 && state.props.data.length > 0 && scrollTarget >= state.props.data.length - 1 && (scrollingToViewPosition != null ? scrollingToViewPosition : 0) > 0;
1609
1660
  const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1610
1661
  const indexByKey = state.indexByKey;
1611
1662
  if (shouldMVCP) {
1612
- if (scrollTarget !== void 0) {
1663
+ if (anchorLock && scrollTarget === void 0) {
1664
+ targetId = anchorLock.id;
1665
+ prevPosition = anchorLock.position;
1666
+ } else if (scrollTarget !== void 0) {
1613
1667
  if (!IsNewArchitecture && (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll)) {
1614
1668
  return void 0;
1615
1669
  }
1616
1670
  targetId = getId(state, scrollTarget);
1617
- } else if (idsInView.length > 0 && state.didContainersLayout) {
1618
- if (dataChanged) {
1619
- for (let i = 0; i < idsInView.length; i++) {
1620
- const id = idsInView[i];
1621
- const index = indexByKey.get(id);
1622
- if (index !== void 0) {
1623
- idsInViewWithPositions.push({ id, position: positions.get(id) });
1624
- }
1671
+ } else if (idsInView.length > 0 && state.didContainersLayout && !dataChanged) {
1672
+ targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
1673
+ }
1674
+ if (dataChanged && idsInView.length > 0 && state.didContainersLayout) {
1675
+ for (let i = 0; i < idsInView.length; i++) {
1676
+ const id = idsInView[i];
1677
+ const index = indexByKey.get(id);
1678
+ if (index !== void 0) {
1679
+ idsInViewWithPositions.push({ id, position: positions.get(id) });
1625
1680
  }
1626
- } else {
1627
- targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
1628
1681
  }
1629
1682
  }
1630
- if (targetId !== void 0) {
1683
+ if (targetId !== void 0 && prevPosition === void 0) {
1631
1684
  prevPosition = positions.get(targetId);
1632
1685
  }
1633
1686
  return () => {
1634
1687
  let positionDiff = 0;
1635
- if (dataChanged && targetId === void 0 && mvcpData) {
1636
- const data = state.props.data;
1688
+ let anchorIdForLock = anchorLock == null ? void 0 : anchorLock.id;
1689
+ let anchorPositionForLock;
1690
+ let skipTargetAnchor = false;
1691
+ const data = state.props.data;
1692
+ const shouldValidateLockedAnchor = isWeb && dataChanged && mvcpData && scrollTarget === void 0 && targetId !== void 0 && (anchorLock == null ? void 0 : anchorLock.id) === targetId && shouldRestorePosition !== void 0;
1693
+ if (shouldValidateLockedAnchor && targetId !== void 0) {
1694
+ const index = indexByKey.get(targetId);
1695
+ if (index !== void 0) {
1696
+ const item = data[index];
1697
+ skipTargetAnchor = item === void 0 || !shouldRestorePosition(item, index, data);
1698
+ if (skipTargetAnchor && (anchorLock == null ? void 0 : anchorLock.id) === targetId) {
1699
+ state.mvcpAnchorLock = void 0;
1700
+ }
1701
+ }
1702
+ }
1703
+ const shouldUseFallbackVisibleAnchor = dataChanged && mvcpData && scrollTarget === void 0 && (targetId === void 0 || positions.get(targetId) === void 0 || skipTargetAnchor);
1704
+ if (shouldUseFallbackVisibleAnchor) {
1637
1705
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1638
1706
  const { id, position } = idsInViewWithPositions[i];
1639
1707
  const index = indexByKey.get(id);
@@ -1646,16 +1714,18 @@ function prepareMVCP(ctx, dataChanged) {
1646
1714
  const newPosition = positions.get(id);
1647
1715
  if (newPosition !== void 0) {
1648
1716
  positionDiff = newPosition - position;
1717
+ anchorIdForLock = id;
1718
+ anchorPositionForLock = newPosition;
1649
1719
  break;
1650
1720
  }
1651
1721
  }
1652
1722
  }
1653
- if (targetId !== void 0 && prevPosition !== void 0) {
1723
+ if (!skipTargetAnchor && targetId !== void 0 && prevPosition !== void 0) {
1654
1724
  const newPosition = positions.get(targetId);
1655
1725
  if (newPosition !== void 0) {
1656
1726
  const totalSize = getContentSize(ctx);
1657
1727
  let diff = newPosition - prevPosition;
1658
- if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1728
+ if (diff !== 0 && isEndAnchoredScrollTarget && state.scroll + state.scrollLength > totalSize) {
1659
1729
  if (diff > 0) {
1660
1730
  diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
1661
1731
  } else {
@@ -1663,20 +1733,29 @@ function prepareMVCP(ctx, dataChanged) {
1663
1733
  }
1664
1734
  }
1665
1735
  positionDiff = diff;
1736
+ anchorIdForLock = targetId;
1737
+ anchorPositionForLock = newPosition;
1666
1738
  }
1667
1739
  }
1668
1740
  if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1669
1741
  const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1670
1742
  const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1671
- if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1743
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== prevSize) {
1672
1744
  const diff = newSize - prevSize;
1673
1745
  if (diff !== 0) {
1674
- positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1746
+ positionDiff += diff * scrollingToViewPosition;
1675
1747
  scrollingTo.itemSize = newSize;
1676
1748
  }
1677
1749
  }
1678
1750
  }
1679
- if (Math.abs(positionDiff) > 0.1) {
1751
+ updateAnchorLock(state, {
1752
+ anchorId: anchorIdForLock,
1753
+ anchorPosition: anchorPositionForLock,
1754
+ dataChanged,
1755
+ now,
1756
+ positionDiff
1757
+ });
1758
+ if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
1680
1759
  requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
1681
1760
  }
1682
1761
  };
@@ -2331,26 +2410,16 @@ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPositi
2331
2410
  // src/utils/setDidLayout.ts
2332
2411
  function setDidLayout(ctx) {
2333
2412
  const state = ctx.state;
2334
- const {
2335
- loadStartTime,
2336
- initialScroll,
2337
- props: { onLoad }
2338
- } = state;
2413
+ const { initialScroll } = state;
2339
2414
  state.queuedInitialLayout = true;
2340
2415
  checkAtBottom(ctx);
2341
- const setIt = () => {
2342
- setInitialRenderState(ctx, { didLayout: true });
2343
- if (onLoad) {
2344
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2345
- }
2346
- };
2347
2416
  if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
2348
2417
  const target = initialScroll;
2349
2418
  const runScroll = () => scrollToIndex(ctx, { ...target, animated: false });
2350
2419
  runScroll();
2351
2420
  requestAnimationFrame(runScroll);
2352
2421
  }
2353
- setIt();
2422
+ setInitialRenderState(ctx, { didLayout: true });
2354
2423
  }
2355
2424
 
2356
2425
  // src/core/calculateItemsInView.ts
@@ -2390,7 +2459,7 @@ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentSt
2390
2459
  }
2391
2460
  }
2392
2461
  }
2393
- function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2462
+ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2394
2463
  var _a3, _b, _c;
2395
2464
  const state = ctx.state;
2396
2465
  for (const containerIndex of state.stickyContainerPool) {
@@ -2411,13 +2480,13 @@ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentSt
2411
2480
  if (nextIndex) {
2412
2481
  const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
2413
2482
  const nextPos = nextId ? state.positions.get(nextId) : void 0;
2414
- shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
2483
+ shouldRecycle = nextPos !== void 0 && scroll > nextPos + drawDistance * 2;
2415
2484
  } else {
2416
2485
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2417
2486
  if (currentId) {
2418
2487
  const currentPos = state.positions.get(currentId);
2419
2488
  const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2420
- shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2489
+ shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + drawDistance * 3;
2421
2490
  }
2422
2491
  }
2423
2492
  if (shouldRecycle) {
@@ -2442,11 +2511,11 @@ function calculateItemsInView(ctx, params = {}) {
2442
2511
  props: {
2443
2512
  alwaysRenderIndicesArr,
2444
2513
  alwaysRenderIndicesSet,
2514
+ drawDistance,
2445
2515
  getItemType,
2446
2516
  itemsAreEqual,
2447
2517
  keyExtractor,
2448
- onStickyHeaderChange,
2449
- scrollBuffer
2518
+ onStickyHeaderChange
2450
2519
  },
2451
2520
  scrollForNextCalculateItemsInView,
2452
2521
  scrollLength,
@@ -2459,6 +2528,7 @@ function calculateItemsInView(ctx, params = {}) {
2459
2528
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2460
2529
  const alwaysRenderArr = alwaysRenderIndicesArr || [];
2461
2530
  const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
2531
+ const { dataChanged, doMVCP, forceFullItemPositions } = params;
2462
2532
  const prevNumContainers = peek$(ctx, "numContainers");
2463
2533
  if (!data || scrollLength === 0 || !prevNumContainers) {
2464
2534
  if (!IsNewArchitecture && state.initialAnchor) {
@@ -2469,7 +2539,6 @@ function calculateItemsInView(ctx, params = {}) {
2469
2539
  const totalSize = getContentSize(ctx);
2470
2540
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
2471
2541
  const numColumns = peek$(ctx, "numColumns");
2472
- const { dataChanged, doMVCP, forceFullItemPositions } = params;
2473
2542
  const speed = getScrollVelocity(state);
2474
2543
  const scrollExtra = 0;
2475
2544
  const { queuedInitialLayout } = state;
@@ -2488,24 +2557,20 @@ function calculateItemsInView(ctx, params = {}) {
2488
2557
  if (scroll + scrollLength > totalSize) {
2489
2558
  scroll = Math.max(0, totalSize - scrollLength);
2490
2559
  }
2491
- if (ENABLE_DEBUG_VIEW) {
2492
- set$(ctx, "debugRawScroll", scrollState);
2493
- set$(ctx, "debugComputedScroll", scroll);
2494
- }
2495
2560
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2496
2561
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2497
2562
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2498
2563
  if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2499
2564
  set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2500
2565
  }
2501
- let scrollBufferTop = scrollBuffer;
2502
- let scrollBufferBottom = scrollBuffer;
2503
- if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
2504
- scrollBufferTop = scrollBuffer * 0.5;
2505
- scrollBufferBottom = scrollBuffer * 1.5;
2566
+ let scrollBufferTop = drawDistance;
2567
+ let scrollBufferBottom = drawDistance;
2568
+ if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
2569
+ scrollBufferTop = drawDistance * 0.5;
2570
+ scrollBufferBottom = drawDistance * 1.5;
2506
2571
  } else {
2507
- scrollBufferTop = scrollBuffer * 1.5;
2508
- scrollBufferBottom = scrollBuffer * 0.5;
2572
+ scrollBufferTop = drawDistance * 1.5;
2573
+ scrollBufferBottom = drawDistance * 0.5;
2509
2574
  }
2510
2575
  const scrollTopBuffered = scroll - scrollBufferTop;
2511
2576
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
@@ -2518,7 +2583,9 @@ function calculateItemsInView(ctx, params = {}) {
2518
2583
  if (!IsNewArchitecture && state.initialAnchor) {
2519
2584
  ensureInitialAnchor(ctx);
2520
2585
  }
2521
- return;
2586
+ if (Platform2.OS !== "web" || !isInMVCPActiveMode(state)) {
2587
+ return;
2588
+ }
2522
2589
  }
2523
2590
  }
2524
2591
  const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
@@ -2750,7 +2817,7 @@ function calculateItemsInView(ctx, params = {}) {
2750
2817
  ctx,
2751
2818
  stickyIndicesArr,
2752
2819
  scroll,
2753
- scrollBuffer,
2820
+ drawDistance,
2754
2821
  currentStickyIdx,
2755
2822
  pendingRemoval,
2756
2823
  alwaysRenderSet
@@ -2963,10 +3030,10 @@ function doInitialAllocateContainers(ctx) {
2963
3030
  scrollLength,
2964
3031
  props: {
2965
3032
  data,
3033
+ drawDistance,
2966
3034
  getEstimatedItemSize,
2967
3035
  getFixedItemSize,
2968
3036
  getItemType,
2969
- scrollBuffer,
2970
3037
  numColumns,
2971
3038
  estimatedItemSize
2972
3039
  }
@@ -2988,7 +3055,7 @@ function doInitialAllocateContainers(ctx) {
2988
3055
  } else {
2989
3056
  averageItemSize = estimatedItemSize;
2990
3057
  }
2991
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize * numColumns);
3058
+ const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
2992
3059
  for (let i = 0; i < numContainers; i++) {
2993
3060
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2994
3061
  set$(ctx, `containerColumn${i}`, -1);
@@ -3076,8 +3143,8 @@ function onScroll(ctx, event) {
3076
3143
  }
3077
3144
  }
3078
3145
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3079
- if (state.scrollingTo) {
3080
- const maxOffset = clampScrollOffset(ctx, newScroll);
3146
+ if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
3147
+ const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
3081
3148
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3082
3149
  newScroll = maxOffset;
3083
3150
  scrollTo(ctx, {
@@ -3130,7 +3197,7 @@ var ScrollAdjustHandler = class {
3130
3197
  if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3131
3198
  const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3132
3199
  targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3133
- targetScroll = clampScrollOffset(this.ctx, targetScroll);
3200
+ targetScroll = clampScrollOffset(this.ctx, targetScroll, scrollTarget);
3134
3201
  } else {
3135
3202
  targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3136
3203
  }
@@ -3149,6 +3216,28 @@ var ScrollAdjustHandler = class {
3149
3216
  };
3150
3217
 
3151
3218
  // src/core/updateItemSize.ts
3219
+ function runOrScheduleMVCPRecalculate(ctx) {
3220
+ const state = ctx.state;
3221
+ if (Platform2.OS === "web") {
3222
+ if (!state.mvcpAnchorLock) {
3223
+ if (state.queuedMVCPRecalculate !== void 0) {
3224
+ cancelAnimationFrame(state.queuedMVCPRecalculate);
3225
+ state.queuedMVCPRecalculate = void 0;
3226
+ }
3227
+ calculateItemsInView(ctx, { doMVCP: true });
3228
+ return;
3229
+ }
3230
+ if (state.queuedMVCPRecalculate !== void 0) {
3231
+ return;
3232
+ }
3233
+ state.queuedMVCPRecalculate = requestAnimationFrame(() => {
3234
+ state.queuedMVCPRecalculate = void 0;
3235
+ calculateItemsInView(ctx, { doMVCP: true });
3236
+ });
3237
+ } else {
3238
+ calculateItemsInView(ctx, { doMVCP: true });
3239
+ }
3240
+ }
3152
3241
  function updateItemSize(ctx, itemKey, sizeObj) {
3153
3242
  var _a3;
3154
3243
  const state = ctx.state;
@@ -3232,7 +3321,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
3232
3321
  if (didContainersLayout || checkAllSizesKnown(state)) {
3233
3322
  if (needsRecalculate) {
3234
3323
  state.scrollForNextCalculateItemsInView = void 0;
3235
- calculateItemsInView(ctx, { doMVCP: true });
3324
+ runOrScheduleMVCPRecalculate(ctx);
3236
3325
  }
3237
3326
  if (shouldMaintainScrollAtEnd) {
3238
3327
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
@@ -3309,8 +3398,9 @@ function getWindowSize() {
3309
3398
  }
3310
3399
  var StyleSheet = reactNative.StyleSheet;
3311
3400
  function useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, onScroll2) {
3401
+ const shouldUseRnAnimatedEngine = !ctx.state.props.stickyPositionComponentInternal;
3312
3402
  return React2.useMemo(() => {
3313
- if (stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.length) {
3403
+ if ((stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.length) && shouldUseRnAnimatedEngine) {
3314
3404
  const { animatedScrollY } = ctx;
3315
3405
  return reactNative.Animated.event(
3316
3406
  [
@@ -3327,7 +3417,7 @@ function useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, onScroll2)
3327
3417
  );
3328
3418
  }
3329
3419
  return onScroll2;
3330
- }, [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(","), horizontal]);
3420
+ }, [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(","), horizontal, shouldUseRnAnimatedEngine]);
3331
3421
  }
3332
3422
 
3333
3423
  // src/utils/createColumnWrapperStyle.ts
@@ -3363,7 +3453,30 @@ function createImperativeHandle(ctx) {
3363
3453
  }
3364
3454
  };
3365
3455
  const refScroller = state.refScroller;
3456
+ const clearCaches = (options) => {
3457
+ var _a3, _b;
3458
+ const mode = (_a3 = options == null ? void 0 : options.mode) != null ? _a3 : "sizes";
3459
+ state.sizes.clear();
3460
+ state.sizesKnown.clear();
3461
+ for (const key in state.averageSizes) {
3462
+ delete state.averageSizes[key];
3463
+ }
3464
+ state.minIndexSizeChanged = 0;
3465
+ state.scrollForNextCalculateItemsInView = void 0;
3466
+ state.pendingTotalSize = void 0;
3467
+ state.totalSize = 0;
3468
+ set$(ctx, "totalSize", 0);
3469
+ if (mode === "full") {
3470
+ state.indexByKey.clear();
3471
+ state.idCache.length = 0;
3472
+ state.positions.clear();
3473
+ state.columns.clear();
3474
+ state.columnSpans.clear();
3475
+ }
3476
+ (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
3477
+ };
3366
3478
  return {
3479
+ clearCaches,
3367
3480
  flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3368
3481
  getNativeScrollRef: () => refScroller.current,
3369
3482
  getScrollableNode: () => refScroller.current.getScrollableNode(),
@@ -3524,8 +3637,8 @@ function normalizeMaintainVisibleContentPosition(value) {
3524
3637
  if (value && typeof value === "object") {
3525
3638
  return {
3526
3639
  data: (_a3 = value.data) != null ? _a3 : false,
3527
- size: (_b = value.size) != null ? _b : true,
3528
- shouldRestorePosition: value.shouldRestorePosition
3640
+ shouldRestorePosition: value.shouldRestorePosition,
3641
+ size: (_b = value.size) != null ? _b : true
3529
3642
  };
3530
3643
  }
3531
3644
  if (value === false) {
@@ -3597,9 +3710,7 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3597
3710
  }
3598
3711
 
3599
3712
  // src/components/LegendList.tsx
3600
- var DEFAULT_DRAW_DISTANCE = 250;
3601
- var DEFAULT_ITEM_SIZE = 100;
3602
- var LegendList = typedMemo(
3713
+ var LegendList = typedMemo2(
3603
3714
  // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3604
3715
  typedForwardRef(function LegendList2(props, forwardedRef) {
3605
3716
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
@@ -3628,7 +3739,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3628
3739
  data: dataProp = [],
3629
3740
  dataVersion,
3630
3741
  drawDistance = 250,
3631
- estimatedItemSize: estimatedItemSizeProp,
3742
+ estimatedItemSize = 100,
3632
3743
  estimatedListSize,
3633
3744
  extraData,
3634
3745
  getEstimatedItemSize,
@@ -3680,7 +3791,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3680
3791
  ...rest
3681
3792
  } = props;
3682
3793
  const animatedPropsInternal = props.animatedPropsInternal;
3683
- const { childrenMode } = rest;
3794
+ const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
3795
+ const {
3796
+ childrenMode,
3797
+ stickyPositionComponentInternal: _stickyPositionComponentInternal,
3798
+ ...restProps
3799
+ } = rest;
3684
3800
  const contentContainerStyleBase = StyleSheet.flatten(contentContainerStyleProp);
3685
3801
  const shouldFlexGrow = alignItemsAtEnd && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
3686
3802
  const contentContainerStyle = {
@@ -3712,9 +3828,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3712
3828
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
3713
3829
  const refScroller = React2.useRef(null);
3714
3830
  const combinedRef = useCombinedRef(refScroller, refScrollView);
3715
- const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
3716
- const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
3717
- const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
3831
+ const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
3718
3832
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
3719
3833
  const alwaysRenderIndices = React2.useMemo(() => {
3720
3834
  const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor);
@@ -3743,8 +3857,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3743
3857
  ctx.state = {
3744
3858
  activeStickyIndex: -1,
3745
3859
  averageSizes: {},
3746
- columns: /* @__PURE__ */ new Map(),
3747
3860
  columnSpans: /* @__PURE__ */ new Map(),
3861
+ columns: /* @__PURE__ */ new Map(),
3748
3862
  containerItemKeys: /* @__PURE__ */ new Map(),
3749
3863
  containerItemTypes: /* @__PURE__ */ new Map(),
3750
3864
  contentInsetOverride: void 0,
@@ -3831,6 +3945,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3831
3945
  contentInset,
3832
3946
  data: dataProp,
3833
3947
  dataVersion,
3948
+ drawDistance,
3834
3949
  estimatedItemSize,
3835
3950
  getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3836
3951
  getFixedItemSize: useWrapIfItem(getFixedItemSize),
@@ -3854,10 +3969,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3854
3969
  overrideItemLayout,
3855
3970
  recycleItems: !!recycleItems,
3856
3971
  renderItem,
3857
- scrollBuffer,
3858
3972
  snapToIndices,
3859
3973
  stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
3860
3974
  stickyIndicesSet: React2.useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
3975
+ stickyPositionComponentInternal,
3861
3976
  stylePaddingBottom: stylePaddingBottomState,
3862
3977
  stylePaddingTop: stylePaddingTopState,
3863
3978
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
@@ -3911,7 +4026,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3911
4026
  } else {
3912
4027
  const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3913
4028
  const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3914
- const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
4029
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset, initialScroll);
3915
4030
  const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3916
4031
  refState.current.initialScroll = updatedInitialScroll;
3917
4032
  state.initialScroll = updatedInitialScroll;
@@ -4067,7 +4182,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4067
4182
  return /* @__PURE__ */ React2__namespace.createElement(React2__namespace.Fragment, null, /* @__PURE__ */ React2__namespace.createElement(
4068
4183
  ListComponent,
4069
4184
  {
4070
- ...rest,
4185
+ ...restProps,
4071
4186
  alignItemsAtEnd,
4072
4187
  canRender,
4073
4188
  contentContainerStyle,
@@ -4101,12 +4216,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4101
4216
  updateItemSize: fns.updateItemSize,
4102
4217
  waitForInitialLayout
4103
4218
  }
4104
- ), IS_DEV && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React2__namespace.createElement(DebugView, { state: refState.current }));
4219
+ ), IS_DEV && ENABLE_DEBUG_VIEW);
4105
4220
  });
4106
4221
 
4107
- exports.LegendList = LegendList;
4222
+ // src/index.ts
4223
+ var LegendList3 = LegendList;
4224
+ if (IS_DEV) {
4225
+ console.warn(
4226
+ "[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."
4227
+ );
4228
+ }
4229
+
4230
+ exports.LegendList = LegendList3;
4108
4231
  exports.typedForwardRef = typedForwardRef;
4109
- exports.typedMemo = typedMemo;
4232
+ exports.typedMemo = typedMemo2;
4110
4233
  exports.useIsLastItem = useIsLastItem;
4111
4234
  exports.useListScrollSize = useListScrollSize;
4112
4235
  exports.useRecyclingEffect = useRecyclingEffect;