@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.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React2 from 'react';
2
- import React2__default, { useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle, forwardRef, memo, useContext } from 'react';
3
- import { Animated, View as View$1, Platform, RefreshControl, Text as Text$1, unstable_batchedUpdates, Dimensions, StyleSheet as StyleSheet$1 } from 'react-native';
2
+ import React2__default, { useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle, memo, forwardRef, useContext } from 'react';
3
+ import { Animated, View as View$1, Text as Text$1, Platform, StyleSheet as StyleSheet$1, RefreshControl, Dimensions, unstable_batchedUpdates } from 'react-native';
4
4
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
5
5
 
6
6
  // src/components/LegendList.tsx
@@ -17,7 +17,7 @@ function getContentInsetEnd(state) {
17
17
  const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
18
18
  const overrideInset = (_a3 = state.contentInsetOverride) != null ? _a3 : void 0;
19
19
  if (overrideInset) {
20
- const mergedInset = { bottom: 0, left: 0, right: 0, top: 0, ...baseInset, ...overrideInset };
20
+ const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
21
21
  return (horizontal ? mergedInset.right : mergedInset.bottom) || 0;
22
22
  }
23
23
  if (baseInset) {
@@ -166,7 +166,7 @@ function useSelector$(signalName, selector) {
166
166
  var DebugRow = ({ children }) => {
167
167
  return /* @__PURE__ */ React2.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
168
168
  };
169
- var DebugView = React2.memo(function DebugView2({ state }) {
169
+ React2.memo(function DebugView2({ state }) {
170
170
  const ctx = useStateContext();
171
171
  const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
172
172
  "totalSize",
@@ -218,7 +218,7 @@ var _a;
218
218
  var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
219
219
  var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
220
220
  var _a2;
221
- var IS_DEV = (_a2 = metroDev != null ? metroDev : processDev) != null ? _a2 : false;
221
+ var IS_DEV = (_a2 = processDev != null ? processDev : metroDev) != null ? _a2 : false;
222
222
 
223
223
  // src/constants.ts
224
224
  var POSITION_OUT_OF_VIEW = -1e7;
@@ -291,7 +291,7 @@ function useValue$(key, params) {
291
291
  useMemo(() => {
292
292
  let prevValue;
293
293
  let didQueueTask = false;
294
- listen$(ctx, key, (v) => {
294
+ listen$(ctx, key, () => {
295
295
  const newValue = getNewValue();
296
296
  if (delay !== void 0) {
297
297
  const fn = () => {
@@ -320,7 +320,6 @@ function useValue$(key, params) {
320
320
  }, []);
321
321
  return animValue;
322
322
  }
323
- var typedForwardRef = forwardRef;
324
323
  var typedMemo = memo;
325
324
  var getComponent = (Component) => {
326
325
  if (React2.isValidElement(Component)) {
@@ -395,10 +394,7 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
395
394
  const stickyPosition = animatedScrollY.interpolate({
396
395
  extrapolateLeft: "clamp",
397
396
  extrapolateRight: "extend",
398
- inputRange: [
399
- stickyStart,
400
- stickyStart + 5e3
401
- ],
397
+ inputRange: [stickyStart, stickyStart + 5e3],
402
398
  outputRange: [position, position + 5e3]
403
399
  });
404
400
  return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
@@ -616,9 +612,16 @@ function useOnLayoutSync({
616
612
  }
617
613
  var Platform2 = Platform;
618
614
  var PlatformAdjustBreaksScroll = Platform2.OS === "android";
615
+ var typedForwardRef = forwardRef;
616
+ var typedMemo2 = memo;
617
+
618
+ // src/utils/isInMVCPActiveMode.native.ts
619
+ function isInMVCPActiveMode(state) {
620
+ return state.dataChangeNeedsScrollUpdate;
621
+ }
619
622
 
620
623
  // src/components/Container.tsx
621
- var Container = typedMemo(function Container2({
624
+ var Container = typedMemo2(function Container2({
622
625
  id,
623
626
  recycleItems,
624
627
  horizontal,
@@ -629,6 +632,7 @@ var Container = typedMemo(function Container2({
629
632
  }) {
630
633
  const ctx = useStateContext();
631
634
  const { columnWrapperStyle, animatedScrollY } = ctx;
635
+ const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
632
636
  const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
633
637
  `containerColumn${id}`,
634
638
  `containerSpan${id}`,
@@ -725,7 +729,8 @@ var Container = typedMemo(function Container2({
725
729
  updateItemSizeFn(currentItemKey, layout);
726
730
  itemLayoutRef.current.didLayout = true;
727
731
  };
728
- if (Platform2.OS === "web" && prevSize !== void 0 && size + 1 < prevSize) {
732
+ const shouldDeferWebShrinkLayoutUpdate = Platform2.OS === "web" && !isInMVCPActiveMode(ctx.state) && prevSize !== void 0 && size + 1 < prevSize;
733
+ if (shouldDeferWebShrinkLayoutUpdate) {
729
734
  const token = pendingShrinkToken + 1;
730
735
  itemLayoutRef.current.pendingShrinkToken = token;
731
736
  requestAnimationFrame(() => {
@@ -754,8 +759,7 @@ var Container = typedMemo(function Container2({
754
759
  const { onLayout } = useOnLayoutSync(
755
760
  {
756
761
  onLayoutChange,
757
- ref
758
- },
762
+ ref},
759
763
  [itemKey, layoutRenderCount]
760
764
  );
761
765
  if (!IsNewArchitecture) {
@@ -781,7 +785,7 @@ var Container = typedMemo(function Container2({
781
785
  }
782
786
  }, [itemKey]);
783
787
  }
784
- const PositionComponent = isSticky ? PositionViewSticky : PositionView;
788
+ const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : PositionView;
785
789
  return /* @__PURE__ */ React2.createElement(
786
790
  PositionComponent,
787
791
  {
@@ -863,25 +867,6 @@ var Containers = typedMemo(function Containers2({
863
867
  }
864
868
  return /* @__PURE__ */ React2.createElement(Animated.View, { style }, containers);
865
869
  });
866
- function DevNumbers() {
867
- return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
868
- React2.memo(function DevNumbers2() {
869
- return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React2.createElement(
870
- View$1,
871
- {
872
- key: index,
873
- style: {
874
- height: 100,
875
- pointerEvents: "none",
876
- position: "absolute",
877
- top: index * 100,
878
- width: "100%"
879
- }
880
- },
881
- /* @__PURE__ */ React2.createElement(Text$1, { style: { color: "red" } }, index * 100)
882
- ));
883
- });
884
- }
885
870
  var ListComponentScrollView = Animated.ScrollView;
886
871
  function ScrollAdjust() {
887
872
  const bias = 1e7;
@@ -911,7 +896,7 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
911
896
  };
912
897
 
913
898
  // src/components/ListComponent.tsx
914
- var ListComponent = typedMemo(function ListComponent2({
899
+ var ListComponent = typedMemo2(function ListComponent2({
915
900
  canRender,
916
901
  style,
917
902
  contentContainerStyle,
@@ -942,7 +927,9 @@ var ListComponent = typedMemo(function ListComponent2({
942
927
  const ctx = useStateContext();
943
928
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
944
929
  const ScrollComponent = renderScrollComponent ? useMemo(
945
- () => React2.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
930
+ () => React2.forwardRef(
931
+ (props, ref) => renderScrollComponent({ ...props, ref })
932
+ ),
946
933
  [renderScrollComponent]
947
934
  ) : ListComponentScrollView;
948
935
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
@@ -999,7 +986,7 @@ var ListComponent = typedMemo(function ListComponent2({
999
986
  },
1000
987
  getComponent(ListFooterComponent)
1001
988
  ),
1002
- IS_DEV && ENABLE_DEVMODE && /* @__PURE__ */ React2.createElement(DevNumbers, null)
989
+ IS_DEV && ENABLE_DEVMODE
1003
990
  );
1004
991
  });
1005
992
 
@@ -1135,12 +1122,15 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1135
1122
  }
1136
1123
 
1137
1124
  // src/core/clampScrollOffset.ts
1138
- function clampScrollOffset(ctx, offset) {
1125
+ function clampScrollOffset(ctx, offset, scrollTarget) {
1139
1126
  const state = ctx.state;
1140
1127
  const contentSize = getContentSize(ctx);
1141
1128
  let clampedOffset = offset;
1142
1129
  if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform2.OS !== "android" || state.lastLayout)) {
1143
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1130
+ const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
1131
+ const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
1132
+ const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
1133
+ const maxOffset = baseMaxOffset + extraEndOffset;
1144
1134
  clampedOffset = Math.min(offset, maxOffset);
1145
1135
  }
1146
1136
  clampedOffset = Math.max(0, clampedOffset);
@@ -1235,7 +1225,7 @@ function checkAtBottom(ctx) {
1235
1225
  function checkAtTop(ctx) {
1236
1226
  var _a3;
1237
1227
  const state = ctx == null ? void 0 : ctx.state;
1238
- if (!state || state.initialScroll) {
1228
+ if (!state || state.initialScroll || state.scrollingTo) {
1239
1229
  return;
1240
1230
  }
1241
1231
  const {
@@ -1279,14 +1269,22 @@ function setInitialRenderState(ctx, {
1279
1269
  didInitialScroll
1280
1270
  }) {
1281
1271
  const { state } = ctx;
1272
+ const {
1273
+ loadStartTime,
1274
+ props: { onLoad }
1275
+ } = state;
1282
1276
  if (didLayout) {
1283
1277
  state.didContainersLayout = true;
1284
1278
  }
1285
1279
  if (didInitialScroll) {
1286
1280
  state.didFinishInitialScroll = true;
1287
1281
  }
1288
- if (state.didContainersLayout && state.didFinishInitialScroll) {
1282
+ const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
1283
+ if (isReadyToRender && !peek$(ctx, "readyToRender")) {
1289
1284
  set$(ctx, "readyToRender", true);
1285
+ if (onLoad) {
1286
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1287
+ }
1290
1288
  }
1291
1289
  }
1292
1290
 
@@ -1325,12 +1323,17 @@ function checkFinishedScrollFrame(ctx) {
1325
1323
  state.animFrameCheckFinishedScroll = void 0;
1326
1324
  const scroll = state.scrollPending;
1327
1325
  const adjust = state.scrollAdjustHandler.getAdjust();
1328
- const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
1329
- const maxOffset = clampScrollOffset(ctx, scroll);
1326
+ const clampedTargetOffset = clampScrollOffset(
1327
+ ctx,
1328
+ scrollingTo.offset - (scrollingTo.viewOffset || 0),
1329
+ scrollingTo
1330
+ );
1331
+ const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
1330
1332
  const diff1 = Math.abs(scroll - clampedTargetOffset);
1331
1333
  const diff2 = Math.abs(diff1 - adjust);
1332
1334
  const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
1333
- if (isNotOverscrolled && (diff1 < 1 || diff2 < 1)) {
1335
+ const isAtTarget = diff1 < 1 || !scrollingTo.animated && diff2 < 1;
1336
+ if (isNotOverscrolled && isAtTarget) {
1334
1337
  finishScrollTo(ctx);
1335
1338
  }
1336
1339
  }
@@ -1392,14 +1395,14 @@ function scrollTo(ctx, params) {
1392
1395
  clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1393
1396
  }
1394
1397
  let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1395
- offset = clampScrollOffset(ctx, offset);
1398
+ offset = clampScrollOffset(ctx, offset, scrollTarget);
1396
1399
  state.scrollHistory.length = 0;
1397
1400
  if (!noScrollingTo) {
1398
1401
  state.scrollingTo = scrollTarget;
1399
1402
  }
1400
1403
  state.scrollPending = offset;
1401
1404
  if (forceScroll || !isInitialScroll || Platform2.OS === "android") {
1402
- doScrollTo(ctx, { animated, horizontal, isInitialScroll, offset });
1405
+ doScrollTo(ctx, { animated, horizontal, offset });
1403
1406
  } else {
1404
1407
  state.scroll = offset;
1405
1408
  }
@@ -1447,7 +1450,8 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1447
1450
  const scrollDelta = Math.abs(newScroll - prevScroll);
1448
1451
  const scrollLength = state.scrollLength;
1449
1452
  const lastCalculated = state.scrollLastCalculate;
1450
- const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1453
+ const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
1454
+ const shouldUpdate = useAggressiveItemRecalculation || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1451
1455
  if (shouldUpdate) {
1452
1456
  state.scrollLastCalculate = state.scroll;
1453
1457
  state.ignoreScrollFromMVCPIgnored = false;
@@ -1544,7 +1548,7 @@ function ensureInitialAnchor(ctx) {
1544
1548
  }
1545
1549
  const availableSpace = Math.max(0, scrollLength - size);
1546
1550
  const desiredOffset = calculateOffsetForIndex(ctx, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1547
- const clampedDesiredOffset = clampScrollOffset(ctx, desiredOffset);
1551
+ const clampedDesiredOffset = clampScrollOffset(ctx, desiredOffset, anchor);
1548
1552
  const delta = clampedDesiredOffset - scroll;
1549
1553
  if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1550
1554
  const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
@@ -1573,46 +1577,110 @@ function ensureInitialAnchor(ctx) {
1573
1577
  }
1574
1578
 
1575
1579
  // src/core/mvcp.ts
1580
+ var MVCP_POSITION_EPSILON = 0.1;
1581
+ var MVCP_ANCHOR_LOCK_TTL_MS = 300;
1582
+ var MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE = 2;
1583
+ function resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) {
1584
+ if (!enableMVCPAnchorLock) {
1585
+ state.mvcpAnchorLock = void 0;
1586
+ return void 0;
1587
+ }
1588
+ const lock = state.mvcpAnchorLock;
1589
+ if (!lock) {
1590
+ return void 0;
1591
+ }
1592
+ const isExpired = now > lock.expiresAt;
1593
+ const isMissing = state.indexByKey.get(lock.id) === void 0;
1594
+ if (isExpired || isMissing || !mvcpData) {
1595
+ state.mvcpAnchorLock = void 0;
1596
+ return void 0;
1597
+ }
1598
+ return lock;
1599
+ }
1600
+ function updateAnchorLock(state, params) {
1601
+ if (Platform2.OS === "web") {
1602
+ const { anchorId, anchorPosition, dataChanged, now, positionDiff } = params;
1603
+ const enableMVCPAnchorLock = !!dataChanged || !!state.mvcpAnchorLock;
1604
+ const mvcpData = state.props.maintainVisibleContentPosition.data;
1605
+ if (!enableMVCPAnchorLock || !mvcpData || state.scrollingTo || !anchorId || anchorPosition === void 0) {
1606
+ return;
1607
+ }
1608
+ const existingLock = state.mvcpAnchorLock;
1609
+ const quietPasses = !dataChanged && Math.abs(positionDiff) <= MVCP_POSITION_EPSILON && (existingLock == null ? void 0 : existingLock.id) === anchorId ? existingLock.quietPasses + 1 : 0;
1610
+ if (!dataChanged && quietPasses >= MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE) {
1611
+ state.mvcpAnchorLock = void 0;
1612
+ return;
1613
+ }
1614
+ state.mvcpAnchorLock = {
1615
+ expiresAt: now + MVCP_ANCHOR_LOCK_TTL_MS,
1616
+ id: anchorId,
1617
+ position: anchorPosition,
1618
+ quietPasses
1619
+ };
1620
+ }
1621
+ }
1576
1622
  function prepareMVCP(ctx, dataChanged) {
1577
1623
  const state = ctx.state;
1578
1624
  const { idsInView, positions, props } = state;
1579
1625
  const {
1580
1626
  maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll, shouldRestorePosition }
1581
1627
  } = props;
1628
+ const isWeb = Platform2.OS === "web";
1629
+ const now = Date.now();
1630
+ const enableMVCPAnchorLock = isWeb && (!!dataChanged || !!state.mvcpAnchorLock);
1582
1631
  const scrollingTo = state.scrollingTo;
1632
+ const anchorLock = isWeb ? resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) : void 0;
1583
1633
  let prevPosition;
1584
1634
  let targetId;
1585
1635
  const idsInViewWithPositions = [];
1586
1636
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1587
1637
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1638
+ const isEndAnchoredScrollTarget = scrollTarget !== void 0 && state.props.data.length > 0 && scrollTarget >= state.props.data.length - 1 && (scrollingToViewPosition != null ? scrollingToViewPosition : 0) > 0;
1588
1639
  const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1589
1640
  const indexByKey = state.indexByKey;
1590
1641
  if (shouldMVCP) {
1591
- if (scrollTarget !== void 0) {
1642
+ if (anchorLock && scrollTarget === void 0) {
1643
+ targetId = anchorLock.id;
1644
+ prevPosition = anchorLock.position;
1645
+ } else if (scrollTarget !== void 0) {
1592
1646
  if (!IsNewArchitecture && (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll)) {
1593
1647
  return void 0;
1594
1648
  }
1595
1649
  targetId = getId(state, scrollTarget);
1596
- } else if (idsInView.length > 0 && state.didContainersLayout) {
1597
- if (dataChanged) {
1598
- for (let i = 0; i < idsInView.length; i++) {
1599
- const id = idsInView[i];
1600
- const index = indexByKey.get(id);
1601
- if (index !== void 0) {
1602
- idsInViewWithPositions.push({ id, position: positions.get(id) });
1603
- }
1650
+ } else if (idsInView.length > 0 && state.didContainersLayout && !dataChanged) {
1651
+ targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
1652
+ }
1653
+ if (dataChanged && idsInView.length > 0 && state.didContainersLayout) {
1654
+ for (let i = 0; i < idsInView.length; i++) {
1655
+ const id = idsInView[i];
1656
+ const index = indexByKey.get(id);
1657
+ if (index !== void 0) {
1658
+ idsInViewWithPositions.push({ id, position: positions.get(id) });
1604
1659
  }
1605
- } else {
1606
- targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
1607
1660
  }
1608
1661
  }
1609
- if (targetId !== void 0) {
1662
+ if (targetId !== void 0 && prevPosition === void 0) {
1610
1663
  prevPosition = positions.get(targetId);
1611
1664
  }
1612
1665
  return () => {
1613
1666
  let positionDiff = 0;
1614
- if (dataChanged && targetId === void 0 && mvcpData) {
1615
- const data = state.props.data;
1667
+ let anchorIdForLock = anchorLock == null ? void 0 : anchorLock.id;
1668
+ let anchorPositionForLock;
1669
+ let skipTargetAnchor = false;
1670
+ const data = state.props.data;
1671
+ const shouldValidateLockedAnchor = isWeb && dataChanged && mvcpData && scrollTarget === void 0 && targetId !== void 0 && (anchorLock == null ? void 0 : anchorLock.id) === targetId && shouldRestorePosition !== void 0;
1672
+ if (shouldValidateLockedAnchor && targetId !== void 0) {
1673
+ const index = indexByKey.get(targetId);
1674
+ if (index !== void 0) {
1675
+ const item = data[index];
1676
+ skipTargetAnchor = item === void 0 || !shouldRestorePosition(item, index, data);
1677
+ if (skipTargetAnchor && (anchorLock == null ? void 0 : anchorLock.id) === targetId) {
1678
+ state.mvcpAnchorLock = void 0;
1679
+ }
1680
+ }
1681
+ }
1682
+ const shouldUseFallbackVisibleAnchor = dataChanged && mvcpData && scrollTarget === void 0 && (targetId === void 0 || positions.get(targetId) === void 0 || skipTargetAnchor);
1683
+ if (shouldUseFallbackVisibleAnchor) {
1616
1684
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1617
1685
  const { id, position } = idsInViewWithPositions[i];
1618
1686
  const index = indexByKey.get(id);
@@ -1625,16 +1693,18 @@ function prepareMVCP(ctx, dataChanged) {
1625
1693
  const newPosition = positions.get(id);
1626
1694
  if (newPosition !== void 0) {
1627
1695
  positionDiff = newPosition - position;
1696
+ anchorIdForLock = id;
1697
+ anchorPositionForLock = newPosition;
1628
1698
  break;
1629
1699
  }
1630
1700
  }
1631
1701
  }
1632
- if (targetId !== void 0 && prevPosition !== void 0) {
1702
+ if (!skipTargetAnchor && targetId !== void 0 && prevPosition !== void 0) {
1633
1703
  const newPosition = positions.get(targetId);
1634
1704
  if (newPosition !== void 0) {
1635
1705
  const totalSize = getContentSize(ctx);
1636
1706
  let diff = newPosition - prevPosition;
1637
- if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1707
+ if (diff !== 0 && isEndAnchoredScrollTarget && state.scroll + state.scrollLength > totalSize) {
1638
1708
  if (diff > 0) {
1639
1709
  diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
1640
1710
  } else {
@@ -1642,20 +1712,29 @@ function prepareMVCP(ctx, dataChanged) {
1642
1712
  }
1643
1713
  }
1644
1714
  positionDiff = diff;
1715
+ anchorIdForLock = targetId;
1716
+ anchorPositionForLock = newPosition;
1645
1717
  }
1646
1718
  }
1647
1719
  if (scrollingToViewPosition && scrollingToViewPosition > 0) {
1648
1720
  const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
1649
1721
  const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
1650
- if (newSize !== void 0 && prevSize !== void 0 && newSize !== (scrollingTo == null ? void 0 : scrollingTo.itemSize)) {
1722
+ if (newSize !== void 0 && prevSize !== void 0 && newSize !== prevSize) {
1651
1723
  const diff = newSize - prevSize;
1652
1724
  if (diff !== 0) {
1653
- positionDiff += (newSize - prevSize) * scrollingToViewPosition;
1725
+ positionDiff += diff * scrollingToViewPosition;
1654
1726
  scrollingTo.itemSize = newSize;
1655
1727
  }
1656
1728
  }
1657
1729
  }
1658
- if (Math.abs(positionDiff) > 0.1) {
1730
+ updateAnchorLock(state, {
1731
+ anchorId: anchorIdForLock,
1732
+ anchorPosition: anchorPositionForLock,
1733
+ dataChanged,
1734
+ now,
1735
+ positionDiff
1736
+ });
1737
+ if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
1659
1738
  requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
1660
1739
  }
1661
1740
  };
@@ -2310,26 +2389,16 @@ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPositi
2310
2389
  // src/utils/setDidLayout.ts
2311
2390
  function setDidLayout(ctx) {
2312
2391
  const state = ctx.state;
2313
- const {
2314
- loadStartTime,
2315
- initialScroll,
2316
- props: { onLoad }
2317
- } = state;
2392
+ const { initialScroll } = state;
2318
2393
  state.queuedInitialLayout = true;
2319
2394
  checkAtBottom(ctx);
2320
- const setIt = () => {
2321
- setInitialRenderState(ctx, { didLayout: true });
2322
- if (onLoad) {
2323
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2324
- }
2325
- };
2326
2395
  if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
2327
2396
  const target = initialScroll;
2328
2397
  const runScroll = () => scrollToIndex(ctx, { ...target, animated: false });
2329
2398
  runScroll();
2330
2399
  requestAnimationFrame(runScroll);
2331
2400
  }
2332
- setIt();
2401
+ setInitialRenderState(ctx, { didLayout: true });
2333
2402
  }
2334
2403
 
2335
2404
  // src/core/calculateItemsInView.ts
@@ -2369,7 +2438,7 @@ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentSt
2369
2438
  }
2370
2439
  }
2371
2440
  }
2372
- function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2441
+ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2373
2442
  var _a3, _b, _c;
2374
2443
  const state = ctx.state;
2375
2444
  for (const containerIndex of state.stickyContainerPool) {
@@ -2390,13 +2459,13 @@ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentSt
2390
2459
  if (nextIndex) {
2391
2460
  const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
2392
2461
  const nextPos = nextId ? state.positions.get(nextId) : void 0;
2393
- shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
2462
+ shouldRecycle = nextPos !== void 0 && scroll > nextPos + drawDistance * 2;
2394
2463
  } else {
2395
2464
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2396
2465
  if (currentId) {
2397
2466
  const currentPos = state.positions.get(currentId);
2398
2467
  const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2399
- shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2468
+ shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + drawDistance * 3;
2400
2469
  }
2401
2470
  }
2402
2471
  if (shouldRecycle) {
@@ -2421,11 +2490,11 @@ function calculateItemsInView(ctx, params = {}) {
2421
2490
  props: {
2422
2491
  alwaysRenderIndicesArr,
2423
2492
  alwaysRenderIndicesSet,
2493
+ drawDistance,
2424
2494
  getItemType,
2425
2495
  itemsAreEqual,
2426
2496
  keyExtractor,
2427
- onStickyHeaderChange,
2428
- scrollBuffer
2497
+ onStickyHeaderChange
2429
2498
  },
2430
2499
  scrollForNextCalculateItemsInView,
2431
2500
  scrollLength,
@@ -2438,6 +2507,7 @@ function calculateItemsInView(ctx, params = {}) {
2438
2507
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2439
2508
  const alwaysRenderArr = alwaysRenderIndicesArr || [];
2440
2509
  const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
2510
+ const { dataChanged, doMVCP, forceFullItemPositions } = params;
2441
2511
  const prevNumContainers = peek$(ctx, "numContainers");
2442
2512
  if (!data || scrollLength === 0 || !prevNumContainers) {
2443
2513
  if (!IsNewArchitecture && state.initialAnchor) {
@@ -2448,7 +2518,6 @@ function calculateItemsInView(ctx, params = {}) {
2448
2518
  const totalSize = getContentSize(ctx);
2449
2519
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
2450
2520
  const numColumns = peek$(ctx, "numColumns");
2451
- const { dataChanged, doMVCP, forceFullItemPositions } = params;
2452
2521
  const speed = getScrollVelocity(state);
2453
2522
  const scrollExtra = 0;
2454
2523
  const { queuedInitialLayout } = state;
@@ -2467,24 +2536,20 @@ function calculateItemsInView(ctx, params = {}) {
2467
2536
  if (scroll + scrollLength > totalSize) {
2468
2537
  scroll = Math.max(0, totalSize - scrollLength);
2469
2538
  }
2470
- if (ENABLE_DEBUG_VIEW) {
2471
- set$(ctx, "debugRawScroll", scrollState);
2472
- set$(ctx, "debugComputedScroll", scroll);
2473
- }
2474
2539
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
2475
2540
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2476
2541
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
2477
2542
  if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
2478
2543
  set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2479
2544
  }
2480
- let scrollBufferTop = scrollBuffer;
2481
- let scrollBufferBottom = scrollBuffer;
2482
- if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
2483
- scrollBufferTop = scrollBuffer * 0.5;
2484
- scrollBufferBottom = scrollBuffer * 1.5;
2545
+ let scrollBufferTop = drawDistance;
2546
+ let scrollBufferBottom = drawDistance;
2547
+ if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
2548
+ scrollBufferTop = drawDistance * 0.5;
2549
+ scrollBufferBottom = drawDistance * 1.5;
2485
2550
  } else {
2486
- scrollBufferTop = scrollBuffer * 1.5;
2487
- scrollBufferBottom = scrollBuffer * 0.5;
2551
+ scrollBufferTop = drawDistance * 1.5;
2552
+ scrollBufferBottom = drawDistance * 0.5;
2488
2553
  }
2489
2554
  const scrollTopBuffered = scroll - scrollBufferTop;
2490
2555
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
@@ -2497,7 +2562,9 @@ function calculateItemsInView(ctx, params = {}) {
2497
2562
  if (!IsNewArchitecture && state.initialAnchor) {
2498
2563
  ensureInitialAnchor(ctx);
2499
2564
  }
2500
- return;
2565
+ if (Platform2.OS !== "web" || !isInMVCPActiveMode(state)) {
2566
+ return;
2567
+ }
2501
2568
  }
2502
2569
  }
2503
2570
  const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
@@ -2729,7 +2796,7 @@ function calculateItemsInView(ctx, params = {}) {
2729
2796
  ctx,
2730
2797
  stickyIndicesArr,
2731
2798
  scroll,
2732
- scrollBuffer,
2799
+ drawDistance,
2733
2800
  currentStickyIdx,
2734
2801
  pendingRemoval,
2735
2802
  alwaysRenderSet
@@ -2942,10 +3009,10 @@ function doInitialAllocateContainers(ctx) {
2942
3009
  scrollLength,
2943
3010
  props: {
2944
3011
  data,
3012
+ drawDistance,
2945
3013
  getEstimatedItemSize,
2946
3014
  getFixedItemSize,
2947
3015
  getItemType,
2948
- scrollBuffer,
2949
3016
  numColumns,
2950
3017
  estimatedItemSize
2951
3018
  }
@@ -2967,7 +3034,7 @@ function doInitialAllocateContainers(ctx) {
2967
3034
  } else {
2968
3035
  averageItemSize = estimatedItemSize;
2969
3036
  }
2970
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize * numColumns);
3037
+ const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
2971
3038
  for (let i = 0; i < numContainers; i++) {
2972
3039
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2973
3040
  set$(ctx, `containerColumn${i}`, -1);
@@ -3055,8 +3122,8 @@ function onScroll(ctx, event) {
3055
3122
  }
3056
3123
  }
3057
3124
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3058
- if (state.scrollingTo) {
3059
- const maxOffset = clampScrollOffset(ctx, newScroll);
3125
+ if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
3126
+ const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
3060
3127
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3061
3128
  newScroll = maxOffset;
3062
3129
  scrollTo(ctx, {
@@ -3109,7 +3176,7 @@ var ScrollAdjustHandler = class {
3109
3176
  if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3110
3177
  const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3111
3178
  targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3112
- targetScroll = clampScrollOffset(this.ctx, targetScroll);
3179
+ targetScroll = clampScrollOffset(this.ctx, targetScroll, scrollTarget);
3113
3180
  } else {
3114
3181
  targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3115
3182
  }
@@ -3128,6 +3195,28 @@ var ScrollAdjustHandler = class {
3128
3195
  };
3129
3196
 
3130
3197
  // src/core/updateItemSize.ts
3198
+ function runOrScheduleMVCPRecalculate(ctx) {
3199
+ const state = ctx.state;
3200
+ if (Platform2.OS === "web") {
3201
+ if (!state.mvcpAnchorLock) {
3202
+ if (state.queuedMVCPRecalculate !== void 0) {
3203
+ cancelAnimationFrame(state.queuedMVCPRecalculate);
3204
+ state.queuedMVCPRecalculate = void 0;
3205
+ }
3206
+ calculateItemsInView(ctx, { doMVCP: true });
3207
+ return;
3208
+ }
3209
+ if (state.queuedMVCPRecalculate !== void 0) {
3210
+ return;
3211
+ }
3212
+ state.queuedMVCPRecalculate = requestAnimationFrame(() => {
3213
+ state.queuedMVCPRecalculate = void 0;
3214
+ calculateItemsInView(ctx, { doMVCP: true });
3215
+ });
3216
+ } else {
3217
+ calculateItemsInView(ctx, { doMVCP: true });
3218
+ }
3219
+ }
3131
3220
  function updateItemSize(ctx, itemKey, sizeObj) {
3132
3221
  var _a3;
3133
3222
  const state = ctx.state;
@@ -3211,7 +3300,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
3211
3300
  if (didContainersLayout || checkAllSizesKnown(state)) {
3212
3301
  if (needsRecalculate) {
3213
3302
  state.scrollForNextCalculateItemsInView = void 0;
3214
- calculateItemsInView(ctx, { doMVCP: true });
3303
+ runOrScheduleMVCPRecalculate(ctx);
3215
3304
  }
3216
3305
  if (shouldMaintainScrollAtEnd) {
3217
3306
  if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
@@ -3288,8 +3377,9 @@ function getWindowSize() {
3288
3377
  }
3289
3378
  var StyleSheet = StyleSheet$1;
3290
3379
  function useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, onScroll2) {
3380
+ const shouldUseRnAnimatedEngine = !ctx.state.props.stickyPositionComponentInternal;
3291
3381
  return useMemo(() => {
3292
- if (stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.length) {
3382
+ if ((stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.length) && shouldUseRnAnimatedEngine) {
3293
3383
  const { animatedScrollY } = ctx;
3294
3384
  return Animated.event(
3295
3385
  [
@@ -3306,7 +3396,7 @@ function useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, onScroll2)
3306
3396
  );
3307
3397
  }
3308
3398
  return onScroll2;
3309
- }, [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(","), horizontal]);
3399
+ }, [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(","), horizontal, shouldUseRnAnimatedEngine]);
3310
3400
  }
3311
3401
 
3312
3402
  // src/utils/createColumnWrapperStyle.ts
@@ -3342,7 +3432,30 @@ function createImperativeHandle(ctx) {
3342
3432
  }
3343
3433
  };
3344
3434
  const refScroller = state.refScroller;
3435
+ const clearCaches = (options) => {
3436
+ var _a3, _b;
3437
+ const mode = (_a3 = options == null ? void 0 : options.mode) != null ? _a3 : "sizes";
3438
+ state.sizes.clear();
3439
+ state.sizesKnown.clear();
3440
+ for (const key in state.averageSizes) {
3441
+ delete state.averageSizes[key];
3442
+ }
3443
+ state.minIndexSizeChanged = 0;
3444
+ state.scrollForNextCalculateItemsInView = void 0;
3445
+ state.pendingTotalSize = void 0;
3446
+ state.totalSize = 0;
3447
+ set$(ctx, "totalSize", 0);
3448
+ if (mode === "full") {
3449
+ state.indexByKey.clear();
3450
+ state.idCache.length = 0;
3451
+ state.positions.clear();
3452
+ state.columns.clear();
3453
+ state.columnSpans.clear();
3454
+ }
3455
+ (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
3456
+ };
3345
3457
  return {
3458
+ clearCaches,
3346
3459
  flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3347
3460
  getNativeScrollRef: () => refScroller.current,
3348
3461
  getScrollableNode: () => refScroller.current.getScrollableNode(),
@@ -3503,8 +3616,8 @@ function normalizeMaintainVisibleContentPosition(value) {
3503
3616
  if (value && typeof value === "object") {
3504
3617
  return {
3505
3618
  data: (_a3 = value.data) != null ? _a3 : false,
3506
- size: (_b = value.size) != null ? _b : true,
3507
- shouldRestorePosition: value.shouldRestorePosition
3619
+ shouldRestorePosition: value.shouldRestorePosition,
3620
+ size: (_b = value.size) != null ? _b : true
3508
3621
  };
3509
3622
  }
3510
3623
  if (value === false) {
@@ -3576,9 +3689,7 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
3576
3689
  }
3577
3690
 
3578
3691
  // src/components/LegendList.tsx
3579
- var DEFAULT_DRAW_DISTANCE = 250;
3580
- var DEFAULT_ITEM_SIZE = 100;
3581
- var LegendList = typedMemo(
3692
+ var LegendList = typedMemo2(
3582
3693
  // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
3583
3694
  typedForwardRef(function LegendList2(props, forwardedRef) {
3584
3695
  const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
@@ -3607,7 +3718,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3607
3718
  data: dataProp = [],
3608
3719
  dataVersion,
3609
3720
  drawDistance = 250,
3610
- estimatedItemSize: estimatedItemSizeProp,
3721
+ estimatedItemSize = 100,
3611
3722
  estimatedListSize,
3612
3723
  extraData,
3613
3724
  getEstimatedItemSize,
@@ -3659,7 +3770,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3659
3770
  ...rest
3660
3771
  } = props;
3661
3772
  const animatedPropsInternal = props.animatedPropsInternal;
3662
- const { childrenMode } = rest;
3773
+ const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
3774
+ const {
3775
+ childrenMode,
3776
+ stickyPositionComponentInternal: _stickyPositionComponentInternal,
3777
+ ...restProps
3778
+ } = rest;
3663
3779
  const contentContainerStyleBase = StyleSheet.flatten(contentContainerStyleProp);
3664
3780
  const shouldFlexGrow = alignItemsAtEnd && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
3665
3781
  const contentContainerStyle = {
@@ -3691,9 +3807,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3691
3807
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
3692
3808
  const refScroller = useRef(null);
3693
3809
  const combinedRef = useCombinedRef(refScroller, refScrollView);
3694
- const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
3695
- const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
3696
- const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
3810
+ const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
3697
3811
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
3698
3812
  const alwaysRenderIndices = useMemo(() => {
3699
3813
  const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor);
@@ -3722,8 +3836,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3722
3836
  ctx.state = {
3723
3837
  activeStickyIndex: -1,
3724
3838
  averageSizes: {},
3725
- columns: /* @__PURE__ */ new Map(),
3726
3839
  columnSpans: /* @__PURE__ */ new Map(),
3840
+ columns: /* @__PURE__ */ new Map(),
3727
3841
  containerItemKeys: /* @__PURE__ */ new Map(),
3728
3842
  containerItemTypes: /* @__PURE__ */ new Map(),
3729
3843
  contentInsetOverride: void 0,
@@ -3810,6 +3924,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3810
3924
  contentInset,
3811
3925
  data: dataProp,
3812
3926
  dataVersion,
3927
+ drawDistance,
3813
3928
  estimatedItemSize,
3814
3929
  getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3815
3930
  getFixedItemSize: useWrapIfItem(getFixedItemSize),
@@ -3833,10 +3948,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3833
3948
  overrideItemLayout,
3834
3949
  recycleItems: !!recycleItems,
3835
3950
  renderItem,
3836
- scrollBuffer,
3837
3951
  snapToIndices,
3838
3952
  stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
3839
3953
  stickyIndicesSet: useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
3954
+ stickyPositionComponentInternal,
3840
3955
  stylePaddingBottom: stylePaddingBottomState,
3841
3956
  stylePaddingTop: stylePaddingTopState,
3842
3957
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
@@ -3890,7 +4005,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3890
4005
  } else {
3891
4006
  const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
3892
4007
  const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
3893
- const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
4008
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset, initialScroll);
3894
4009
  const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3895
4010
  refState.current.initialScroll = updatedInitialScroll;
3896
4011
  state.initialScroll = updatedInitialScroll;
@@ -4046,7 +4161,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4046
4161
  return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(
4047
4162
  ListComponent,
4048
4163
  {
4049
- ...rest,
4164
+ ...restProps,
4050
4165
  alignItemsAtEnd,
4051
4166
  canRender,
4052
4167
  contentContainerStyle,
@@ -4080,7 +4195,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4080
4195
  updateItemSize: fns.updateItemSize,
4081
4196
  waitForInitialLayout
4082
4197
  }
4083
- ), IS_DEV && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React2.createElement(DebugView, { state: refState.current }));
4198
+ ), IS_DEV && ENABLE_DEBUG_VIEW);
4084
4199
  });
4085
4200
 
4086
- export { LegendList, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
4201
+ // src/index.ts
4202
+ var LegendList3 = LegendList;
4203
+ if (IS_DEV) {
4204
+ console.warn(
4205
+ "[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."
4206
+ );
4207
+ }
4208
+
4209
+ export { LegendList3 as LegendList, typedForwardRef, typedMemo2 as typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };