@legendapp/list 2.1.0-beta.10 → 2.1.0-beta.11

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.
package/index.d.mts CHANGED
@@ -395,12 +395,14 @@ interface InternalState {
395
395
  refScroller: React.RefObject<ScrollView>;
396
396
  loadStartTime: number;
397
397
  initialScroll: ScrollIndexWithOffsetAndContentOffset | undefined;
398
+ initialAnchor?: InitialScrollAnchor;
398
399
  lastLayout: LayoutRectangle | undefined;
399
400
  timeoutSetPaddingTop?: any;
400
401
  activeStickyIndex: number | undefined;
401
402
  stickyContainers: Map<number, number>;
402
403
  stickyContainerPool: Set<number>;
403
404
  scrollProcessingEnabled: boolean;
405
+ pendingTotalSize?: number;
404
406
  props: {
405
407
  alignItemsAtEnd: boolean;
406
408
  data: readonly any[];
@@ -638,14 +640,20 @@ type TypedMemo = <T extends React.ComponentType<any>>(Component: T, propsAreEqua
638
640
  declare const typedMemo: TypedMemo;
639
641
  interface ScrollIndexWithOffset {
640
642
  index: number;
641
- viewOffset: number;
643
+ viewOffset?: number;
644
+ viewPosition?: number;
642
645
  }
643
646
  interface ScrollIndexWithOffsetPosition extends ScrollIndexWithOffset {
644
- viewPosition: number;
647
+ viewPosition?: number;
645
648
  }
646
- interface ScrollIndexWithOffsetAndContentOffset extends ScrollIndexWithOffset {
649
+ interface ScrollIndexWithOffsetAndContentOffset extends ScrollIndexWithOffsetPosition {
647
650
  contentOffset?: number;
648
651
  }
652
+ interface InitialScrollAnchor extends ScrollIndexWithOffsetPosition {
653
+ attempts?: number;
654
+ lastDelta?: number;
655
+ settledTicks?: number;
656
+ }
649
657
  type GetRenderedItemResult<ItemT> = {
650
658
  index: number;
651
659
  item: ItemT;
@@ -668,4 +676,4 @@ declare function useListScrollSize(): {
668
676
  };
669
677
  declare function useSyncLayout(): () => void;
670
678
 
671
- export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type MaintainScrollAtEndOptions, type OnViewableItemsChanged, type ScrollIndexWithOffset, type ScrollIndexWithOffsetAndContentOffset, type ScrollIndexWithOffsetPosition, type ScrollState, type ScrollTarget, type ThresholdSnapshot, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
679
+ export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InitialScrollAnchor, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type MaintainScrollAtEndOptions, type OnViewableItemsChanged, type ScrollIndexWithOffset, type ScrollIndexWithOffsetAndContentOffset, type ScrollIndexWithOffsetPosition, type ScrollState, type ScrollTarget, type ThresholdSnapshot, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
package/index.d.ts CHANGED
@@ -395,12 +395,14 @@ interface InternalState {
395
395
  refScroller: React.RefObject<ScrollView>;
396
396
  loadStartTime: number;
397
397
  initialScroll: ScrollIndexWithOffsetAndContentOffset | undefined;
398
+ initialAnchor?: InitialScrollAnchor;
398
399
  lastLayout: LayoutRectangle | undefined;
399
400
  timeoutSetPaddingTop?: any;
400
401
  activeStickyIndex: number | undefined;
401
402
  stickyContainers: Map<number, number>;
402
403
  stickyContainerPool: Set<number>;
403
404
  scrollProcessingEnabled: boolean;
405
+ pendingTotalSize?: number;
404
406
  props: {
405
407
  alignItemsAtEnd: boolean;
406
408
  data: readonly any[];
@@ -638,14 +640,20 @@ type TypedMemo = <T extends React.ComponentType<any>>(Component: T, propsAreEqua
638
640
  declare const typedMemo: TypedMemo;
639
641
  interface ScrollIndexWithOffset {
640
642
  index: number;
641
- viewOffset: number;
643
+ viewOffset?: number;
644
+ viewPosition?: number;
642
645
  }
643
646
  interface ScrollIndexWithOffsetPosition extends ScrollIndexWithOffset {
644
- viewPosition: number;
647
+ viewPosition?: number;
645
648
  }
646
- interface ScrollIndexWithOffsetAndContentOffset extends ScrollIndexWithOffset {
649
+ interface ScrollIndexWithOffsetAndContentOffset extends ScrollIndexWithOffsetPosition {
647
650
  contentOffset?: number;
648
651
  }
652
+ interface InitialScrollAnchor extends ScrollIndexWithOffsetPosition {
653
+ attempts?: number;
654
+ lastDelta?: number;
655
+ settledTicks?: number;
656
+ }
649
657
  type GetRenderedItemResult<ItemT> = {
650
658
  index: number;
651
659
  item: ItemT;
@@ -668,4 +676,4 @@ declare function useListScrollSize(): {
668
676
  };
669
677
  declare function useSyncLayout(): () => void;
670
678
 
671
- export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type MaintainScrollAtEndOptions, type OnViewableItemsChanged, type ScrollIndexWithOffset, type ScrollIndexWithOffsetAndContentOffset, type ScrollIndexWithOffsetPosition, type ScrollState, type ScrollTarget, type ThresholdSnapshot, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
679
+ export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InitialScrollAnchor, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type MaintainScrollAtEndOptions, type OnViewableItemsChanged, type ScrollIndexWithOffset, type ScrollIndexWithOffsetAndContentOffset, type ScrollIndexWithOffsetPosition, type ScrollState, type ScrollTarget, type ThresholdSnapshot, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
package/index.js CHANGED
@@ -126,11 +126,12 @@ function set$(ctx, signalName, value) {
126
126
  }
127
127
  }
128
128
  function getContentSize(ctx) {
129
+ var _a3, _b;
129
130
  const { values } = ctx;
130
131
  const stylePaddingTop = values.get("stylePaddingTop") || 0;
131
132
  const headerSize = values.get("headerSize") || 0;
132
133
  const footerSize = values.get("footerSize") || 0;
133
- const totalSize = values.get("totalSize");
134
+ const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
134
135
  return headerSize + footerSize + totalSize + stylePaddingTop;
135
136
  }
136
137
  function useArr$(signalNames) {
@@ -1241,44 +1242,28 @@ function updateAlignItemsPaddingTop(ctx, state) {
1241
1242
  }
1242
1243
  }
1243
1244
 
1244
- // src/core/updateTotalSize.ts
1245
- function updateTotalSize(ctx, state) {
1246
- const {
1247
- positions,
1248
- props: { data }
1249
- } = state;
1250
- if (data.length === 0) {
1251
- addTotalSize(ctx, state, null, 0);
1252
- } else {
1253
- const lastId = getId(state, data.length - 1);
1254
- if (lastId !== void 0) {
1255
- const lastPosition = positions.get(lastId);
1256
- if (lastPosition !== void 0) {
1257
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1258
- if (lastSize !== void 0) {
1259
- const totalSize = lastPosition + lastSize;
1260
- addTotalSize(ctx, state, null, totalSize);
1261
- }
1262
- }
1263
- }
1264
- }
1265
- }
1245
+ // src/core/addTotalSize.ts
1266
1246
  function addTotalSize(ctx, state, key, add) {
1267
1247
  const { alignItemsAtEnd } = state.props;
1268
1248
  const prevTotalSize = state.totalSize;
1249
+ let totalSize = state.totalSize;
1269
1250
  if (key === null) {
1270
- state.totalSize = add;
1251
+ totalSize = add;
1271
1252
  if (state.timeoutSetPaddingTop) {
1272
1253
  clearTimeout(state.timeoutSetPaddingTop);
1273
1254
  state.timeoutSetPaddingTop = void 0;
1274
1255
  }
1275
1256
  } else {
1276
- state.totalSize += add;
1257
+ totalSize += add;
1277
1258
  }
1278
- if (prevTotalSize !== state.totalSize) {
1279
- set$(ctx, "totalSize", state.totalSize);
1280
- if (alignItemsAtEnd) {
1281
- updateAlignItemsPaddingTop(ctx, state);
1259
+ if (prevTotalSize !== totalSize) {
1260
+ {
1261
+ state.pendingTotalSize = void 0;
1262
+ state.totalSize = totalSize;
1263
+ set$(ctx, "totalSize", totalSize);
1264
+ if (alignItemsAtEnd) {
1265
+ updateAlignItemsPaddingTop(ctx, state);
1266
+ }
1282
1267
  }
1283
1268
  }
1284
1269
  }
@@ -1483,6 +1468,7 @@ function onScroll(ctx, state, event) {
1483
1468
  onScrollProp == null ? void 0 : onScrollProp(event);
1484
1469
  }
1485
1470
  function updateScroll(ctx, state, newScroll, forceUpdate) {
1471
+ var _a3;
1486
1472
  const scrollingTo = peek$(ctx, "scrollingTo");
1487
1473
  state.hasScrolled = true;
1488
1474
  state.lastBatchingAction = Date.now();
@@ -1516,7 +1502,7 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1516
1502
  }
1517
1503
  if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1518
1504
  state.ignoreScrollFromMVCPIgnored = false;
1519
- calculateItemsInView(ctx, state, { doMVCP: scrollingTo !== void 0 });
1505
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1520
1506
  checkAtBottom(ctx, state);
1521
1507
  checkAtTop(state);
1522
1508
  state.dataChangeNeedsScrollUpdate = false;
@@ -1529,7 +1515,11 @@ function finishScrollTo(ctx, state) {
1529
1515
  if (state) {
1530
1516
  state.scrollHistory.length = 0;
1531
1517
  state.initialScroll = void 0;
1518
+ state.initialAnchor = void 0;
1532
1519
  set$(ctx, "scrollingTo", void 0);
1520
+ if (state.pendingTotalSize !== void 0) {
1521
+ addTotalSize(ctx, state, null, state.pendingTotalSize);
1522
+ }
1533
1523
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1534
1524
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1535
1525
  }
@@ -1592,6 +1582,58 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1592
1582
  }
1593
1583
  }
1594
1584
 
1585
+ // src/core/ensureInitialAnchor.ts
1586
+ var INITIAL_ANCHOR_TOLERANCE = 0.5;
1587
+ var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1588
+ var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1589
+ function ensureInitialAnchor(ctx, state) {
1590
+ var _a3, _b, _c, _d, _e;
1591
+ const anchor = state.initialAnchor;
1592
+ const item = state.props.data[anchor.index];
1593
+ const containersDidLayout = peek$(ctx, "containersDidLayout");
1594
+ if (!containersDidLayout) {
1595
+ return;
1596
+ }
1597
+ const id = getId(state, anchor.index);
1598
+ if (state.positions.get(id) === void 0) {
1599
+ return;
1600
+ }
1601
+ const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1602
+ if (size === void 0) {
1603
+ return;
1604
+ }
1605
+ const availableSpace = Math.max(0, state.scrollLength - size);
1606
+ const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1607
+ const contentSize = getContentSize(ctx);
1608
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1609
+ const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1610
+ const delta = clampedDesiredOffset - state.scroll;
1611
+ if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1612
+ const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1613
+ if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1614
+ state.initialAnchor = void 0;
1615
+ } else {
1616
+ anchor.settledTicks = settledTicks;
1617
+ }
1618
+ return;
1619
+ }
1620
+ if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1621
+ state.initialAnchor = void 0;
1622
+ return;
1623
+ }
1624
+ const lastDelta = anchor.lastDelta;
1625
+ if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1626
+ state.initialAnchor = void 0;
1627
+ return;
1628
+ }
1629
+ Object.assign(anchor, {
1630
+ attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1631
+ lastDelta: delta,
1632
+ settledTicks: 0
1633
+ });
1634
+ requestAdjust(ctx, state, delta);
1635
+ }
1636
+
1595
1637
  // src/core/mvcp.ts
1596
1638
  function prepareMVCP(ctx, state, dataChanged) {
1597
1639
  const {
@@ -1640,7 +1682,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1640
1682
  if (targetId !== void 0 && prevPosition !== void 0) {
1641
1683
  const newPosition = positions.get(targetId);
1642
1684
  if (newPosition !== void 0) {
1643
- const totalSize = peek$(ctx, "totalSize");
1685
+ const totalSize = getContentSize(ctx);
1644
1686
  let diff = newPosition - prevPosition;
1645
1687
  if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1646
1688
  if (diff > 0) {
@@ -1720,6 +1762,29 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1720
1762
  return maxSize;
1721
1763
  }
1722
1764
 
1765
+ // src/core/updateTotalSize.ts
1766
+ function updateTotalSize(ctx, state) {
1767
+ const {
1768
+ positions,
1769
+ props: { data }
1770
+ } = state;
1771
+ if (data.length === 0) {
1772
+ addTotalSize(ctx, state, null, 0);
1773
+ } else {
1774
+ const lastId = getId(state, data.length - 1);
1775
+ if (lastId !== void 0) {
1776
+ const lastPosition = positions.get(lastId);
1777
+ if (lastPosition !== void 0) {
1778
+ const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1779
+ if (lastSize !== void 0) {
1780
+ const totalSize = lastPosition + lastSize;
1781
+ addTotalSize(ctx, state, null, totalSize);
1782
+ }
1783
+ }
1784
+ }
1785
+ }
1786
+ }
1787
+
1723
1788
  // src/utils/getScrollVelocity.ts
1724
1789
  var getScrollVelocity = (state) => {
1725
1790
  const { scrollHistory } = state;
@@ -2329,9 +2394,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2329
2394
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2330
2395
  const prevNumContainers = peek$(ctx, "numContainers");
2331
2396
  if (!data || scrollLength === 0 || !prevNumContainers) {
2397
+ if (state.initialAnchor) {
2398
+ ensureInitialAnchor(ctx, state);
2399
+ }
2332
2400
  return;
2333
2401
  }
2334
- const totalSize = peek$(ctx, "totalSize");
2402
+ const totalSize = getContentSize(ctx);
2335
2403
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
2336
2404
  const numColumns = peek$(ctx, "numColumns");
2337
2405
  const { dataChanged, doMVCP, forceFullItemPositions } = params;
@@ -2378,6 +2446,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2378
2446
  if (!dataChanged && scrollForNextCalculateItemsInView) {
2379
2447
  const { top, bottom } = scrollForNextCalculateItemsInView;
2380
2448
  if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2449
+ if (state.initialAnchor) {
2450
+ ensureInitialAnchor(ctx, state);
2451
+ }
2381
2452
  return;
2382
2453
  }
2383
2454
  }
@@ -2630,6 +2701,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2630
2701
  }
2631
2702
  }
2632
2703
  });
2704
+ if (state.initialAnchor) {
2705
+ ensureInitialAnchor(ctx, state);
2706
+ }
2633
2707
  }
2634
2708
 
2635
2709
  // src/core/checkActualChange.ts
@@ -3246,7 +3320,7 @@ var LegendList = typedMemo(
3246
3320
  })
3247
3321
  );
3248
3322
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3249
- var _a3;
3323
+ var _a3, _b;
3250
3324
  const {
3251
3325
  alignItemsAtEnd = false,
3252
3326
  columnWrapperStyle,
@@ -3337,6 +3411,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3337
3411
  idCache: [],
3338
3412
  idsInView: [],
3339
3413
  indexByKey: /* @__PURE__ */ new Map(),
3414
+ initialAnchor: (initialScrollProp == null ? void 0 : initialScrollProp.index) !== void 0 && (initialScrollProp == null ? void 0 : initialScrollProp.viewPosition) !== void 0 ? {
3415
+ attempts: 0,
3416
+ index: initialScrollProp.index,
3417
+ settledTicks: 0,
3418
+ viewOffset: (_a3 = initialScrollProp.viewOffset) != null ? _a3 : 0,
3419
+ viewPosition: initialScrollProp.viewPosition
3420
+ } : void 0,
3340
3421
  initialScroll: initialScrollProp,
3341
3422
  isAtEnd: false,
3342
3423
  isAtStart: false,
@@ -3458,10 +3539,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3458
3539
  );
3459
3540
  }
3460
3541
  const initialContentOffset = React3.useMemo(() => {
3542
+ var _a4, _b2;
3461
3543
  const { initialScroll } = refState.current;
3462
3544
  if (!initialScroll) {
3545
+ refState.current.initialAnchor = void 0;
3463
3546
  return 0;
3464
3547
  }
3548
+ if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3549
+ refState.current.initialAnchor = {
3550
+ attempts: 0,
3551
+ index: initialScroll.index,
3552
+ settledTicks: 0,
3553
+ viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3554
+ viewPosition: initialScroll.viewPosition
3555
+ };
3556
+ }
3465
3557
  if (initialScroll.contentOffset !== void 0) {
3466
3558
  return initialScroll.contentOffset;
3467
3559
  }
@@ -3511,6 +3603,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3511
3603
  scrollTo(ctx, state, {
3512
3604
  animated: false,
3513
3605
  index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3606
+ isInitialScroll: true,
3514
3607
  offset: initialContentOffset,
3515
3608
  precomputedWithViewOffset: true
3516
3609
  });
@@ -3616,7 +3709,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3616
3709
  }
3617
3710
  ),
3618
3711
  refScrollView: combinedRef,
3619
- scrollAdjustHandler: (_a3 = refState.current) == null ? void 0 : _a3.scrollAdjustHandler,
3712
+ scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3620
3713
  scrollEventThrottle: 16 ,
3621
3714
  snapToIndices,
3622
3715
  stickyIndices,
package/index.mjs CHANGED
@@ -105,11 +105,12 @@ function set$(ctx, signalName, value) {
105
105
  }
106
106
  }
107
107
  function getContentSize(ctx) {
108
+ var _a3, _b;
108
109
  const { values } = ctx;
109
110
  const stylePaddingTop = values.get("stylePaddingTop") || 0;
110
111
  const headerSize = values.get("headerSize") || 0;
111
112
  const footerSize = values.get("footerSize") || 0;
112
- const totalSize = values.get("totalSize");
113
+ const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
113
114
  return headerSize + footerSize + totalSize + stylePaddingTop;
114
115
  }
115
116
  function useArr$(signalNames) {
@@ -1220,44 +1221,28 @@ function updateAlignItemsPaddingTop(ctx, state) {
1220
1221
  }
1221
1222
  }
1222
1223
 
1223
- // src/core/updateTotalSize.ts
1224
- function updateTotalSize(ctx, state) {
1225
- const {
1226
- positions,
1227
- props: { data }
1228
- } = state;
1229
- if (data.length === 0) {
1230
- addTotalSize(ctx, state, null, 0);
1231
- } else {
1232
- const lastId = getId(state, data.length - 1);
1233
- if (lastId !== void 0) {
1234
- const lastPosition = positions.get(lastId);
1235
- if (lastPosition !== void 0) {
1236
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1237
- if (lastSize !== void 0) {
1238
- const totalSize = lastPosition + lastSize;
1239
- addTotalSize(ctx, state, null, totalSize);
1240
- }
1241
- }
1242
- }
1243
- }
1244
- }
1224
+ // src/core/addTotalSize.ts
1245
1225
  function addTotalSize(ctx, state, key, add) {
1246
1226
  const { alignItemsAtEnd } = state.props;
1247
1227
  const prevTotalSize = state.totalSize;
1228
+ let totalSize = state.totalSize;
1248
1229
  if (key === null) {
1249
- state.totalSize = add;
1230
+ totalSize = add;
1250
1231
  if (state.timeoutSetPaddingTop) {
1251
1232
  clearTimeout(state.timeoutSetPaddingTop);
1252
1233
  state.timeoutSetPaddingTop = void 0;
1253
1234
  }
1254
1235
  } else {
1255
- state.totalSize += add;
1236
+ totalSize += add;
1256
1237
  }
1257
- if (prevTotalSize !== state.totalSize) {
1258
- set$(ctx, "totalSize", state.totalSize);
1259
- if (alignItemsAtEnd) {
1260
- updateAlignItemsPaddingTop(ctx, state);
1238
+ if (prevTotalSize !== totalSize) {
1239
+ {
1240
+ state.pendingTotalSize = void 0;
1241
+ state.totalSize = totalSize;
1242
+ set$(ctx, "totalSize", totalSize);
1243
+ if (alignItemsAtEnd) {
1244
+ updateAlignItemsPaddingTop(ctx, state);
1245
+ }
1261
1246
  }
1262
1247
  }
1263
1248
  }
@@ -1462,6 +1447,7 @@ function onScroll(ctx, state, event) {
1462
1447
  onScrollProp == null ? void 0 : onScrollProp(event);
1463
1448
  }
1464
1449
  function updateScroll(ctx, state, newScroll, forceUpdate) {
1450
+ var _a3;
1465
1451
  const scrollingTo = peek$(ctx, "scrollingTo");
1466
1452
  state.hasScrolled = true;
1467
1453
  state.lastBatchingAction = Date.now();
@@ -1495,7 +1481,7 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1495
1481
  }
1496
1482
  if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1497
1483
  state.ignoreScrollFromMVCPIgnored = false;
1498
- calculateItemsInView(ctx, state, { doMVCP: scrollingTo !== void 0 });
1484
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1499
1485
  checkAtBottom(ctx, state);
1500
1486
  checkAtTop(state);
1501
1487
  state.dataChangeNeedsScrollUpdate = false;
@@ -1508,7 +1494,11 @@ function finishScrollTo(ctx, state) {
1508
1494
  if (state) {
1509
1495
  state.scrollHistory.length = 0;
1510
1496
  state.initialScroll = void 0;
1497
+ state.initialAnchor = void 0;
1511
1498
  set$(ctx, "scrollingTo", void 0);
1499
+ if (state.pendingTotalSize !== void 0) {
1500
+ addTotalSize(ctx, state, null, state.pendingTotalSize);
1501
+ }
1512
1502
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1513
1503
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1514
1504
  }
@@ -1571,6 +1561,58 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1571
1561
  }
1572
1562
  }
1573
1563
 
1564
+ // src/core/ensureInitialAnchor.ts
1565
+ var INITIAL_ANCHOR_TOLERANCE = 0.5;
1566
+ var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1567
+ var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1568
+ function ensureInitialAnchor(ctx, state) {
1569
+ var _a3, _b, _c, _d, _e;
1570
+ const anchor = state.initialAnchor;
1571
+ const item = state.props.data[anchor.index];
1572
+ const containersDidLayout = peek$(ctx, "containersDidLayout");
1573
+ if (!containersDidLayout) {
1574
+ return;
1575
+ }
1576
+ const id = getId(state, anchor.index);
1577
+ if (state.positions.get(id) === void 0) {
1578
+ return;
1579
+ }
1580
+ const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1581
+ if (size === void 0) {
1582
+ return;
1583
+ }
1584
+ const availableSpace = Math.max(0, state.scrollLength - size);
1585
+ const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1586
+ const contentSize = getContentSize(ctx);
1587
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1588
+ const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1589
+ const delta = clampedDesiredOffset - state.scroll;
1590
+ if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1591
+ const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1592
+ if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1593
+ state.initialAnchor = void 0;
1594
+ } else {
1595
+ anchor.settledTicks = settledTicks;
1596
+ }
1597
+ return;
1598
+ }
1599
+ if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1600
+ state.initialAnchor = void 0;
1601
+ return;
1602
+ }
1603
+ const lastDelta = anchor.lastDelta;
1604
+ if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1605
+ state.initialAnchor = void 0;
1606
+ return;
1607
+ }
1608
+ Object.assign(anchor, {
1609
+ attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1610
+ lastDelta: delta,
1611
+ settledTicks: 0
1612
+ });
1613
+ requestAdjust(ctx, state, delta);
1614
+ }
1615
+
1574
1616
  // src/core/mvcp.ts
1575
1617
  function prepareMVCP(ctx, state, dataChanged) {
1576
1618
  const {
@@ -1619,7 +1661,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1619
1661
  if (targetId !== void 0 && prevPosition !== void 0) {
1620
1662
  const newPosition = positions.get(targetId);
1621
1663
  if (newPosition !== void 0) {
1622
- const totalSize = peek$(ctx, "totalSize");
1664
+ const totalSize = getContentSize(ctx);
1623
1665
  let diff = newPosition - prevPosition;
1624
1666
  if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1625
1667
  if (diff > 0) {
@@ -1699,6 +1741,29 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1699
1741
  return maxSize;
1700
1742
  }
1701
1743
 
1744
+ // src/core/updateTotalSize.ts
1745
+ function updateTotalSize(ctx, state) {
1746
+ const {
1747
+ positions,
1748
+ props: { data }
1749
+ } = state;
1750
+ if (data.length === 0) {
1751
+ addTotalSize(ctx, state, null, 0);
1752
+ } else {
1753
+ const lastId = getId(state, data.length - 1);
1754
+ if (lastId !== void 0) {
1755
+ const lastPosition = positions.get(lastId);
1756
+ if (lastPosition !== void 0) {
1757
+ const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1758
+ if (lastSize !== void 0) {
1759
+ const totalSize = lastPosition + lastSize;
1760
+ addTotalSize(ctx, state, null, totalSize);
1761
+ }
1762
+ }
1763
+ }
1764
+ }
1765
+ }
1766
+
1702
1767
  // src/utils/getScrollVelocity.ts
1703
1768
  var getScrollVelocity = (state) => {
1704
1769
  const { scrollHistory } = state;
@@ -2308,9 +2373,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2308
2373
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2309
2374
  const prevNumContainers = peek$(ctx, "numContainers");
2310
2375
  if (!data || scrollLength === 0 || !prevNumContainers) {
2376
+ if (state.initialAnchor) {
2377
+ ensureInitialAnchor(ctx, state);
2378
+ }
2311
2379
  return;
2312
2380
  }
2313
- const totalSize = peek$(ctx, "totalSize");
2381
+ const totalSize = getContentSize(ctx);
2314
2382
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
2315
2383
  const numColumns = peek$(ctx, "numColumns");
2316
2384
  const { dataChanged, doMVCP, forceFullItemPositions } = params;
@@ -2357,6 +2425,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2357
2425
  if (!dataChanged && scrollForNextCalculateItemsInView) {
2358
2426
  const { top, bottom } = scrollForNextCalculateItemsInView;
2359
2427
  if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2428
+ if (state.initialAnchor) {
2429
+ ensureInitialAnchor(ctx, state);
2430
+ }
2360
2431
  return;
2361
2432
  }
2362
2433
  }
@@ -2609,6 +2680,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2609
2680
  }
2610
2681
  }
2611
2682
  });
2683
+ if (state.initialAnchor) {
2684
+ ensureInitialAnchor(ctx, state);
2685
+ }
2612
2686
  }
2613
2687
 
2614
2688
  // src/core/checkActualChange.ts
@@ -3225,7 +3299,7 @@ var LegendList = typedMemo(
3225
3299
  })
3226
3300
  );
3227
3301
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3228
- var _a3;
3302
+ var _a3, _b;
3229
3303
  const {
3230
3304
  alignItemsAtEnd = false,
3231
3305
  columnWrapperStyle,
@@ -3316,6 +3390,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3316
3390
  idCache: [],
3317
3391
  idsInView: [],
3318
3392
  indexByKey: /* @__PURE__ */ new Map(),
3393
+ initialAnchor: (initialScrollProp == null ? void 0 : initialScrollProp.index) !== void 0 && (initialScrollProp == null ? void 0 : initialScrollProp.viewPosition) !== void 0 ? {
3394
+ attempts: 0,
3395
+ index: initialScrollProp.index,
3396
+ settledTicks: 0,
3397
+ viewOffset: (_a3 = initialScrollProp.viewOffset) != null ? _a3 : 0,
3398
+ viewPosition: initialScrollProp.viewPosition
3399
+ } : void 0,
3319
3400
  initialScroll: initialScrollProp,
3320
3401
  isAtEnd: false,
3321
3402
  isAtStart: false,
@@ -3437,10 +3518,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3437
3518
  );
3438
3519
  }
3439
3520
  const initialContentOffset = useMemo(() => {
3521
+ var _a4, _b2;
3440
3522
  const { initialScroll } = refState.current;
3441
3523
  if (!initialScroll) {
3524
+ refState.current.initialAnchor = void 0;
3442
3525
  return 0;
3443
3526
  }
3527
+ if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3528
+ refState.current.initialAnchor = {
3529
+ attempts: 0,
3530
+ index: initialScroll.index,
3531
+ settledTicks: 0,
3532
+ viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3533
+ viewPosition: initialScroll.viewPosition
3534
+ };
3535
+ }
3444
3536
  if (initialScroll.contentOffset !== void 0) {
3445
3537
  return initialScroll.contentOffset;
3446
3538
  }
@@ -3490,6 +3582,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3490
3582
  scrollTo(ctx, state, {
3491
3583
  animated: false,
3492
3584
  index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3585
+ isInitialScroll: true,
3493
3586
  offset: initialContentOffset,
3494
3587
  precomputedWithViewOffset: true
3495
3588
  });
@@ -3595,7 +3688,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3595
3688
  }
3596
3689
  ),
3597
3690
  refScrollView: combinedRef,
3598
- scrollAdjustHandler: (_a3 = refState.current) == null ? void 0 : _a3.scrollAdjustHandler,
3691
+ scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3599
3692
  scrollEventThrottle: 16 ,
3600
3693
  snapToIndices,
3601
3694
  stickyIndices,