@legendapp/list 3.0.0-beta.32 → 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 (54) hide show
  1. package/README.md +7 -1
  2. package/animated.d.ts +600 -6
  3. package/animated.js +2 -2
  4. package/animated.mjs +1 -1
  5. package/index.d.ts +454 -108
  6. package/index.js +81 -32
  7. package/index.mjs +81 -32
  8. package/index.native.js +89 -44
  9. package/index.native.mjs +88 -43
  10. package/keyboard-controller.d.ts +611 -6
  11. package/keyboard-controller.js +2 -2
  12. package/keyboard-controller.mjs +1 -1
  13. package/keyboard.d.ts +204 -8
  14. package/keyboard.js +66 -52
  15. package/keyboard.mjs +69 -54
  16. package/{index.d.mts → list-react-native.d.ts} +95 -32
  17. package/list-react-native.js +4234 -0
  18. package/list-react-native.mjs +4204 -0
  19. package/{index.native.d.mts → list-react.d.ts} +355 -40
  20. package/list-react.js +4426 -0
  21. package/list-react.mjs +4396 -0
  22. package/package.json +52 -1
  23. package/reanimated.d.ts +595 -7
  24. package/reanimated.js +156 -11
  25. package/reanimated.mjs +153 -8
  26. package/section-list.d.ts +610 -14
  27. package/section-list.js +6 -6
  28. package/section-list.mjs +1 -1
  29. package/animated.d.mts +0 -9
  30. package/animated.native.d.mts +0 -9
  31. package/animated.native.d.ts +0 -9
  32. package/animated.native.js +0 -9
  33. package/animated.native.mjs +0 -7
  34. package/index.native.d.ts +0 -817
  35. package/keyboard-controller.d.mts +0 -12
  36. package/keyboard-controller.native.d.mts +0 -12
  37. package/keyboard-controller.native.d.ts +0 -12
  38. package/keyboard-controller.native.js +0 -69
  39. package/keyboard-controller.native.mjs +0 -48
  40. package/keyboard.d.mts +0 -13
  41. package/keyboard.native.d.mts +0 -13
  42. package/keyboard.native.d.ts +0 -13
  43. package/keyboard.native.js +0 -399
  44. package/keyboard.native.mjs +0 -377
  45. package/reanimated.d.mts +0 -18
  46. package/reanimated.native.d.mts +0 -18
  47. package/reanimated.native.d.ts +0 -18
  48. package/reanimated.native.js +0 -89
  49. package/reanimated.native.mjs +0 -65
  50. package/section-list.d.mts +0 -112
  51. package/section-list.native.d.mts +0 -112
  52. package/section-list.native.d.ts +0 -112
  53. package/section-list.native.js +0 -293
  54. package/section-list.native.mjs +0 -271
package/index.js CHANGED
@@ -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
  };
@@ -642,6 +645,7 @@ var Container = typedMemo(function Container2({
642
645
  }) {
643
646
  const ctx = useStateContext();
644
647
  const { columnWrapperStyle, animatedScrollY } = ctx;
648
+ const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
645
649
  const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
646
650
  `containerColumn${id}`,
647
651
  `containerSpan${id}`,
@@ -767,7 +771,7 @@ var Container = typedMemo(function Container2({
767
771
  },
768
772
  [itemKey, layoutRenderCount]
769
773
  );
770
- const PositionComponent = isSticky ? PositionViewSticky : PositionView;
774
+ const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : PositionView;
771
775
  return /* @__PURE__ */ React3__namespace.createElement(
772
776
  PositionComponent,
773
777
  {
@@ -1219,7 +1223,9 @@ var ListComponent = typedMemo(function ListComponent2({
1219
1223
  const ctx = useStateContext();
1220
1224
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1221
1225
  const ScrollComponent = renderScrollComponent ? React3.useMemo(
1222
- () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1226
+ () => React3__namespace.forwardRef(
1227
+ (props, ref) => renderScrollComponent({ ...props, ref })
1228
+ ),
1223
1229
  [renderScrollComponent]
1224
1230
  ) : ListComponentScrollView;
1225
1231
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
@@ -1410,12 +1416,15 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1410
1416
  }
1411
1417
 
1412
1418
  // src/core/clampScrollOffset.ts
1413
- function clampScrollOffset(ctx, offset) {
1419
+ function clampScrollOffset(ctx, offset, scrollTarget) {
1414
1420
  const state = ctx.state;
1415
1421
  const contentSize = getContentSize(ctx);
1416
1422
  let clampedOffset = offset;
1417
1423
  if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android")) {
1418
- 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;
1419
1428
  clampedOffset = Math.min(offset, maxOffset);
1420
1429
  }
1421
1430
  clampedOffset = Math.max(0, clampedOffset);
@@ -1510,7 +1519,7 @@ function checkAtBottom(ctx) {
1510
1519
  function checkAtTop(ctx) {
1511
1520
  var _a3;
1512
1521
  const state = ctx == null ? void 0 : ctx.state;
1513
- if (!state || state.initialScroll) {
1522
+ if (!state || state.initialScroll || state.scrollingTo) {
1514
1523
  return;
1515
1524
  }
1516
1525
  const {
@@ -1554,14 +1563,22 @@ function setInitialRenderState(ctx, {
1554
1563
  didInitialScroll
1555
1564
  }) {
1556
1565
  const { state } = ctx;
1566
+ const {
1567
+ loadStartTime,
1568
+ props: { onLoad }
1569
+ } = state;
1557
1570
  if (didLayout) {
1558
1571
  state.didContainersLayout = true;
1559
1572
  }
1560
1573
  if (didInitialScroll) {
1561
1574
  state.didFinishInitialScroll = true;
1562
1575
  }
1563
- if (state.didContainersLayout && state.didFinishInitialScroll) {
1576
+ const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
1577
+ if (isReadyToRender && !peek$(ctx, "readyToRender")) {
1564
1578
  set$(ctx, "readyToRender", true);
1579
+ if (onLoad) {
1580
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1581
+ }
1565
1582
  }
1566
1583
  }
1567
1584
 
@@ -1683,7 +1700,7 @@ function scrollTo(ctx, params) {
1683
1700
  clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1684
1701
  }
1685
1702
  let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1686
- offset = clampScrollOffset(ctx, offset);
1703
+ offset = clampScrollOffset(ctx, offset, scrollTarget);
1687
1704
  state.scrollHistory.length = 0;
1688
1705
  if (!noScrollingTo) {
1689
1706
  state.scrollingTo = scrollTarget;
@@ -1836,6 +1853,7 @@ function prepareMVCP(ctx, dataChanged) {
1836
1853
  const idsInViewWithPositions = [];
1837
1854
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1838
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;
1839
1857
  const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1840
1858
  const indexByKey = state.indexByKey;
1841
1859
  if (shouldMVCP) {
@@ -1901,7 +1919,7 @@ function prepareMVCP(ctx, dataChanged) {
1901
1919
  if (newPosition !== void 0) {
1902
1920
  const totalSize = getContentSize(ctx);
1903
1921
  let diff = newPosition - prevPosition;
1904
- if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1922
+ if (diff !== 0 && isEndAnchoredScrollTarget && state.scroll + state.scrollLength > totalSize) {
1905
1923
  if (diff > 0) {
1906
1924
  diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
1907
1925
  } else {
@@ -2586,26 +2604,16 @@ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPositi
2586
2604
  // src/utils/setDidLayout.ts
2587
2605
  function setDidLayout(ctx) {
2588
2606
  const state = ctx.state;
2589
- const {
2590
- loadStartTime,
2591
- initialScroll,
2592
- props: { onLoad }
2593
- } = state;
2607
+ const { initialScroll } = state;
2594
2608
  state.queuedInitialLayout = true;
2595
2609
  checkAtBottom(ctx);
2596
- const setIt = () => {
2597
- setInitialRenderState(ctx, { didLayout: true });
2598
- if (onLoad) {
2599
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2600
- }
2601
- };
2602
2610
  if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
2603
2611
  const target = initialScroll;
2604
2612
  const runScroll = () => scrollToIndex(ctx, { ...target, animated: false });
2605
2613
  runScroll();
2606
2614
  requestAnimationFrame(runScroll);
2607
2615
  }
2608
- setIt();
2616
+ setInitialRenderState(ctx, { didLayout: true });
2609
2617
  }
2610
2618
 
2611
2619
  // src/core/calculateItemsInView.ts
@@ -3104,8 +3112,12 @@ function checkFinishedScrollFrame(ctx) {
3104
3112
  state.animFrameCheckFinishedScroll = void 0;
3105
3113
  const scroll = state.scrollPending;
3106
3114
  const adjust = state.scrollAdjustHandler.getAdjust();
3107
- const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
3108
- 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);
3109
3121
  const diff1 = Math.abs(scroll - clampedTargetOffset);
3110
3122
  const diff2 = Math.abs(diff1 - adjust);
3111
3123
  const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
@@ -3368,7 +3380,7 @@ function onScroll(ctx, event) {
3368
3380
  }
3369
3381
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3370
3382
  if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
3371
- const maxOffset = clampScrollOffset(ctx, newScroll);
3383
+ const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
3372
3384
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3373
3385
  newScroll = maxOffset;
3374
3386
  scrollTo(ctx, {
@@ -3421,7 +3433,7 @@ var ScrollAdjustHandler = class {
3421
3433
  if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3422
3434
  const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3423
3435
  targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3424
- targetScroll = clampScrollOffset(this.ctx, targetScroll);
3436
+ targetScroll = clampScrollOffset(this.ctx, targetScroll, scrollTarget);
3425
3437
  } else {
3426
3438
  targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3427
3439
  }
@@ -3655,7 +3667,30 @@ function createImperativeHandle(ctx) {
3655
3667
  }
3656
3668
  };
3657
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
+ };
3658
3692
  return {
3693
+ clearCaches,
3659
3694
  flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3660
3695
  getNativeScrollRef: () => refScroller.current,
3661
3696
  getScrollableNode: () => refScroller.current.getScrollableNode(),
@@ -3816,8 +3851,8 @@ function normalizeMaintainVisibleContentPosition(value) {
3816
3851
  if (value && typeof value === "object") {
3817
3852
  return {
3818
3853
  data: (_a3 = value.data) != null ? _a3 : false,
3819
- size: (_b = value.size) != null ? _b : true,
3820
- shouldRestorePosition: value.shouldRestorePosition
3854
+ shouldRestorePosition: value.shouldRestorePosition,
3855
+ size: (_b = value.size) != null ? _b : true
3821
3856
  };
3822
3857
  }
3823
3858
  if (value === false) {
@@ -3970,7 +4005,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3970
4005
  ...rest
3971
4006
  } = props;
3972
4007
  const animatedPropsInternal = props.animatedPropsInternal;
3973
- const { childrenMode } = rest;
4008
+ const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
4009
+ const {
4010
+ childrenMode,
4011
+ stickyPositionComponentInternal: _stickyPositionComponentInternal,
4012
+ ...restProps
4013
+ } = rest;
3974
4014
  const contentContainerStyleBase = StyleSheet.flatten(contentContainerStyleProp);
3975
4015
  const shouldFlexGrow = alignItemsAtEnd && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
3976
4016
  const contentContainerStyle = {
@@ -4146,6 +4186,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4146
4186
  snapToIndices,
4147
4187
  stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
4148
4188
  stickyIndicesSet: React3.useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
4189
+ stickyPositionComponentInternal,
4149
4190
  stylePaddingBottom: stylePaddingBottomState,
4150
4191
  stylePaddingTop: stylePaddingTopState,
4151
4192
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
@@ -4184,7 +4225,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4184
4225
  } else {
4185
4226
  const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
4186
4227
  const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
4187
- const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
4228
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset, initialScroll);
4188
4229
  const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
4189
4230
  refState.current.initialScroll = updatedInitialScroll;
4190
4231
  state.initialScroll = updatedInitialScroll;
@@ -4333,7 +4374,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4333
4374
  return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(
4334
4375
  ListComponent,
4335
4376
  {
4336
- ...rest,
4377
+ ...restProps,
4337
4378
  alignItemsAtEnd,
4338
4379
  canRender,
4339
4380
  contentContainerStyle,
@@ -4370,7 +4411,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4370
4411
  ), IS_DEV && ENABLE_DEBUG_VIEW);
4371
4412
  });
4372
4413
 
4373
- 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;
4374
4423
  exports.typedForwardRef = typedForwardRef;
4375
4424
  exports.typedMemo = typedMemo;
4376
4425
  exports.useIsLastItem = useIsLastItem;
package/index.mjs CHANGED
@@ -224,7 +224,7 @@ var _a;
224
224
  var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
225
225
  var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
226
226
  var _a2;
227
- var IS_DEV = (_a2 = metroDev != null ? metroDev : processDev) != null ? _a2 : false;
227
+ var IS_DEV = (_a2 = processDev != null ? processDev : metroDev) != null ? _a2 : false;
228
228
 
229
229
  // src/constants.ts
230
230
  var POSITION_OUT_OF_VIEW = -1e7;
@@ -307,7 +307,10 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
307
307
  children,
308
308
  ...rest
309
309
  }) {
310
- const [position = POSITION_OUT_OF_VIEW, activeStickyIndex] = useArr$([`containerPosition${id}`, "activeStickyIndex"]);
310
+ const [position = POSITION_OUT_OF_VIEW, activeStickyIndex] = useArr$([
311
+ `containerPosition${id}`,
312
+ "activeStickyIndex"
313
+ ]);
311
314
  const base = {
312
315
  contain: "paint layout style"
313
316
  };
@@ -621,6 +624,7 @@ var Container = typedMemo(function Container2({
621
624
  }) {
622
625
  const ctx = useStateContext();
623
626
  const { columnWrapperStyle, animatedScrollY } = ctx;
627
+ const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
624
628
  const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
625
629
  `containerColumn${id}`,
626
630
  `containerSpan${id}`,
@@ -746,7 +750,7 @@ var Container = typedMemo(function Container2({
746
750
  },
747
751
  [itemKey, layoutRenderCount]
748
752
  );
749
- const PositionComponent = isSticky ? PositionViewSticky : PositionView;
753
+ const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : PositionView;
750
754
  return /* @__PURE__ */ React3.createElement(
751
755
  PositionComponent,
752
756
  {
@@ -1198,7 +1202,9 @@ var ListComponent = typedMemo(function ListComponent2({
1198
1202
  const ctx = useStateContext();
1199
1203
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1200
1204
  const ScrollComponent = renderScrollComponent ? useMemo(
1201
- () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1205
+ () => React3.forwardRef(
1206
+ (props, ref) => renderScrollComponent({ ...props, ref })
1207
+ ),
1202
1208
  [renderScrollComponent]
1203
1209
  ) : ListComponentScrollView;
1204
1210
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
@@ -1389,12 +1395,15 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1389
1395
  }
1390
1396
 
1391
1397
  // src/core/clampScrollOffset.ts
1392
- function clampScrollOffset(ctx, offset) {
1398
+ function clampScrollOffset(ctx, offset, scrollTarget) {
1393
1399
  const state = ctx.state;
1394
1400
  const contentSize = getContentSize(ctx);
1395
1401
  let clampedOffset = offset;
1396
1402
  if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android")) {
1397
- const maxOffset = Math.max(0, contentSize - state.scrollLength);
1403
+ const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
1404
+ const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
1405
+ const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
1406
+ const maxOffset = baseMaxOffset + extraEndOffset;
1398
1407
  clampedOffset = Math.min(offset, maxOffset);
1399
1408
  }
1400
1409
  clampedOffset = Math.max(0, clampedOffset);
@@ -1489,7 +1498,7 @@ function checkAtBottom(ctx) {
1489
1498
  function checkAtTop(ctx) {
1490
1499
  var _a3;
1491
1500
  const state = ctx == null ? void 0 : ctx.state;
1492
- if (!state || state.initialScroll) {
1501
+ if (!state || state.initialScroll || state.scrollingTo) {
1493
1502
  return;
1494
1503
  }
1495
1504
  const {
@@ -1533,14 +1542,22 @@ function setInitialRenderState(ctx, {
1533
1542
  didInitialScroll
1534
1543
  }) {
1535
1544
  const { state } = ctx;
1545
+ const {
1546
+ loadStartTime,
1547
+ props: { onLoad }
1548
+ } = state;
1536
1549
  if (didLayout) {
1537
1550
  state.didContainersLayout = true;
1538
1551
  }
1539
1552
  if (didInitialScroll) {
1540
1553
  state.didFinishInitialScroll = true;
1541
1554
  }
1542
- if (state.didContainersLayout && state.didFinishInitialScroll) {
1555
+ const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
1556
+ if (isReadyToRender && !peek$(ctx, "readyToRender")) {
1543
1557
  set$(ctx, "readyToRender", true);
1558
+ if (onLoad) {
1559
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1560
+ }
1544
1561
  }
1545
1562
  }
1546
1563
 
@@ -1662,7 +1679,7 @@ function scrollTo(ctx, params) {
1662
1679
  clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1663
1680
  }
1664
1681
  let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1665
- offset = clampScrollOffset(ctx, offset);
1682
+ offset = clampScrollOffset(ctx, offset, scrollTarget);
1666
1683
  state.scrollHistory.length = 0;
1667
1684
  if (!noScrollingTo) {
1668
1685
  state.scrollingTo = scrollTarget;
@@ -1815,6 +1832,7 @@ function prepareMVCP(ctx, dataChanged) {
1815
1832
  const idsInViewWithPositions = [];
1816
1833
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1817
1834
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1835
+ const isEndAnchoredScrollTarget = scrollTarget !== void 0 && state.props.data.length > 0 && scrollTarget >= state.props.data.length - 1 && (scrollingToViewPosition != null ? scrollingToViewPosition : 0) > 0;
1818
1836
  const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1819
1837
  const indexByKey = state.indexByKey;
1820
1838
  if (shouldMVCP) {
@@ -1880,7 +1898,7 @@ function prepareMVCP(ctx, dataChanged) {
1880
1898
  if (newPosition !== void 0) {
1881
1899
  const totalSize = getContentSize(ctx);
1882
1900
  let diff = newPosition - prevPosition;
1883
- if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1901
+ if (diff !== 0 && isEndAnchoredScrollTarget && state.scroll + state.scrollLength > totalSize) {
1884
1902
  if (diff > 0) {
1885
1903
  diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
1886
1904
  } else {
@@ -2565,26 +2583,16 @@ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPositi
2565
2583
  // src/utils/setDidLayout.ts
2566
2584
  function setDidLayout(ctx) {
2567
2585
  const state = ctx.state;
2568
- const {
2569
- loadStartTime,
2570
- initialScroll,
2571
- props: { onLoad }
2572
- } = state;
2586
+ const { initialScroll } = state;
2573
2587
  state.queuedInitialLayout = true;
2574
2588
  checkAtBottom(ctx);
2575
- const setIt = () => {
2576
- setInitialRenderState(ctx, { didLayout: true });
2577
- if (onLoad) {
2578
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2579
- }
2580
- };
2581
2589
  if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
2582
2590
  const target = initialScroll;
2583
2591
  const runScroll = () => scrollToIndex(ctx, { ...target, animated: false });
2584
2592
  runScroll();
2585
2593
  requestAnimationFrame(runScroll);
2586
2594
  }
2587
- setIt();
2595
+ setInitialRenderState(ctx, { didLayout: true });
2588
2596
  }
2589
2597
 
2590
2598
  // src/core/calculateItemsInView.ts
@@ -3083,8 +3091,12 @@ function checkFinishedScrollFrame(ctx) {
3083
3091
  state.animFrameCheckFinishedScroll = void 0;
3084
3092
  const scroll = state.scrollPending;
3085
3093
  const adjust = state.scrollAdjustHandler.getAdjust();
3086
- const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
3087
- const maxOffset = clampScrollOffset(ctx, scroll);
3094
+ const clampedTargetOffset = clampScrollOffset(
3095
+ ctx,
3096
+ scrollingTo.offset - (scrollingTo.viewOffset || 0),
3097
+ scrollingTo
3098
+ );
3099
+ const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
3088
3100
  const diff1 = Math.abs(scroll - clampedTargetOffset);
3089
3101
  const diff2 = Math.abs(diff1 - adjust);
3090
3102
  const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
@@ -3347,7 +3359,7 @@ function onScroll(ctx, event) {
3347
3359
  }
3348
3360
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3349
3361
  if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
3350
- const maxOffset = clampScrollOffset(ctx, newScroll);
3362
+ const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
3351
3363
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
3352
3364
  newScroll = maxOffset;
3353
3365
  scrollTo(ctx, {
@@ -3400,7 +3412,7 @@ var ScrollAdjustHandler = class {
3400
3412
  if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3401
3413
  const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3402
3414
  targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3403
- targetScroll = clampScrollOffset(this.ctx, targetScroll);
3415
+ targetScroll = clampScrollOffset(this.ctx, targetScroll, scrollTarget);
3404
3416
  } else {
3405
3417
  targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3406
3418
  }
@@ -3634,7 +3646,30 @@ function createImperativeHandle(ctx) {
3634
3646
  }
3635
3647
  };
3636
3648
  const refScroller = state.refScroller;
3649
+ const clearCaches = (options) => {
3650
+ var _a3, _b;
3651
+ const mode = (_a3 = options == null ? void 0 : options.mode) != null ? _a3 : "sizes";
3652
+ state.sizes.clear();
3653
+ state.sizesKnown.clear();
3654
+ for (const key in state.averageSizes) {
3655
+ delete state.averageSizes[key];
3656
+ }
3657
+ state.minIndexSizeChanged = 0;
3658
+ state.scrollForNextCalculateItemsInView = void 0;
3659
+ state.pendingTotalSize = void 0;
3660
+ state.totalSize = 0;
3661
+ set$(ctx, "totalSize", 0);
3662
+ if (mode === "full") {
3663
+ state.indexByKey.clear();
3664
+ state.idCache.length = 0;
3665
+ state.positions.clear();
3666
+ state.columns.clear();
3667
+ state.columnSpans.clear();
3668
+ }
3669
+ (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
3670
+ };
3637
3671
  return {
3672
+ clearCaches,
3638
3673
  flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3639
3674
  getNativeScrollRef: () => refScroller.current,
3640
3675
  getScrollableNode: () => refScroller.current.getScrollableNode(),
@@ -3795,8 +3830,8 @@ function normalizeMaintainVisibleContentPosition(value) {
3795
3830
  if (value && typeof value === "object") {
3796
3831
  return {
3797
3832
  data: (_a3 = value.data) != null ? _a3 : false,
3798
- size: (_b = value.size) != null ? _b : true,
3799
- shouldRestorePosition: value.shouldRestorePosition
3833
+ shouldRestorePosition: value.shouldRestorePosition,
3834
+ size: (_b = value.size) != null ? _b : true
3800
3835
  };
3801
3836
  }
3802
3837
  if (value === false) {
@@ -3949,7 +3984,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3949
3984
  ...rest
3950
3985
  } = props;
3951
3986
  const animatedPropsInternal = props.animatedPropsInternal;
3952
- const { childrenMode } = rest;
3987
+ const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
3988
+ const {
3989
+ childrenMode,
3990
+ stickyPositionComponentInternal: _stickyPositionComponentInternal,
3991
+ ...restProps
3992
+ } = rest;
3953
3993
  const contentContainerStyleBase = StyleSheet.flatten(contentContainerStyleProp);
3954
3994
  const shouldFlexGrow = alignItemsAtEnd && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
3955
3995
  const contentContainerStyle = {
@@ -4125,6 +4165,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4125
4165
  snapToIndices,
4126
4166
  stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
4127
4167
  stickyIndicesSet: useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
4168
+ stickyPositionComponentInternal,
4128
4169
  stylePaddingBottom: stylePaddingBottomState,
4129
4170
  stylePaddingTop: stylePaddingTopState,
4130
4171
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
@@ -4163,7 +4204,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4163
4204
  } else {
4164
4205
  const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
4165
4206
  const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
4166
- const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
4207
+ const clampedOffset = clampScrollOffset(ctx, resolvedOffset, initialScroll);
4167
4208
  const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
4168
4209
  refState.current.initialScroll = updatedInitialScroll;
4169
4210
  state.initialScroll = updatedInitialScroll;
@@ -4312,7 +4353,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4312
4353
  return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
4313
4354
  ListComponent,
4314
4355
  {
4315
- ...rest,
4356
+ ...restProps,
4316
4357
  alignItemsAtEnd,
4317
4358
  canRender,
4318
4359
  contentContainerStyle,
@@ -4349,4 +4390,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4349
4390
  ), IS_DEV && ENABLE_DEBUG_VIEW);
4350
4391
  });
4351
4392
 
4352
- export { LegendList, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
4393
+ // src/index.ts
4394
+ var LegendList3 = LegendList;
4395
+ if (IS_DEV) {
4396
+ console.warn(
4397
+ "[legend-list] Legend List 3.0 deprecates the root import (@legendapp/list) because it now supports both react and react-native. The root import is fully functional, but please switch to platform-specific imports for strict platform types:\n - React Native: @legendapp/list/react-native\n - React: @legendapp/list/react\nSee README for details."
4398
+ );
4399
+ }
4400
+
4401
+ export { LegendList3 as LegendList, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };