@legendapp/list 3.3.11 → 3.4.0

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.
@@ -409,6 +409,14 @@ var EDGE_POSITION_EPSILON = 1;
409
409
  var ENABLE_DEVMODE = IS_DEV && false;
410
410
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
411
411
 
412
+ // src/core/endOfContentTarget.ts
413
+ function getEndAlignedViewOffset(stylePaddingEnd, footerSize = 0) {
414
+ return -stylePaddingEnd - footerSize;
415
+ }
416
+ function isEndOfContentTarget(target, dataLength) {
417
+ return !!target && dataLength > 0 && target.viewPosition === 1 && !!target.preserveForBottomPadding && target.index !== void 0 && target.index >= dataLength - 1;
418
+ }
419
+
412
420
  // src/core/cancelImperativeScroll.ts
413
421
  function cancelScrollCompletionChecks({ scheduledWork }) {
414
422
  scheduledWork.cancel("checkFinishedScrollFrame");
@@ -593,26 +601,25 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
593
601
  scrollPosition: context.scrollPosition
594
602
  });
595
603
  };
604
+ let reached = !!wasReached;
596
605
  if (!wasReached) {
597
- if (!within) {
598
- return false;
599
- }
600
- onReached(distance);
601
- updateSnapshot();
602
- return true;
603
- }
604
- const reset = isOutsideThresholdHysteresis(distance, atThreshold, threshold);
605
- if (reset) {
606
- setSnapshot(void 0);
607
- return false;
608
- }
609
- if (within) {
610
- const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
611
- if (changed) {
606
+ if (within && onReached(distance)) {
612
607
  updateSnapshot();
608
+ reached = true;
609
+ }
610
+ } else {
611
+ const reset = isOutsideThresholdHysteresis(distance, atThreshold, threshold);
612
+ if (reset) {
613
+ setSnapshot(void 0);
614
+ reached = false;
615
+ } else if (within) {
616
+ const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
617
+ if (changed) {
618
+ updateSnapshot();
619
+ }
613
620
  }
614
621
  }
615
- return true;
622
+ return reached;
616
623
  };
617
624
 
618
625
  // src/utils/edgeReachedGate.ts
@@ -659,7 +666,6 @@ function beginReachedEdgeUserScroll(ctx, scrollDelta) {
659
666
  return void 0;
660
667
  }
661
668
  const allowedEdge = scrollDelta < 0 ? "start" : "end";
662
- state.edgeReachedGate = "closed";
663
669
  resetEdgeLatch(ctx, allowedEdge);
664
670
  return allowedEdge;
665
671
  }
@@ -700,7 +706,7 @@ function checkAtBottom(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
700
706
  set$(
701
707
  ctx,
702
708
  "isWithinMaintainScrollAtEndThreshold",
703
- isContentLess || distanceFromEnd <= maintainScrollAtEndThreshold * scrollLength || state.pendingMaintainScrollAtEnd || maintainingScrollAtEnd === "animated" || maintainingScrollAtEnd === "instant"
709
+ isContentLess || distanceFromEnd <= maintainScrollAtEndThreshold * scrollLength || state.pendingMaintainScrollAtEnd || !!maintainingScrollAtEnd
704
710
  );
705
711
  const shouldSkipThresholdChecks = hasActiveInitialScroll(state) || maintainingScrollAtEnd;
706
712
  if (!shouldSkipThresholdChecks) {
@@ -716,11 +722,13 @@ function checkAtBottom(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
716
722
  scrollPosition: scroll
717
723
  },
718
724
  (distance) => {
719
- var _a4, _b;
720
- if (canDispatchReachedEdge(ctx, "end", allowedEdge, allowGateCreatedInCurrentCheck)) {
725
+ let dispatched = false;
726
+ if (state.props.onEndReached && canDispatchReachedEdge(ctx, "end", allowedEdge, allowGateCreatedInCurrentCheck)) {
721
727
  markReachedEdge(ctx);
722
- (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
728
+ state.props.onEndReached({ distanceFromEnd: distance });
729
+ dispatched = true;
723
730
  }
731
+ return dispatched;
724
732
  },
725
733
  (snapshot) => {
726
734
  state.endReachedSnapshot = snapshot;
@@ -753,7 +761,7 @@ function checkAtTop(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
753
761
  }
754
762
  set$(ctx, "isAtStart", scroll <= EDGE_POSITION_EPSILON);
755
763
  set$(ctx, "isNearStart", scroll <= threshold);
756
- const shouldSkipThresholdChecks = hasActiveInitialScroll(state) || !!state.scrollingTo;
764
+ const shouldSkipThresholdChecks = !state.queuedInitialLayout || hasActiveInitialScroll(state) || !!state.scrollingTo;
757
765
  if (!shouldSkipThresholdChecks) {
758
766
  state.isStartReached = checkThreshold(
759
767
  scroll,
@@ -767,11 +775,13 @@ function checkAtTop(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
767
775
  scrollPosition: scroll
768
776
  },
769
777
  (distance) => {
770
- var _a3, _b;
771
- if (canDispatchReachedEdge(ctx, "start", allowedEdge, allowGateCreatedInCurrentCheck)) {
778
+ let dispatched = false;
779
+ if (state.props.onStartReached && canDispatchReachedEdge(ctx, "start", allowedEdge, allowGateCreatedInCurrentCheck)) {
772
780
  markReachedEdge(ctx);
773
- (_b = (_a3 = state.props).onStartReached) == null ? void 0 : _b.call(_a3, { distanceFromStart: distance });
781
+ state.props.onStartReached({ distanceFromStart: distance });
782
+ dispatched = true;
774
783
  }
784
+ return dispatched;
775
785
  },
776
786
  (snapshot) => {
777
787
  state.startReachedSnapshot = snapshot;
@@ -884,6 +894,11 @@ function resetInitialRenderState(ctx, {
884
894
  if (resetLayout) {
885
895
  state.didContainersLayout = false;
886
896
  state.queuedInitialLayout = false;
897
+ state.edgeReachedGate = void 0;
898
+ state.isStartReached = null;
899
+ state.isEndReached = null;
900
+ state.startReachedSnapshot = void 0;
901
+ state.endReachedSnapshot = void 0;
887
902
  }
888
903
  if (resetInitialScroll) {
889
904
  state.didFinishInitialScroll = false;
@@ -898,7 +913,7 @@ function setInitialRenderState(ctx, {
898
913
  const { state } = ctx;
899
914
  const {
900
915
  loadStartTime,
901
- props: { onLoad }
916
+ props: { onLoad, onReady }
902
917
  } = state;
903
918
  if (didLayout) {
904
919
  state.didContainersLayout = true;
@@ -919,6 +934,7 @@ function setInitialRenderState(ctx, {
919
934
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
920
935
  }
921
936
  }
937
+ onReady == null ? void 0 : onReady();
922
938
  }
923
939
  }
924
940
 
@@ -1262,10 +1278,6 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1262
1278
  const itemSize = Math.max(0, measuredItemSize - (isOutOfBounds ? 0 : ctx.scrollAxisGap));
1263
1279
  const trailingInset = getContentInsetEnd(ctx);
1264
1280
  offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1265
- if (!isOutOfBounds && index === state.props.data.length - 1) {
1266
- const footerSize = peek$(ctx, "footerSize") || 0;
1267
- offset += footerSize;
1268
- }
1269
1281
  }
1270
1282
  return offset;
1271
1283
  }
@@ -1827,89 +1839,103 @@ function finishMaintainScrollAtEnd(ctx) {
1827
1839
  requestAdjust(ctx, nextScroll - state.scroll);
1828
1840
  }
1829
1841
  }
1830
- function doMaintainScrollAtEnd(ctx) {
1831
- var _a3, _b, _c, _d, _e;
1842
+ function doMaintainScrollAtEnd(ctx, options) {
1843
+ var _a3, _b, _c, _d, _e, _f;
1832
1844
  const state = ctx.state;
1833
- const {
1834
- didContainersLayout,
1835
- didFinishInitialScroll,
1836
- pendingNativeMVCPAdjust,
1837
- props: { maintainScrollAtEnd }
1838
- } = state;
1839
- const isWithinMaintainScrollAtEndThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1840
- const isReplayingPendingMaintain = !!state.pendingMaintainScrollAtEnd;
1841
- const shouldMaintainScrollAtEnd = !!(!((_a3 = ctx.scrollRequestTracker) == null ? void 0 : _a3.isWaitingToRun()) && (!state.scrollingTo || state.scrollingTo.isScrollToEnd) && (isWithinMaintainScrollAtEndThreshold || isReplayingPendingMaintain || ((_b = state.scrollingTo) == null ? void 0 : _b.isScrollToEnd)) && maintainScrollAtEnd && didFinishInitialScroll);
1842
- if (shouldMaintainScrollAtEnd && !state.scrollingTo) {
1843
- const scroller = state.refScroller.current;
1844
- const nativeMax = (_c = scroller == null ? void 0 : scroller.getMaxScrollOffset) == null ? void 0 : _c.call(scroller);
1845
- const observed = (_d = scroller == null ? void 0 : scroller.getCurrentScrollOffset) == null ? void 0 : _d.call(scroller);
1846
- if (nativeMax !== void 0 && observed !== void 0 && nativeMax < state.scroll - 1 && Math.abs(observed - nativeMax) <= 1) {
1845
+ let didMaintain = false;
1846
+ if (state.isDragging) {
1847
+ finishMaintainScrollAtEnd(ctx);
1848
+ } else {
1849
+ const {
1850
+ didContainersLayout,
1851
+ didFinishInitialScroll,
1852
+ pendingNativeMVCPAdjust,
1853
+ props: { maintainScrollAtEnd }
1854
+ } = state;
1855
+ const immediate = (options == null ? void 0 : options.immediate) && Platform.OS === "web" && !(maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.animated);
1856
+ const isWithinMaintainScrollAtEndThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1857
+ const isReplayingPendingMaintain = !!state.pendingMaintainScrollAtEnd;
1858
+ const shouldMaintainScrollAtEnd = !!(!((_a3 = ctx.scrollRequestTracker) == null ? void 0 : _a3.isWaitingToRun()) && (!state.scrollingTo || state.scrollingTo.isScrollToEnd) && (isWithinMaintainScrollAtEndThreshold || isReplayingPendingMaintain || ((_b = state.scrollingTo) == null ? void 0 : _b.isScrollToEnd)) && maintainScrollAtEnd && didFinishInitialScroll);
1859
+ if (shouldMaintainScrollAtEnd && !state.scrollingTo) {
1860
+ const scroller = state.refScroller.current;
1861
+ const nativeMax = (_c = scroller == null ? void 0 : scroller.getMaxScrollOffset) == null ? void 0 : _c.call(scroller);
1862
+ const observed = (_d = scroller == null ? void 0 : scroller.getCurrentScrollOffset) == null ? void 0 : _d.call(scroller);
1863
+ if (nativeMax !== void 0 && observed !== void 0 && nativeMax < state.scroll - 1 && Math.abs(observed - nativeMax) <= 1) {
1864
+ state.pendingMaintainScrollAtEnd = true;
1865
+ state.scrollPending = observed;
1866
+ updateScroll(ctx, observed, true, { markHasScrolled: false });
1867
+ }
1868
+ }
1869
+ if (shouldMaintainScrollAtEnd && !didContainersLayout) {
1847
1870
  state.pendingMaintainScrollAtEnd = true;
1848
- state.scrollPending = observed;
1849
- updateScroll(ctx, observed, true, { markHasScrolled: false });
1850
- }
1851
- }
1852
- if (shouldMaintainScrollAtEnd && !didContainersLayout) {
1853
- state.pendingMaintainScrollAtEnd = true;
1854
- return false;
1855
- }
1856
- if (pendingNativeMVCPAdjust) {
1857
- state.pendingMaintainScrollAtEnd = shouldMaintainScrollAtEnd;
1858
- return false;
1859
- }
1860
- if (shouldMaintainScrollAtEnd && (state.scrollingTo || state.pendingScrollResolve)) {
1861
- state.pendingMaintainScrollAtEnd = true;
1862
- (_e = state.maintainingScrollAtEnd) != null ? _e : state.maintainingScrollAtEnd = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1863
- return false;
1864
- }
1865
- if (shouldMaintainScrollAtEnd && didContainersLayout) {
1866
- state.pendingMaintainScrollAtEnd = false;
1867
- const contentSize = getContentSize(ctx);
1868
- if (contentSize < state.scrollLength) {
1869
- state.scroll = 0;
1870
- }
1871
- if (!state.maintainingScrollAtEnd) {
1872
- const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1873
- const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1874
- const scrollAtRequest = state.scroll;
1875
- state.maintainingScrollAtEnd = pendingState;
1876
- requestAnimationFrame(() => {
1877
- if (state.maintainingScrollAtEnd !== pendingState) {
1878
- return;
1879
- }
1880
- const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1881
- const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1882
- if (isReplayingPendingMaintain || isStillWithinThreshold || !didScrollSinceRequest) {
1883
- if (state.scrollingTo || state.pendingScrollResolve) {
1884
- state.pendingMaintainScrollAtEnd = true;
1885
- return;
1886
- }
1887
- state.maintainingScrollAtEnd = activeState;
1888
- const scrollPromise = getScrollRequestTracker(ctx).runNowIfIdle(
1889
- () => ctx.scrollToEnd({ animated: maintainScrollAtEnd.animated })
1890
- );
1891
- void scrollPromise.then(() => {
1892
- if (state.maintainingScrollAtEnd !== activeState) {
1893
- return;
1894
- }
1895
- if (state.pendingMaintainScrollAtEnd) {
1896
- state.maintainingScrollAtEnd = void 0;
1897
- doMaintainScrollAtEnd(ctx);
1898
- } else {
1871
+ } else if (pendingNativeMVCPAdjust) {
1872
+ state.pendingMaintainScrollAtEnd = shouldMaintainScrollAtEnd;
1873
+ } else if (shouldMaintainScrollAtEnd && (state.scrollingTo || state.pendingScrollResolve)) {
1874
+ if (immediate && ((_e = state.scrollingTo) == null ? void 0 : _e.isScrollToEnd) && !state.scrollingTo.animated) {
1875
+ state.pendingMaintainScrollAtEnd = false;
1876
+ ctx.scrollToEnd({ animated: false });
1877
+ didMaintain = true;
1878
+ } else {
1879
+ state.pendingMaintainScrollAtEnd = true;
1880
+ (_f = state.maintainingScrollAtEnd) != null ? _f : state.maintainingScrollAtEnd = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1881
+ }
1882
+ } else if (shouldMaintainScrollAtEnd && didContainersLayout) {
1883
+ state.pendingMaintainScrollAtEnd = false;
1884
+ const contentSize = getContentSize(ctx);
1885
+ if (contentSize < state.scrollLength) {
1886
+ state.scroll = 0;
1887
+ }
1888
+ if (!state.maintainingScrollAtEnd || immediate && state.maintainingScrollAtEnd === "pending-instant") {
1889
+ const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1890
+ const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1891
+ const scrollAtRequest = state.scroll;
1892
+ state.maintainingScrollAtEnd = pendingState;
1893
+ const run = () => {
1894
+ if (state.maintainingScrollAtEnd === pendingState) {
1895
+ if (state.isDragging) {
1899
1896
  finishMaintainScrollAtEnd(ctx);
1897
+ } else {
1898
+ const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1899
+ const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1900
+ if (isReplayingPendingMaintain || isStillWithinThreshold || !didScrollSinceRequest) {
1901
+ if (state.scrollingTo || state.pendingScrollResolve) {
1902
+ state.pendingMaintainScrollAtEnd = true;
1903
+ } else {
1904
+ state.maintainingScrollAtEnd = activeState;
1905
+ const scrollPromise = getScrollRequestTracker(ctx).runNowIfIdle(
1906
+ () => ctx.scrollToEnd({ animated: maintainScrollAtEnd.animated })
1907
+ );
1908
+ void scrollPromise.then(() => {
1909
+ if (state.maintainingScrollAtEnd === activeState) {
1910
+ if (state.pendingMaintainScrollAtEnd) {
1911
+ state.maintainingScrollAtEnd = void 0;
1912
+ doMaintainScrollAtEnd(ctx);
1913
+ } else {
1914
+ finishMaintainScrollAtEnd(ctx);
1915
+ }
1916
+ }
1917
+ });
1918
+ }
1919
+ } else if (state.maintainingScrollAtEnd === pendingState) {
1920
+ finishMaintainScrollAtEnd(ctx);
1921
+ }
1900
1922
  }
1901
- });
1902
- } else if (state.maintainingScrollAtEnd === pendingState) {
1903
- finishMaintainScrollAtEnd(ctx);
1923
+ }
1924
+ };
1925
+ if (immediate) {
1926
+ run();
1927
+ } else {
1928
+ requestAnimationFrame(run);
1904
1929
  }
1905
- });
1930
+ } else {
1931
+ state.pendingMaintainScrollAtEnd = true;
1932
+ }
1933
+ didMaintain = true;
1906
1934
  } else {
1907
- state.pendingMaintainScrollAtEnd = true;
1935
+ finishMaintainScrollAtEnd(ctx);
1908
1936
  }
1909
- return true;
1910
1937
  }
1911
- finishMaintainScrollAtEnd(ctx);
1912
- return false;
1938
+ return didMaintain;
1913
1939
  }
1914
1940
 
1915
1941
  // src/core/finishScrollTo.ts
@@ -2213,7 +2239,9 @@ function scrollTo(ctx, params) {
2213
2239
  pinScrollTargetRenderRange(ctx, targetOffset, scrollTarget.index);
2214
2240
  }
2215
2241
  }
2216
- state.scrollPending = targetOffset;
2242
+ if (!animated || isInitialScroll) {
2243
+ state.scrollPending = targetOffset;
2244
+ }
2217
2245
  syncInitialScrollNativeWatchdog(state, { isInitialScroll, requestedOffset: offset, targetOffset });
2218
2246
  if (!isInitialScroll && !noScrollingTo && Math.abs(state.scroll - targetOffset) > 1) {
2219
2247
  if (animated) {
@@ -2590,13 +2618,13 @@ function rearmBootstrapInitialScroll(ctx, options) {
2590
2618
  queueBootstrapInitialScrollReevaluation(ctx.state);
2591
2619
  }
2592
2620
  function createInitialScrollAtEndTarget(options) {
2593
- const { dataLength, footerSize, preserveForFooterLayout, stylePaddingEnd } = options;
2621
+ const { dataLength, footerSize, index, preserveForFooterLayout, stylePaddingEnd } = options;
2594
2622
  return {
2595
2623
  contentOffset: void 0,
2596
- index: Math.max(0, dataLength - 1),
2624
+ index: index != null ? index : Math.max(0, dataLength - 1),
2597
2625
  preserveForBottomPadding: true,
2598
2626
  preserveForFooterLayout,
2599
- viewOffset: -stylePaddingEnd - footerSize,
2627
+ viewOffset: getEndAlignedViewOffset(stylePaddingEnd, footerSize),
2600
2628
  viewPosition: 1
2601
2629
  };
2602
2630
  }
@@ -2612,13 +2640,14 @@ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2612
2640
  function createRetargetedBottomAlignedInitialScroll(options) {
2613
2641
  const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd, target } = options;
2614
2642
  const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2643
+ const alignsToContentEnd = initialScrollAtEnd || isEndOfContentTarget(target, dataLength);
2615
2644
  return {
2616
2645
  ...target,
2617
2646
  contentOffset: void 0,
2618
2647
  index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2619
2648
  preserveForBottomPadding: true,
2620
2649
  preserveForFooterLayout,
2621
- viewOffset: -stylePaddingEnd - (preserveForFooterLayout ? footerSize : 0),
2650
+ viewOffset: getEndAlignedViewOffset(stylePaddingEnd, alignsToContentEnd ? footerSize : 0),
2622
2651
  viewPosition: 1
2623
2652
  };
2624
2653
  }
@@ -2632,7 +2661,7 @@ function clearPendingInitialScrollFooterLayout(ctx, options) {
2632
2661
  }
2633
2662
  const clearedFooterTarget = createInitialScrollAtEndTarget({
2634
2663
  dataLength,
2635
- footerSize: 0,
2664
+ footerSize: peek$(ctx, "footerSize") || 0,
2636
2665
  preserveForFooterLayout: void 0,
2637
2666
  stylePaddingEnd
2638
2667
  });
@@ -2655,13 +2684,12 @@ function getObservedBootstrapInitialScrollOffset(state) {
2655
2684
  return typeof observedOffset === "number" && Number.isFinite(observedOffset) ? observedOffset : (_d = (_c = state.scrollPending) != null ? _c : state.scroll) != null ? _d : 0;
2656
2685
  }
2657
2686
  function getPreservedEndAnchorOffsetDiff(ctx) {
2658
- var _a3;
2659
2687
  const state = ctx.state;
2660
2688
  const initialScroll = state.initialScroll;
2661
- if (!state.didFinishInitialScroll || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) || !initialScroll || initialScroll.viewPosition !== 1 || state.props.data.length === 0 || isOffsetInitialScrollSession(state)) {
2689
+ if (!state.didFinishInitialScroll || state.scrollingTo || state.pendingScrollResolve || state.maintainingScrollAtEnd || state.isDragging || !initialScroll || initialScroll.viewPosition !== 1 || state.props.data.length === 0 || isOffsetInitialScrollSession(state)) {
2662
2690
  return;
2663
2691
  }
2664
- const currentOffset = typeof state.lastNativeScroll === "number" && Number.isFinite(state.lastNativeScroll) ? state.lastNativeScroll : getObservedBootstrapInitialScrollOffset(state);
2692
+ const currentOffset = getObservedBootstrapInitialScrollOffset(state);
2665
2693
  return resolveInitialScrollOffset(ctx, initialScroll) - currentOffset;
2666
2694
  }
2667
2695
  function schedulePreservedEndAnchorCorrection(ctx) {
@@ -2689,6 +2717,9 @@ function schedulePreservedEndAnchorCorrectionFrame(ctx, correction) {
2689
2717
  const hasObservedNativeScrollAfterRequest = !activeCorrection.lastRequestTime || ((_a3 = state.lastNativeScrollTime) != null ? _a3 : 0) > activeCorrection.lastRequestTime;
2690
2718
  if (hasObservedNativeScrollAfterRequest) {
2691
2719
  activeCorrection.lastRequestTime = Date.now();
2720
+ {
2721
+ state.scroll = getObservedBootstrapInitialScrollOffset(state);
2722
+ }
2692
2723
  requestAdjust(ctx, offsetDiff);
2693
2724
  }
2694
2725
  schedulePreservedEndAnchorCorrectionFrame(ctx, correction);
@@ -2811,10 +2842,10 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2811
2842
  function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2812
2843
  const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd } = options;
2813
2844
  const state = ctx.state;
2814
- if (!initialScrollAtEnd) {
2845
+ const initialScroll = state.initialScroll;
2846
+ if (!initialScrollAtEnd && !isEndOfContentTarget(initialScroll, dataLength)) {
2815
2847
  return;
2816
2848
  }
2817
- const initialScroll = state.initialScroll;
2818
2849
  if (isOffsetInitialScrollSession(state) || dataLength === 0 || !initialScroll) {
2819
2850
  return;
2820
2851
  }
@@ -2832,6 +2863,7 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2832
2863
  const updatedInitialScroll = createInitialScrollAtEndTarget({
2833
2864
  dataLength,
2834
2865
  footerSize,
2866
+ index: initialScrollAtEnd ? void 0 : initialScroll.index,
2835
2867
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2836
2868
  stylePaddingEnd
2837
2869
  });
@@ -3981,7 +4013,7 @@ function getExpandedContainerPoolSize(dataLength, numContainers) {
3981
4013
  }
3982
4014
 
3983
4015
  // src/utils/findAvailableContainers.ts
3984
- function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffered, pendingRemoval, getRequiredItemType, protectedKeys) {
4016
+ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffered, pendingRemoval, protectedKeys, reverseItemOrder = false) {
3985
4017
  var _a3;
3986
4018
  const numNeeded = needNewContainers.length;
3987
4019
  if (numNeeded === 0) {
@@ -3990,16 +4022,27 @@ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffe
3990
4022
  const numContainers = peek$(ctx, "numContainers");
3991
4023
  const state = ctx.state;
3992
4024
  const { containerItemMetadata, stickyContainerPool } = state;
4025
+ const { data, getItemType } = state.props;
4026
+ const hasItemTypes = !!getItemType;
3993
4027
  const shouldAvoidAssignedContainerReuse = state.props.recycleItems && !!state.props.positionComponentInternal;
3994
4028
  const pendingRemovalSet = pendingRemoval.length > 0 ? new Set(pendingRemoval) : void 0;
3995
- const requests = needNewContainers.map((itemIndex, order) => ({
3996
- isSticky: state.props.stickyHeaderIndicesSet.has(itemIndex),
3997
- itemIndex,
3998
- itemType: getRequiredItemType == null ? void 0 : getRequiredItemType(itemIndex),
3999
- order
4000
- }));
4001
- const normalRequests = requests.filter((request) => !request.isSticky);
4002
- const stickyRequests = requests.filter((request) => request.isSticky);
4029
+ const requests = new Array(numNeeded);
4030
+ const normalRequests = [];
4031
+ const stickyRequests = [];
4032
+ for (let order = 0; order < numNeeded; order++) {
4033
+ const itemIndex = needNewContainers[order];
4034
+ const itemType = getItemType == null ? void 0 : getItemType(data[itemIndex], itemIndex);
4035
+ const request = {
4036
+ isBuffered: itemIndex >= startBuffered && itemIndex <= endBuffered,
4037
+ isSticky: state.props.stickyHeaderIndicesSet.has(itemIndex),
4038
+ itemIndex,
4039
+ itemType: hasItemTypes ? itemType !== void 0 ? String(itemType) : "" : void 0,
4040
+ order,
4041
+ renderPriority: reverseItemOrder ? -itemIndex : itemIndex
4042
+ };
4043
+ requests[order] = request;
4044
+ (request.isSticky ? stickyRequests : normalRequests).push(request);
4045
+ }
4003
4046
  const normalCandidates = [];
4004
4047
  const stickyCandidates = [];
4005
4048
  for (let containerIndex = 0; containerIndex < numContainers; containerIndex++) {
@@ -4055,7 +4098,7 @@ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffe
4055
4098
  }
4056
4099
  };
4057
4100
  const assignFromPool = (pendingRequests, candidates, allowCrossType) => {
4058
- if (getRequiredItemType) {
4101
+ if (hasItemTypes) {
4059
4102
  assignMatching(
4060
4103
  pendingRequests,
4061
4104
  candidates,
@@ -4079,6 +4122,11 @@ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffe
4079
4122
  }
4080
4123
  assign(request, containerIndex);
4081
4124
  }
4125
+ if (normalRequests.length > 1 || stickyRequests.length > 1) {
4126
+ const containerIndices = [];
4127
+ reorderPoolAssignments(normalRequests, allocations, containerIndices, hasItemTypes);
4128
+ reorderPoolAssignments(stickyRequests, allocations, containerIndices, hasItemTypes);
4129
+ }
4082
4130
  if (pendingRemovalChanged) {
4083
4131
  pendingRemoval.length = 0;
4084
4132
  if (pendingRemovalSet) {
@@ -4108,12 +4156,53 @@ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffe
4108
4156
  function comparatorByDistance(a, b) {
4109
4157
  return b.distance - a.distance;
4110
4158
  }
4159
+ function comparatorByRenderPriority(a, b) {
4160
+ return Number(b.isBuffered) - Number(a.isBuffered) || a.renderPriority - b.renderPriority;
4161
+ }
4162
+ function comparatorByIndex(a, b) {
4163
+ return a - b;
4164
+ }
4165
+ function reorderPoolAssignments(requests, allocations, containerIndices, groupByType) {
4166
+ if (requests.length >= 2) {
4167
+ if (groupByType) {
4168
+ const groups = /* @__PURE__ */ new Map();
4169
+ for (const request of requests) {
4170
+ const group = groups.get(request.itemType);
4171
+ if (group) {
4172
+ group.push(request);
4173
+ } else {
4174
+ groups.set(request.itemType, [request]);
4175
+ }
4176
+ }
4177
+ for (const group of groups.values()) {
4178
+ reorderPoolAssignments(group, allocations, containerIndices, false);
4179
+ }
4180
+ } else {
4181
+ containerIndices.length = 0;
4182
+ let indicesSorted = true;
4183
+ for (let i = 0; i < requests.length; i++) {
4184
+ const containerIndex = allocations[requests[i].order].containerIndex;
4185
+ if (i > 0 && containerIndex < containerIndices[i - 1]) {
4186
+ indicesSorted = false;
4187
+ }
4188
+ containerIndices.push(containerIndex);
4189
+ }
4190
+ if (!indicesSorted) {
4191
+ containerIndices.sort(comparatorByIndex);
4192
+ }
4193
+ requests.sort(comparatorByRenderPriority);
4194
+ for (let i = 0; i < requests.length; i++) {
4195
+ allocations[requests[i].order].containerIndex = containerIndices[i];
4196
+ }
4197
+ }
4198
+ }
4199
+ }
4111
4200
 
4112
4201
  // src/utils/setDidLayout.ts
4113
4202
  function setDidLayout(ctx) {
4114
4203
  const state = ctx.state;
4115
4204
  state.queuedInitialLayout = true;
4116
- checkAtBottom(ctx);
4205
+ checkThresholds(ctx);
4117
4206
  setInitialRenderState(ctx, { didLayout: true });
4118
4207
  if (state.pendingMaintainScrollAtEnd) {
4119
4208
  doMaintainScrollAtEnd(ctx);
@@ -4341,9 +4430,9 @@ function calculateItemsInView(ctx, params = {}) {
4341
4430
  enableScrollForNextCalculateItemsInView,
4342
4431
  idCache,
4343
4432
  indexByKey,
4344
- minIndexSizeChanged,
4433
+ positionRecalculationStartIndex,
4345
4434
  positions,
4346
- props: { alwaysRenderIndicesArr, alwaysRenderIndicesSet, getItemType, keyExtractor, onStickyHeaderChange },
4435
+ props: { alwaysRenderIndicesArr, alwaysRenderIndicesSet, keyExtractor, onStickyHeaderChange },
4347
4436
  scrollForNextCalculateItemsInView,
4348
4437
  scrollLength,
4349
4438
  sizes,
@@ -4459,21 +4548,21 @@ function calculateItemsInView(ctx, params = {}) {
4459
4548
  if (dataChanged) {
4460
4549
  resetLayoutCachesForDataChange(state);
4461
4550
  }
4462
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_e = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _e : 0;
4463
- const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4551
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_e = positionRecalculationStartIndex != null ? positionRecalculationStartIndex : state.startBuffered) != null ? _e : 0;
4552
+ const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && positionRecalculationStartIndex !== void 0;
4464
4553
  updateItemPositions(ctx, dataChanged, {
4465
4554
  doMVCP,
4466
4555
  // A changed size shifts every following position. The scrolling early-exit
4467
4556
  // would leave the untouched suffix in the old coordinate space.
4468
- forceFullUpdate: !!forceFullItemPositions || minIndexSizeChanged !== void 0,
4557
+ forceFullUpdate: !!forceFullItemPositions || positionRecalculationStartIndex !== void 0,
4469
4558
  optimizeForVisibleWindow,
4470
4559
  scrollBottomBuffered,
4471
4560
  scrollVelocity: speed,
4472
4561
  startIndex
4473
4562
  });
4474
4563
  totalSize = getContentSize(ctx);
4475
- if (minIndexSizeChanged !== void 0) {
4476
- state.minIndexSizeChanged = void 0;
4564
+ if (positionRecalculationStartIndex !== void 0) {
4565
+ state.positionRecalculationStartIndex = void 0;
4477
4566
  }
4478
4567
  let protectedContainerKeys;
4479
4568
  if (dataChanged && doMVCP && state.props.maintainVisibleContentPosition.data && state.didContainersLayout && state.idsInView.length > 0) {
@@ -4649,18 +4738,18 @@ function calculateItemsInView(ctx, params = {}) {
4649
4738
  set$(ctx, "activeStickyIndex", -1);
4650
4739
  }
4651
4740
  if (needNewContainers.length > 0) {
4652
- const getRequiredItemType = getItemType ? (i) => {
4653
- const itemType = getItemType(data[i], i);
4654
- return itemType !== void 0 ? String(itemType) : "";
4655
- } : void 0;
4656
4741
  const availableContainerAllocations = findAvailableContainers(
4657
4742
  ctx,
4658
4743
  needNewContainers,
4659
4744
  startBuffered,
4660
4745
  endBuffered,
4661
4746
  pendingRemoval,
4662
- getRequiredItemType,
4663
- protectedContainerKeys
4747
+ protectedContainerKeys,
4748
+ // Initial end alignment has no scroll velocity yet. Keep its
4749
+ // target-side rows first until the initial scroll settles.
4750
+ // After a pause velocity can be zero on the first movement;
4751
+ // use its displacement without treating initial insets as motion.
4752
+ hasActiveInitialScroll(state) ? (initialScroll == null ? void 0 : initialScroll.viewPosition) === 1 : (speed || (state.hasScrolled ? state.scroll - state.scrollPrev : 0)) < 0
4664
4753
  );
4665
4754
  for (const allocation of availableContainerAllocations) {
4666
4755
  const i = allocation.itemIndex;
@@ -4943,6 +5032,7 @@ function updateItemSizesBatch(ctx, measurements) {
4943
5032
  var _a3;
4944
5033
  const state = ctx.state;
4945
5034
  const result = {};
5035
+ const previousTotalSize = state.totalSize;
4946
5036
  for (const measurement of measurements) {
4947
5037
  const ownsMeasuredItem = measurement.containerId === void 0 || peek$(ctx, `containerItemKey${measurement.containerId}`) === measurement.itemKey;
4948
5038
  if (ownsMeasuredItem) {
@@ -4953,6 +5043,9 @@ function updateItemSizesBatch(ctx, measurements) {
4953
5043
  mergeItemSizeUpdateResult(result, nextResult);
4954
5044
  }
4955
5045
  }
5046
+ if (state.totalSize !== previousTotalSize) {
5047
+ set$(ctx, "totalSize", state.totalSize);
5048
+ }
4956
5049
  flushItemSizeUpdates(ctx, result);
4957
5050
  }
4958
5051
  function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
@@ -4991,12 +5084,12 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4991
5084
  }
4992
5085
  let needsRecalculate = !didContainersLayout;
4993
5086
  let shouldMaintainScrollAtEnd = false;
4994
- let minIndexSizeChanged;
5087
+ let positionRecalculationStartIndex;
4995
5088
  const prevSizeKnown = state.sizesKnown.get(itemKey);
4996
- const diff = updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem);
5089
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem, false);
4997
5090
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
4998
5091
  if (diff !== 0) {
4999
- minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
5092
+ positionRecalculationStartIndex = positionRecalculationStartIndex !== void 0 ? Math.min(positionRecalculationStartIndex, index) : index;
5000
5093
  const { startBuffered, endBuffered } = state;
5001
5094
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
5002
5095
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
@@ -5013,8 +5106,8 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5013
5106
  size
5014
5107
  });
5015
5108
  }
5016
- if (minIndexSizeChanged !== void 0) {
5017
- state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
5109
+ if (positionRecalculationStartIndex !== void 0) {
5110
+ state.positionRecalculationStartIndex = state.positionRecalculationStartIndex !== void 0 ? Math.min(state.positionRecalculationStartIndex, positionRecalculationStartIndex) : positionRecalculationStartIndex;
5018
5111
  }
5019
5112
  updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5020
5113
  if (didContainersLayout || checkAllSizesKnown(state, state.startBuffered, state.endBuffered)) {
@@ -5031,7 +5124,7 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5031
5124
  didMeasureUserScrollAnchorResetItem
5032
5125
  };
5033
5126
  }
5034
- function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5127
+ function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem, notifyTotalSize = true) {
5035
5128
  var _a3, _b;
5036
5129
  const state = ctx.state;
5037
5130
  const {
@@ -5054,7 +5147,16 @@ function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5054
5147
  fixedItemSize,
5055
5148
  itemType
5056
5149
  } : void 0;
5057
- const prevSize = getItemSize(ctx, itemKey, index, itemData, void 0, void 0, void 0, resolvedItemSize);
5150
+ const prevSize = getItemSize(
5151
+ ctx,
5152
+ itemKey,
5153
+ index,
5154
+ itemData,
5155
+ void 0,
5156
+ void 0,
5157
+ notifyTotalSize,
5158
+ resolvedItemSize
5159
+ );
5058
5160
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
5059
5161
  const prevSizeKnown = sizesKnown.get(itemKey);
5060
5162
  const size = Math.round(rawSize) ;
@@ -5076,7 +5178,7 @@ function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5076
5178
  }
5077
5179
  }
5078
5180
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
5079
- setSize(ctx, itemKey, size);
5181
+ setSize(ctx, itemKey, size, notifyTotalSize);
5080
5182
  return size - prevSize;
5081
5183
  }
5082
5184
  return 0;
@@ -6777,6 +6879,7 @@ var ListComponent = typedMemo(function ListComponent2({
6777
6879
  renderScrollComponent,
6778
6880
  onLayoutFooter,
6779
6881
  onInternalScrollBeginDrag,
6882
+ onInternalScrollEndDrag,
6780
6883
  onInternalScrollEnd,
6781
6884
  scrollAdjustHandler,
6782
6885
  snapToIndices,
@@ -6967,7 +7070,7 @@ function checkResetContainers(ctx, dataProp, { didColumnsChange = false } = {})
6967
7070
  for (const key in state.averageSizes) {
6968
7071
  delete state.averageSizes[key];
6969
7072
  }
6970
- state.minIndexSizeChanged = 0;
7073
+ state.positionRecalculationStartIndex = 0;
6971
7074
  state.scrollForNextCalculateItemsInView = void 0;
6972
7075
  }
6973
7076
  calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
@@ -7135,7 +7238,7 @@ function handleLayout(ctx, layoutParam, setCanRender) {
7135
7238
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
7136
7239
  }
7137
7240
  if (maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.onLayout) {
7138
- doMaintainScrollAtEnd(ctx);
7241
+ doMaintainScrollAtEnd(ctx, { immediate: true });
7139
7242
  }
7140
7243
  checkThresholds(ctx);
7141
7244
  if (state) {
@@ -7364,12 +7467,12 @@ function scrollToEnd(ctx, options) {
7364
7467
  if (index === -1) {
7365
7468
  return false;
7366
7469
  }
7367
- const paddingBottom = state.props.stylePaddingBottom || 0;
7470
+ const paddingBottom = getStylePaddingEnd(state.props);
7368
7471
  const footerSize = peek$(ctx, "footerSize") || 0;
7369
7472
  scrollToIndex(ctx, {
7370
7473
  ...options,
7371
7474
  index,
7372
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
7475
+ viewOffset: getEndAlignedViewOffset(paddingBottom, footerSize) + ((options == null ? void 0 : options.viewOffset) || 0),
7373
7476
  viewPosition: 1
7374
7477
  });
7375
7478
  if (state.scrollingTo) {
@@ -7556,7 +7659,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7556
7659
  for (const key in state.averageSizes) {
7557
7660
  delete state.averageSizes[key];
7558
7661
  }
7559
- state.minIndexSizeChanged = 0;
7662
+ state.positionRecalculationStartIndex = 0;
7560
7663
  state.scrollForNextCalculateItemsInView = void 0;
7561
7664
  state.pendingTotalSize = void 0;
7562
7665
  state.totalSize = 0;
@@ -7950,10 +8053,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7950
8053
  onMetricsChange,
7951
8054
  onLayout: onLayoutProp,
7952
8055
  onLoad,
8056
+ onReady,
7953
8057
  onMomentumScrollEnd,
7954
8058
  onRefresh,
7955
8059
  onScroll: onScrollProp,
7956
8060
  onScrollBeginDrag,
8061
+ onScrollEndDrag,
7957
8062
  onStartReached,
7958
8063
  onStartReachedThreshold = 0.5,
7959
8064
  onStickyHeaderChange,
@@ -8022,17 +8127,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8022
8127
  const initialScrollProp = initialScrollAtEnd ? {
8023
8128
  index: Math.max(0, dataProp.length - 1),
8024
8129
  preserveForBottomPadding: true,
8025
- viewOffset: -stylePaddingEndState,
8130
+ viewOffset: getEndAlignedViewOffset(stylePaddingEndState),
8026
8131
  viewPosition: 1
8027
8132
  } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
8028
8133
  index: (_b = initialScrollIndexProp.index) != null ? _b : 0,
8029
8134
  preserveForBottomPadding: initialScrollIndexProp.viewOffset === void 0 && initialScrollIndexProp.viewPosition === 1 ? true : void 0,
8030
- viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingEndState : 0,
8135
+ viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? getEndAlignedViewOffset(stylePaddingEndState) : 0,
8031
8136
  viewPosition: (_d = initialScrollIndexProp.viewPosition) != null ? _d : 0
8032
8137
  } : {
8033
8138
  index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
8034
8139
  preserveForBottomPadding: shouldBottomAlignNumericInitialScrollIndex ? true : void 0,
8035
- viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : shouldBottomAlignNumericInitialScrollIndex ? -stylePaddingEndState : 0,
8140
+ viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : shouldBottomAlignNumericInitialScrollIndex ? getEndAlignedViewOffset(stylePaddingEndState) : 0,
8036
8141
  viewPosition: shouldBottomAlignNumericInitialScrollIndex ? 1 : void 0
8037
8142
  } : initialScrollUsesOffsetOnly ? {
8038
8143
  contentOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0,
@@ -8110,11 +8215,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8110
8215
  lastLayout: void 0,
8111
8216
  lastScrollDelta: 0,
8112
8217
  loadStartTime: Date.now(),
8113
- minIndexSizeChanged: 0,
8114
8218
  nativeContentInset: void 0,
8115
8219
  nativeMarginTop: 0,
8116
8220
  pendingDataComparison: void 0,
8117
8221
  pendingNativeMVCPAdjust: void 0,
8222
+ positionRecalculationStartIndex: 0,
8118
8223
  positions: [],
8119
8224
  props: {},
8120
8225
  queuedCalculateItemsInView: 0,
@@ -8217,8 +8322,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8217
8322
  onItemSizeChanged,
8218
8323
  onLoad,
8219
8324
  onMomentumScrollEnd,
8325
+ onReady,
8220
8326
  onScroll: throttleScrollFn,
8221
8327
  onScrollBeginDrag,
8328
+ onScrollEndDrag,
8222
8329
  onStartReached,
8223
8330
  onStartReachedThreshold,
8224
8331
  onStickyHeaderChange,
@@ -8506,11 +8613,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8506
8613
  onScroll: (event) => onScroll(ctx, event),
8507
8614
  onScrollBeginDrag: (event) => {
8508
8615
  var _a4, _b2;
8616
+ state.isDragging = true;
8509
8617
  interruptMaintainScrollAtEnd(ctx);
8510
8618
  prepareReachedEdgeForNextUserScroll(ctx);
8511
8619
  (_b2 = (_a4 = state.props).onScrollBeginDrag) == null ? void 0 : _b2.call(_a4, event);
8512
8620
  },
8513
- onScrollEnd: () => prepareReachedEdgeForNextUserScroll(ctx)
8621
+ onScrollEnd: () => prepareReachedEdgeForNextUserScroll(ctx),
8622
+ onScrollEndDrag: (event) => {
8623
+ var _a4, _b2;
8624
+ state.isDragging = false;
8625
+ (_b2 = (_a4 = state.props).onScrollEndDrag) == null ? void 0 : _b2.call(_a4, event);
8626
+ }
8514
8627
  }),
8515
8628
  []
8516
8629
  );
@@ -8534,6 +8647,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8534
8647
  ListHeaderComponent,
8535
8648
  onInternalScrollBeginDrag: fns.onScrollBeginDrag,
8536
8649
  onInternalScrollEnd: fns.onScrollEnd,
8650
+ onInternalScrollEndDrag: fns.onScrollEndDrag,
8537
8651
  onLayout,
8538
8652
  onLayoutFooter,
8539
8653
  onMomentumScrollEnd: fns.onMomentumScrollEnd,