@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.
package/react.js CHANGED
@@ -430,6 +430,14 @@ var EDGE_POSITION_EPSILON = 1;
430
430
  var ENABLE_DEVMODE = IS_DEV && false;
431
431
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
432
432
 
433
+ // src/core/endOfContentTarget.ts
434
+ function getEndAlignedViewOffset(stylePaddingEnd, footerSize = 0) {
435
+ return -stylePaddingEnd - footerSize;
436
+ }
437
+ function isEndOfContentTarget(target, dataLength) {
438
+ return !!target && dataLength > 0 && target.viewPosition === 1 && !!target.preserveForBottomPadding && target.index !== void 0 && target.index >= dataLength - 1;
439
+ }
440
+
433
441
  // src/core/cancelImperativeScroll.ts
434
442
  function cancelScrollCompletionChecks({ scheduledWork }) {
435
443
  scheduledWork.cancel("checkFinishedScrollFrame");
@@ -614,26 +622,25 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
614
622
  scrollPosition: context.scrollPosition
615
623
  });
616
624
  };
625
+ let reached = !!wasReached;
617
626
  if (!wasReached) {
618
- if (!within) {
619
- return false;
620
- }
621
- onReached(distance);
622
- updateSnapshot();
623
- return true;
624
- }
625
- const reset = isOutsideThresholdHysteresis(distance, atThreshold, threshold);
626
- if (reset) {
627
- setSnapshot(void 0);
628
- return false;
629
- }
630
- if (within) {
631
- const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
632
- if (changed) {
627
+ if (within && onReached(distance)) {
633
628
  updateSnapshot();
629
+ reached = true;
630
+ }
631
+ } else {
632
+ const reset = isOutsideThresholdHysteresis(distance, atThreshold, threshold);
633
+ if (reset) {
634
+ setSnapshot(void 0);
635
+ reached = false;
636
+ } else if (within) {
637
+ const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
638
+ if (changed) {
639
+ updateSnapshot();
640
+ }
634
641
  }
635
642
  }
636
- return true;
643
+ return reached;
637
644
  };
638
645
 
639
646
  // src/utils/edgeReachedGate.ts
@@ -680,7 +687,6 @@ function beginReachedEdgeUserScroll(ctx, scrollDelta) {
680
687
  return void 0;
681
688
  }
682
689
  const allowedEdge = scrollDelta < 0 ? "start" : "end";
683
- state.edgeReachedGate = "closed";
684
690
  resetEdgeLatch(ctx, allowedEdge);
685
691
  return allowedEdge;
686
692
  }
@@ -721,7 +727,7 @@ function checkAtBottom(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
721
727
  set$(
722
728
  ctx,
723
729
  "isWithinMaintainScrollAtEndThreshold",
724
- isContentLess || distanceFromEnd <= maintainScrollAtEndThreshold * scrollLength || state.pendingMaintainScrollAtEnd || maintainingScrollAtEnd === "animated" || maintainingScrollAtEnd === "instant"
730
+ isContentLess || distanceFromEnd <= maintainScrollAtEndThreshold * scrollLength || state.pendingMaintainScrollAtEnd || !!maintainingScrollAtEnd
725
731
  );
726
732
  const shouldSkipThresholdChecks = hasActiveInitialScroll(state) || maintainingScrollAtEnd;
727
733
  if (!shouldSkipThresholdChecks) {
@@ -737,11 +743,13 @@ function checkAtBottom(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
737
743
  scrollPosition: scroll
738
744
  },
739
745
  (distance) => {
740
- var _a4, _b;
741
- if (canDispatchReachedEdge(ctx, "end", allowedEdge, allowGateCreatedInCurrentCheck)) {
746
+ let dispatched = false;
747
+ if (state.props.onEndReached && canDispatchReachedEdge(ctx, "end", allowedEdge, allowGateCreatedInCurrentCheck)) {
742
748
  markReachedEdge(ctx);
743
- (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
749
+ state.props.onEndReached({ distanceFromEnd: distance });
750
+ dispatched = true;
744
751
  }
752
+ return dispatched;
745
753
  },
746
754
  (snapshot) => {
747
755
  state.endReachedSnapshot = snapshot;
@@ -774,7 +782,7 @@ function checkAtTop(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
774
782
  }
775
783
  set$(ctx, "isAtStart", scroll <= EDGE_POSITION_EPSILON);
776
784
  set$(ctx, "isNearStart", scroll <= threshold);
777
- const shouldSkipThresholdChecks = hasActiveInitialScroll(state) || !!state.scrollingTo;
785
+ const shouldSkipThresholdChecks = !state.queuedInitialLayout || hasActiveInitialScroll(state) || !!state.scrollingTo;
778
786
  if (!shouldSkipThresholdChecks) {
779
787
  state.isStartReached = checkThreshold(
780
788
  scroll,
@@ -788,11 +796,13 @@ function checkAtTop(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
788
796
  scrollPosition: scroll
789
797
  },
790
798
  (distance) => {
791
- var _a3, _b;
792
- if (canDispatchReachedEdge(ctx, "start", allowedEdge, allowGateCreatedInCurrentCheck)) {
799
+ let dispatched = false;
800
+ if (state.props.onStartReached && canDispatchReachedEdge(ctx, "start", allowedEdge, allowGateCreatedInCurrentCheck)) {
793
801
  markReachedEdge(ctx);
794
- (_b = (_a3 = state.props).onStartReached) == null ? void 0 : _b.call(_a3, { distanceFromStart: distance });
802
+ state.props.onStartReached({ distanceFromStart: distance });
803
+ dispatched = true;
795
804
  }
805
+ return dispatched;
796
806
  },
797
807
  (snapshot) => {
798
808
  state.startReachedSnapshot = snapshot;
@@ -905,6 +915,11 @@ function resetInitialRenderState(ctx, {
905
915
  if (resetLayout) {
906
916
  state.didContainersLayout = false;
907
917
  state.queuedInitialLayout = false;
918
+ state.edgeReachedGate = void 0;
919
+ state.isStartReached = null;
920
+ state.isEndReached = null;
921
+ state.startReachedSnapshot = void 0;
922
+ state.endReachedSnapshot = void 0;
908
923
  }
909
924
  if (resetInitialScroll) {
910
925
  state.didFinishInitialScroll = false;
@@ -919,7 +934,7 @@ function setInitialRenderState(ctx, {
919
934
  const { state } = ctx;
920
935
  const {
921
936
  loadStartTime,
922
- props: { onLoad }
937
+ props: { onLoad, onReady }
923
938
  } = state;
924
939
  if (didLayout) {
925
940
  state.didContainersLayout = true;
@@ -940,6 +955,7 @@ function setInitialRenderState(ctx, {
940
955
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
941
956
  }
942
957
  }
958
+ onReady == null ? void 0 : onReady();
943
959
  }
944
960
  }
945
961
 
@@ -1283,10 +1299,6 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1283
1299
  const itemSize = Math.max(0, measuredItemSize - (isOutOfBounds ? 0 : ctx.scrollAxisGap));
1284
1300
  const trailingInset = getContentInsetEnd(ctx);
1285
1301
  offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1286
- if (!isOutOfBounds && index === state.props.data.length - 1) {
1287
- const footerSize = peek$(ctx, "footerSize") || 0;
1288
- offset += footerSize;
1289
- }
1290
1302
  }
1291
1303
  return offset;
1292
1304
  }
@@ -1848,89 +1860,103 @@ function finishMaintainScrollAtEnd(ctx) {
1848
1860
  requestAdjust(ctx, nextScroll - state.scroll);
1849
1861
  }
1850
1862
  }
1851
- function doMaintainScrollAtEnd(ctx) {
1852
- var _a3, _b, _c, _d, _e;
1863
+ function doMaintainScrollAtEnd(ctx, options) {
1864
+ var _a3, _b, _c, _d, _e, _f;
1853
1865
  const state = ctx.state;
1854
- const {
1855
- didContainersLayout,
1856
- didFinishInitialScroll,
1857
- pendingNativeMVCPAdjust,
1858
- props: { maintainScrollAtEnd }
1859
- } = state;
1860
- const isWithinMaintainScrollAtEndThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1861
- const isReplayingPendingMaintain = !!state.pendingMaintainScrollAtEnd;
1862
- 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);
1863
- if (shouldMaintainScrollAtEnd && !state.scrollingTo) {
1864
- const scroller = state.refScroller.current;
1865
- const nativeMax = (_c = scroller == null ? void 0 : scroller.getMaxScrollOffset) == null ? void 0 : _c.call(scroller);
1866
- const observed = (_d = scroller == null ? void 0 : scroller.getCurrentScrollOffset) == null ? void 0 : _d.call(scroller);
1867
- if (nativeMax !== void 0 && observed !== void 0 && nativeMax < state.scroll - 1 && Math.abs(observed - nativeMax) <= 1) {
1866
+ let didMaintain = false;
1867
+ if (state.isDragging) {
1868
+ finishMaintainScrollAtEnd(ctx);
1869
+ } else {
1870
+ const {
1871
+ didContainersLayout,
1872
+ didFinishInitialScroll,
1873
+ pendingNativeMVCPAdjust,
1874
+ props: { maintainScrollAtEnd }
1875
+ } = state;
1876
+ const immediate = (options == null ? void 0 : options.immediate) && Platform.OS === "web" && !(maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.animated);
1877
+ const isWithinMaintainScrollAtEndThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1878
+ const isReplayingPendingMaintain = !!state.pendingMaintainScrollAtEnd;
1879
+ 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);
1880
+ if (shouldMaintainScrollAtEnd && !state.scrollingTo) {
1881
+ const scroller = state.refScroller.current;
1882
+ const nativeMax = (_c = scroller == null ? void 0 : scroller.getMaxScrollOffset) == null ? void 0 : _c.call(scroller);
1883
+ const observed = (_d = scroller == null ? void 0 : scroller.getCurrentScrollOffset) == null ? void 0 : _d.call(scroller);
1884
+ if (nativeMax !== void 0 && observed !== void 0 && nativeMax < state.scroll - 1 && Math.abs(observed - nativeMax) <= 1) {
1885
+ state.pendingMaintainScrollAtEnd = true;
1886
+ state.scrollPending = observed;
1887
+ updateScroll(ctx, observed, true, { markHasScrolled: false });
1888
+ }
1889
+ }
1890
+ if (shouldMaintainScrollAtEnd && !didContainersLayout) {
1868
1891
  state.pendingMaintainScrollAtEnd = true;
1869
- state.scrollPending = observed;
1870
- updateScroll(ctx, observed, true, { markHasScrolled: false });
1871
- }
1872
- }
1873
- if (shouldMaintainScrollAtEnd && !didContainersLayout) {
1874
- state.pendingMaintainScrollAtEnd = true;
1875
- return false;
1876
- }
1877
- if (pendingNativeMVCPAdjust) {
1878
- state.pendingMaintainScrollAtEnd = shouldMaintainScrollAtEnd;
1879
- return false;
1880
- }
1881
- if (shouldMaintainScrollAtEnd && (state.scrollingTo || state.pendingScrollResolve)) {
1882
- state.pendingMaintainScrollAtEnd = true;
1883
- (_e = state.maintainingScrollAtEnd) != null ? _e : state.maintainingScrollAtEnd = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1884
- return false;
1885
- }
1886
- if (shouldMaintainScrollAtEnd && didContainersLayout) {
1887
- state.pendingMaintainScrollAtEnd = false;
1888
- const contentSize = getContentSize(ctx);
1889
- if (contentSize < state.scrollLength) {
1890
- state.scroll = 0;
1891
- }
1892
- if (!state.maintainingScrollAtEnd) {
1893
- const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1894
- const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1895
- const scrollAtRequest = state.scroll;
1896
- state.maintainingScrollAtEnd = pendingState;
1897
- requestAnimationFrame(() => {
1898
- if (state.maintainingScrollAtEnd !== pendingState) {
1899
- return;
1900
- }
1901
- const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1902
- const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1903
- if (isReplayingPendingMaintain || isStillWithinThreshold || !didScrollSinceRequest) {
1904
- if (state.scrollingTo || state.pendingScrollResolve) {
1905
- state.pendingMaintainScrollAtEnd = true;
1906
- return;
1907
- }
1908
- state.maintainingScrollAtEnd = activeState;
1909
- const scrollPromise = getScrollRequestTracker(ctx).runNowIfIdle(
1910
- () => ctx.scrollToEnd({ animated: maintainScrollAtEnd.animated })
1911
- );
1912
- void scrollPromise.then(() => {
1913
- if (state.maintainingScrollAtEnd !== activeState) {
1914
- return;
1915
- }
1916
- if (state.pendingMaintainScrollAtEnd) {
1917
- state.maintainingScrollAtEnd = void 0;
1918
- doMaintainScrollAtEnd(ctx);
1919
- } else {
1892
+ } else if (pendingNativeMVCPAdjust) {
1893
+ state.pendingMaintainScrollAtEnd = shouldMaintainScrollAtEnd;
1894
+ } else if (shouldMaintainScrollAtEnd && (state.scrollingTo || state.pendingScrollResolve)) {
1895
+ if (immediate && ((_e = state.scrollingTo) == null ? void 0 : _e.isScrollToEnd) && !state.scrollingTo.animated) {
1896
+ state.pendingMaintainScrollAtEnd = false;
1897
+ ctx.scrollToEnd({ animated: false });
1898
+ didMaintain = true;
1899
+ } else {
1900
+ state.pendingMaintainScrollAtEnd = true;
1901
+ (_f = state.maintainingScrollAtEnd) != null ? _f : state.maintainingScrollAtEnd = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1902
+ }
1903
+ } else if (shouldMaintainScrollAtEnd && didContainersLayout) {
1904
+ state.pendingMaintainScrollAtEnd = false;
1905
+ const contentSize = getContentSize(ctx);
1906
+ if (contentSize < state.scrollLength) {
1907
+ state.scroll = 0;
1908
+ }
1909
+ if (!state.maintainingScrollAtEnd || immediate && state.maintainingScrollAtEnd === "pending-instant") {
1910
+ const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1911
+ const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1912
+ const scrollAtRequest = state.scroll;
1913
+ state.maintainingScrollAtEnd = pendingState;
1914
+ const run = () => {
1915
+ if (state.maintainingScrollAtEnd === pendingState) {
1916
+ if (state.isDragging) {
1920
1917
  finishMaintainScrollAtEnd(ctx);
1918
+ } else {
1919
+ const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1920
+ const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1921
+ if (isReplayingPendingMaintain || isStillWithinThreshold || !didScrollSinceRequest) {
1922
+ if (state.scrollingTo || state.pendingScrollResolve) {
1923
+ state.pendingMaintainScrollAtEnd = true;
1924
+ } else {
1925
+ state.maintainingScrollAtEnd = activeState;
1926
+ const scrollPromise = getScrollRequestTracker(ctx).runNowIfIdle(
1927
+ () => ctx.scrollToEnd({ animated: maintainScrollAtEnd.animated })
1928
+ );
1929
+ void scrollPromise.then(() => {
1930
+ if (state.maintainingScrollAtEnd === activeState) {
1931
+ if (state.pendingMaintainScrollAtEnd) {
1932
+ state.maintainingScrollAtEnd = void 0;
1933
+ doMaintainScrollAtEnd(ctx);
1934
+ } else {
1935
+ finishMaintainScrollAtEnd(ctx);
1936
+ }
1937
+ }
1938
+ });
1939
+ }
1940
+ } else if (state.maintainingScrollAtEnd === pendingState) {
1941
+ finishMaintainScrollAtEnd(ctx);
1942
+ }
1921
1943
  }
1922
- });
1923
- } else if (state.maintainingScrollAtEnd === pendingState) {
1924
- finishMaintainScrollAtEnd(ctx);
1944
+ }
1945
+ };
1946
+ if (immediate) {
1947
+ run();
1948
+ } else {
1949
+ requestAnimationFrame(run);
1925
1950
  }
1926
- });
1951
+ } else {
1952
+ state.pendingMaintainScrollAtEnd = true;
1953
+ }
1954
+ didMaintain = true;
1927
1955
  } else {
1928
- state.pendingMaintainScrollAtEnd = true;
1956
+ finishMaintainScrollAtEnd(ctx);
1929
1957
  }
1930
- return true;
1931
1958
  }
1932
- finishMaintainScrollAtEnd(ctx);
1933
- return false;
1959
+ return didMaintain;
1934
1960
  }
1935
1961
 
1936
1962
  // src/core/finishScrollTo.ts
@@ -2234,7 +2260,9 @@ function scrollTo(ctx, params) {
2234
2260
  pinScrollTargetRenderRange(ctx, targetOffset, scrollTarget.index);
2235
2261
  }
2236
2262
  }
2237
- state.scrollPending = targetOffset;
2263
+ if (!animated || isInitialScroll) {
2264
+ state.scrollPending = targetOffset;
2265
+ }
2238
2266
  syncInitialScrollNativeWatchdog(state, { isInitialScroll, requestedOffset: offset, targetOffset });
2239
2267
  if (!isInitialScroll && !noScrollingTo && Math.abs(state.scroll - targetOffset) > 1) {
2240
2268
  if (animated) {
@@ -2611,13 +2639,13 @@ function rearmBootstrapInitialScroll(ctx, options) {
2611
2639
  queueBootstrapInitialScrollReevaluation(ctx.state);
2612
2640
  }
2613
2641
  function createInitialScrollAtEndTarget(options) {
2614
- const { dataLength, footerSize, preserveForFooterLayout, stylePaddingEnd } = options;
2642
+ const { dataLength, footerSize, index, preserveForFooterLayout, stylePaddingEnd } = options;
2615
2643
  return {
2616
2644
  contentOffset: void 0,
2617
- index: Math.max(0, dataLength - 1),
2645
+ index: index != null ? index : Math.max(0, dataLength - 1),
2618
2646
  preserveForBottomPadding: true,
2619
2647
  preserveForFooterLayout,
2620
- viewOffset: -stylePaddingEnd - footerSize,
2648
+ viewOffset: getEndAlignedViewOffset(stylePaddingEnd, footerSize),
2621
2649
  viewPosition: 1
2622
2650
  };
2623
2651
  }
@@ -2633,13 +2661,14 @@ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2633
2661
  function createRetargetedBottomAlignedInitialScroll(options) {
2634
2662
  const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd, target } = options;
2635
2663
  const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2664
+ const alignsToContentEnd = initialScrollAtEnd || isEndOfContentTarget(target, dataLength);
2636
2665
  return {
2637
2666
  ...target,
2638
2667
  contentOffset: void 0,
2639
2668
  index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2640
2669
  preserveForBottomPadding: true,
2641
2670
  preserveForFooterLayout,
2642
- viewOffset: -stylePaddingEnd - (preserveForFooterLayout ? footerSize : 0),
2671
+ viewOffset: getEndAlignedViewOffset(stylePaddingEnd, alignsToContentEnd ? footerSize : 0),
2643
2672
  viewPosition: 1
2644
2673
  };
2645
2674
  }
@@ -2653,7 +2682,7 @@ function clearPendingInitialScrollFooterLayout(ctx, options) {
2653
2682
  }
2654
2683
  const clearedFooterTarget = createInitialScrollAtEndTarget({
2655
2684
  dataLength,
2656
- footerSize: 0,
2685
+ footerSize: peek$(ctx, "footerSize") || 0,
2657
2686
  preserveForFooterLayout: void 0,
2658
2687
  stylePaddingEnd
2659
2688
  });
@@ -2676,13 +2705,12 @@ function getObservedBootstrapInitialScrollOffset(state) {
2676
2705
  return typeof observedOffset === "number" && Number.isFinite(observedOffset) ? observedOffset : (_d = (_c = state.scrollPending) != null ? _c : state.scroll) != null ? _d : 0;
2677
2706
  }
2678
2707
  function getPreservedEndAnchorOffsetDiff(ctx) {
2679
- var _a3;
2680
2708
  const state = ctx.state;
2681
2709
  const initialScroll = state.initialScroll;
2682
- if (!state.didFinishInitialScroll || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) || !initialScroll || initialScroll.viewPosition !== 1 || state.props.data.length === 0 || isOffsetInitialScrollSession(state)) {
2710
+ if (!state.didFinishInitialScroll || state.scrollingTo || state.pendingScrollResolve || state.maintainingScrollAtEnd || state.isDragging || !initialScroll || initialScroll.viewPosition !== 1 || state.props.data.length === 0 || isOffsetInitialScrollSession(state)) {
2683
2711
  return;
2684
2712
  }
2685
- const currentOffset = typeof state.lastNativeScroll === "number" && Number.isFinite(state.lastNativeScroll) ? state.lastNativeScroll : getObservedBootstrapInitialScrollOffset(state);
2713
+ const currentOffset = getObservedBootstrapInitialScrollOffset(state);
2686
2714
  return resolveInitialScrollOffset(ctx, initialScroll) - currentOffset;
2687
2715
  }
2688
2716
  function schedulePreservedEndAnchorCorrection(ctx) {
@@ -2710,6 +2738,9 @@ function schedulePreservedEndAnchorCorrectionFrame(ctx, correction) {
2710
2738
  const hasObservedNativeScrollAfterRequest = !activeCorrection.lastRequestTime || ((_a3 = state.lastNativeScrollTime) != null ? _a3 : 0) > activeCorrection.lastRequestTime;
2711
2739
  if (hasObservedNativeScrollAfterRequest) {
2712
2740
  activeCorrection.lastRequestTime = Date.now();
2741
+ {
2742
+ state.scroll = getObservedBootstrapInitialScrollOffset(state);
2743
+ }
2713
2744
  requestAdjust(ctx, offsetDiff);
2714
2745
  }
2715
2746
  schedulePreservedEndAnchorCorrectionFrame(ctx, correction);
@@ -2832,10 +2863,10 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2832
2863
  function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2833
2864
  const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd } = options;
2834
2865
  const state = ctx.state;
2835
- if (!initialScrollAtEnd) {
2866
+ const initialScroll = state.initialScroll;
2867
+ if (!initialScrollAtEnd && !isEndOfContentTarget(initialScroll, dataLength)) {
2836
2868
  return;
2837
2869
  }
2838
- const initialScroll = state.initialScroll;
2839
2870
  if (isOffsetInitialScrollSession(state) || dataLength === 0 || !initialScroll) {
2840
2871
  return;
2841
2872
  }
@@ -2853,6 +2884,7 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2853
2884
  const updatedInitialScroll = createInitialScrollAtEndTarget({
2854
2885
  dataLength,
2855
2886
  footerSize,
2887
+ index: initialScrollAtEnd ? void 0 : initialScroll.index,
2856
2888
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2857
2889
  stylePaddingEnd
2858
2890
  });
@@ -4002,7 +4034,7 @@ function getExpandedContainerPoolSize(dataLength, numContainers) {
4002
4034
  }
4003
4035
 
4004
4036
  // src/utils/findAvailableContainers.ts
4005
- function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffered, pendingRemoval, getRequiredItemType, protectedKeys) {
4037
+ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffered, pendingRemoval, protectedKeys, reverseItemOrder = false) {
4006
4038
  var _a3;
4007
4039
  const numNeeded = needNewContainers.length;
4008
4040
  if (numNeeded === 0) {
@@ -4011,16 +4043,27 @@ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffe
4011
4043
  const numContainers = peek$(ctx, "numContainers");
4012
4044
  const state = ctx.state;
4013
4045
  const { containerItemMetadata, stickyContainerPool } = state;
4046
+ const { data, getItemType } = state.props;
4047
+ const hasItemTypes = !!getItemType;
4014
4048
  const shouldAvoidAssignedContainerReuse = state.props.recycleItems && !!state.props.positionComponentInternal;
4015
4049
  const pendingRemovalSet = pendingRemoval.length > 0 ? new Set(pendingRemoval) : void 0;
4016
- const requests = needNewContainers.map((itemIndex, order) => ({
4017
- isSticky: state.props.stickyHeaderIndicesSet.has(itemIndex),
4018
- itemIndex,
4019
- itemType: getRequiredItemType == null ? void 0 : getRequiredItemType(itemIndex),
4020
- order
4021
- }));
4022
- const normalRequests = requests.filter((request) => !request.isSticky);
4023
- const stickyRequests = requests.filter((request) => request.isSticky);
4050
+ const requests = new Array(numNeeded);
4051
+ const normalRequests = [];
4052
+ const stickyRequests = [];
4053
+ for (let order = 0; order < numNeeded; order++) {
4054
+ const itemIndex = needNewContainers[order];
4055
+ const itemType = getItemType == null ? void 0 : getItemType(data[itemIndex], itemIndex);
4056
+ const request = {
4057
+ isBuffered: itemIndex >= startBuffered && itemIndex <= endBuffered,
4058
+ isSticky: state.props.stickyHeaderIndicesSet.has(itemIndex),
4059
+ itemIndex,
4060
+ itemType: hasItemTypes ? itemType !== void 0 ? String(itemType) : "" : void 0,
4061
+ order,
4062
+ renderPriority: reverseItemOrder ? -itemIndex : itemIndex
4063
+ };
4064
+ requests[order] = request;
4065
+ (request.isSticky ? stickyRequests : normalRequests).push(request);
4066
+ }
4024
4067
  const normalCandidates = [];
4025
4068
  const stickyCandidates = [];
4026
4069
  for (let containerIndex = 0; containerIndex < numContainers; containerIndex++) {
@@ -4076,7 +4119,7 @@ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffe
4076
4119
  }
4077
4120
  };
4078
4121
  const assignFromPool = (pendingRequests, candidates, allowCrossType) => {
4079
- if (getRequiredItemType) {
4122
+ if (hasItemTypes) {
4080
4123
  assignMatching(
4081
4124
  pendingRequests,
4082
4125
  candidates,
@@ -4100,6 +4143,11 @@ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffe
4100
4143
  }
4101
4144
  assign(request, containerIndex);
4102
4145
  }
4146
+ if (normalRequests.length > 1 || stickyRequests.length > 1) {
4147
+ const containerIndices = [];
4148
+ reorderPoolAssignments(normalRequests, allocations, containerIndices, hasItemTypes);
4149
+ reorderPoolAssignments(stickyRequests, allocations, containerIndices, hasItemTypes);
4150
+ }
4103
4151
  if (pendingRemovalChanged) {
4104
4152
  pendingRemoval.length = 0;
4105
4153
  if (pendingRemovalSet) {
@@ -4129,12 +4177,53 @@ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffe
4129
4177
  function comparatorByDistance(a, b) {
4130
4178
  return b.distance - a.distance;
4131
4179
  }
4180
+ function comparatorByRenderPriority(a, b) {
4181
+ return Number(b.isBuffered) - Number(a.isBuffered) || a.renderPriority - b.renderPriority;
4182
+ }
4183
+ function comparatorByIndex(a, b) {
4184
+ return a - b;
4185
+ }
4186
+ function reorderPoolAssignments(requests, allocations, containerIndices, groupByType) {
4187
+ if (requests.length >= 2) {
4188
+ if (groupByType) {
4189
+ const groups = /* @__PURE__ */ new Map();
4190
+ for (const request of requests) {
4191
+ const group = groups.get(request.itemType);
4192
+ if (group) {
4193
+ group.push(request);
4194
+ } else {
4195
+ groups.set(request.itemType, [request]);
4196
+ }
4197
+ }
4198
+ for (const group of groups.values()) {
4199
+ reorderPoolAssignments(group, allocations, containerIndices, false);
4200
+ }
4201
+ } else {
4202
+ containerIndices.length = 0;
4203
+ let indicesSorted = true;
4204
+ for (let i = 0; i < requests.length; i++) {
4205
+ const containerIndex = allocations[requests[i].order].containerIndex;
4206
+ if (i > 0 && containerIndex < containerIndices[i - 1]) {
4207
+ indicesSorted = false;
4208
+ }
4209
+ containerIndices.push(containerIndex);
4210
+ }
4211
+ if (!indicesSorted) {
4212
+ containerIndices.sort(comparatorByIndex);
4213
+ }
4214
+ requests.sort(comparatorByRenderPriority);
4215
+ for (let i = 0; i < requests.length; i++) {
4216
+ allocations[requests[i].order].containerIndex = containerIndices[i];
4217
+ }
4218
+ }
4219
+ }
4220
+ }
4132
4221
 
4133
4222
  // src/utils/setDidLayout.ts
4134
4223
  function setDidLayout(ctx) {
4135
4224
  const state = ctx.state;
4136
4225
  state.queuedInitialLayout = true;
4137
- checkAtBottom(ctx);
4226
+ checkThresholds(ctx);
4138
4227
  setInitialRenderState(ctx, { didLayout: true });
4139
4228
  if (state.pendingMaintainScrollAtEnd) {
4140
4229
  doMaintainScrollAtEnd(ctx);
@@ -4362,9 +4451,9 @@ function calculateItemsInView(ctx, params = {}) {
4362
4451
  enableScrollForNextCalculateItemsInView,
4363
4452
  idCache,
4364
4453
  indexByKey,
4365
- minIndexSizeChanged,
4454
+ positionRecalculationStartIndex,
4366
4455
  positions,
4367
- props: { alwaysRenderIndicesArr, alwaysRenderIndicesSet, getItemType, keyExtractor, onStickyHeaderChange },
4456
+ props: { alwaysRenderIndicesArr, alwaysRenderIndicesSet, keyExtractor, onStickyHeaderChange },
4368
4457
  scrollForNextCalculateItemsInView,
4369
4458
  scrollLength,
4370
4459
  sizes,
@@ -4480,21 +4569,21 @@ function calculateItemsInView(ctx, params = {}) {
4480
4569
  if (dataChanged) {
4481
4570
  resetLayoutCachesForDataChange(state);
4482
4571
  }
4483
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_e = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _e : 0;
4484
- const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4572
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_e = positionRecalculationStartIndex != null ? positionRecalculationStartIndex : state.startBuffered) != null ? _e : 0;
4573
+ const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && positionRecalculationStartIndex !== void 0;
4485
4574
  updateItemPositions(ctx, dataChanged, {
4486
4575
  doMVCP,
4487
4576
  // A changed size shifts every following position. The scrolling early-exit
4488
4577
  // would leave the untouched suffix in the old coordinate space.
4489
- forceFullUpdate: !!forceFullItemPositions || minIndexSizeChanged !== void 0,
4578
+ forceFullUpdate: !!forceFullItemPositions || positionRecalculationStartIndex !== void 0,
4490
4579
  optimizeForVisibleWindow,
4491
4580
  scrollBottomBuffered,
4492
4581
  scrollVelocity: speed,
4493
4582
  startIndex
4494
4583
  });
4495
4584
  totalSize = getContentSize(ctx);
4496
- if (minIndexSizeChanged !== void 0) {
4497
- state.minIndexSizeChanged = void 0;
4585
+ if (positionRecalculationStartIndex !== void 0) {
4586
+ state.positionRecalculationStartIndex = void 0;
4498
4587
  }
4499
4588
  let protectedContainerKeys;
4500
4589
  if (dataChanged && doMVCP && state.props.maintainVisibleContentPosition.data && state.didContainersLayout && state.idsInView.length > 0) {
@@ -4670,18 +4759,18 @@ function calculateItemsInView(ctx, params = {}) {
4670
4759
  set$(ctx, "activeStickyIndex", -1);
4671
4760
  }
4672
4761
  if (needNewContainers.length > 0) {
4673
- const getRequiredItemType = getItemType ? (i) => {
4674
- const itemType = getItemType(data[i], i);
4675
- return itemType !== void 0 ? String(itemType) : "";
4676
- } : void 0;
4677
4762
  const availableContainerAllocations = findAvailableContainers(
4678
4763
  ctx,
4679
4764
  needNewContainers,
4680
4765
  startBuffered,
4681
4766
  endBuffered,
4682
4767
  pendingRemoval,
4683
- getRequiredItemType,
4684
- protectedContainerKeys
4768
+ protectedContainerKeys,
4769
+ // Initial end alignment has no scroll velocity yet. Keep its
4770
+ // target-side rows first until the initial scroll settles.
4771
+ // After a pause velocity can be zero on the first movement;
4772
+ // use its displacement without treating initial insets as motion.
4773
+ hasActiveInitialScroll(state) ? (initialScroll == null ? void 0 : initialScroll.viewPosition) === 1 : (speed || (state.hasScrolled ? state.scroll - state.scrollPrev : 0)) < 0
4685
4774
  );
4686
4775
  for (const allocation of availableContainerAllocations) {
4687
4776
  const i = allocation.itemIndex;
@@ -4964,6 +5053,7 @@ function updateItemSizesBatch(ctx, measurements) {
4964
5053
  var _a3;
4965
5054
  const state = ctx.state;
4966
5055
  const result = {};
5056
+ const previousTotalSize = state.totalSize;
4967
5057
  for (const measurement of measurements) {
4968
5058
  const ownsMeasuredItem = measurement.containerId === void 0 || peek$(ctx, `containerItemKey${measurement.containerId}`) === measurement.itemKey;
4969
5059
  if (ownsMeasuredItem) {
@@ -4974,6 +5064,9 @@ function updateItemSizesBatch(ctx, measurements) {
4974
5064
  mergeItemSizeUpdateResult(result, nextResult);
4975
5065
  }
4976
5066
  }
5067
+ if (state.totalSize !== previousTotalSize) {
5068
+ set$(ctx, "totalSize", state.totalSize);
5069
+ }
4977
5070
  flushItemSizeUpdates(ctx, result);
4978
5071
  }
4979
5072
  function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
@@ -5012,12 +5105,12 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5012
5105
  }
5013
5106
  let needsRecalculate = !didContainersLayout;
5014
5107
  let shouldMaintainScrollAtEnd = false;
5015
- let minIndexSizeChanged;
5108
+ let positionRecalculationStartIndex;
5016
5109
  const prevSizeKnown = state.sizesKnown.get(itemKey);
5017
- const diff = updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem);
5110
+ const diff = updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem, false);
5018
5111
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
5019
5112
  if (diff !== 0) {
5020
- minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
5113
+ positionRecalculationStartIndex = positionRecalculationStartIndex !== void 0 ? Math.min(positionRecalculationStartIndex, index) : index;
5021
5114
  const { startBuffered, endBuffered } = state;
5022
5115
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
5023
5116
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
@@ -5034,8 +5127,8 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5034
5127
  size
5035
5128
  });
5036
5129
  }
5037
- if (minIndexSizeChanged !== void 0) {
5038
- state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
5130
+ if (positionRecalculationStartIndex !== void 0) {
5131
+ state.positionRecalculationStartIndex = state.positionRecalculationStartIndex !== void 0 ? Math.min(state.positionRecalculationStartIndex, positionRecalculationStartIndex) : positionRecalculationStartIndex;
5039
5132
  }
5040
5133
  updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5041
5134
  if (didContainersLayout || checkAllSizesKnown(state, state.startBuffered, state.endBuffered)) {
@@ -5052,7 +5145,7 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5052
5145
  didMeasureUserScrollAnchorResetItem
5053
5146
  };
5054
5147
  }
5055
- function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5148
+ function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem, notifyTotalSize = true) {
5056
5149
  var _a3, _b;
5057
5150
  const state = ctx.state;
5058
5151
  const {
@@ -5075,7 +5168,16 @@ function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5075
5168
  fixedItemSize,
5076
5169
  itemType
5077
5170
  } : void 0;
5078
- const prevSize = getItemSize(ctx, itemKey, index, itemData, void 0, void 0, void 0, resolvedItemSize);
5171
+ const prevSize = getItemSize(
5172
+ ctx,
5173
+ itemKey,
5174
+ index,
5175
+ itemData,
5176
+ void 0,
5177
+ void 0,
5178
+ notifyTotalSize,
5179
+ resolvedItemSize
5180
+ );
5079
5181
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
5080
5182
  const prevSizeKnown = sizesKnown.get(itemKey);
5081
5183
  const size = Math.round(rawSize) ;
@@ -5097,7 +5199,7 @@ function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5097
5199
  }
5098
5200
  }
5099
5201
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
5100
- setSize(ctx, itemKey, size);
5202
+ setSize(ctx, itemKey, size, notifyTotalSize);
5101
5203
  return size - prevSize;
5102
5204
  }
5103
5205
  return 0;
@@ -6798,6 +6900,7 @@ var ListComponent = typedMemo(function ListComponent2({
6798
6900
  renderScrollComponent,
6799
6901
  onLayoutFooter,
6800
6902
  onInternalScrollBeginDrag,
6903
+ onInternalScrollEndDrag,
6801
6904
  onInternalScrollEnd,
6802
6905
  scrollAdjustHandler,
6803
6906
  snapToIndices,
@@ -6988,7 +7091,7 @@ function checkResetContainers(ctx, dataProp, { didColumnsChange = false } = {})
6988
7091
  for (const key in state.averageSizes) {
6989
7092
  delete state.averageSizes[key];
6990
7093
  }
6991
- state.minIndexSizeChanged = 0;
7094
+ state.positionRecalculationStartIndex = 0;
6992
7095
  state.scrollForNextCalculateItemsInView = void 0;
6993
7096
  }
6994
7097
  calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
@@ -7156,7 +7259,7 @@ function handleLayout(ctx, layoutParam, setCanRender) {
7156
7259
  set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
7157
7260
  }
7158
7261
  if (maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.onLayout) {
7159
- doMaintainScrollAtEnd(ctx);
7262
+ doMaintainScrollAtEnd(ctx, { immediate: true });
7160
7263
  }
7161
7264
  checkThresholds(ctx);
7162
7265
  if (state) {
@@ -7385,12 +7488,12 @@ function scrollToEnd(ctx, options) {
7385
7488
  if (index === -1) {
7386
7489
  return false;
7387
7490
  }
7388
- const paddingBottom = state.props.stylePaddingBottom || 0;
7491
+ const paddingBottom = getStylePaddingEnd(state.props);
7389
7492
  const footerSize = peek$(ctx, "footerSize") || 0;
7390
7493
  scrollToIndex(ctx, {
7391
7494
  ...options,
7392
7495
  index,
7393
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
7496
+ viewOffset: getEndAlignedViewOffset(paddingBottom, footerSize) + ((options == null ? void 0 : options.viewOffset) || 0),
7394
7497
  viewPosition: 1
7395
7498
  });
7396
7499
  if (state.scrollingTo) {
@@ -7577,7 +7680,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7577
7680
  for (const key in state.averageSizes) {
7578
7681
  delete state.averageSizes[key];
7579
7682
  }
7580
- state.minIndexSizeChanged = 0;
7683
+ state.positionRecalculationStartIndex = 0;
7581
7684
  state.scrollForNextCalculateItemsInView = void 0;
7582
7685
  state.pendingTotalSize = void 0;
7583
7686
  state.totalSize = 0;
@@ -7971,10 +8074,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7971
8074
  onMetricsChange,
7972
8075
  onLayout: onLayoutProp,
7973
8076
  onLoad,
8077
+ onReady,
7974
8078
  onMomentumScrollEnd,
7975
8079
  onRefresh,
7976
8080
  onScroll: onScrollProp,
7977
8081
  onScrollBeginDrag,
8082
+ onScrollEndDrag,
7978
8083
  onStartReached,
7979
8084
  onStartReachedThreshold = 0.5,
7980
8085
  onStickyHeaderChange,
@@ -8043,17 +8148,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8043
8148
  const initialScrollProp = initialScrollAtEnd ? {
8044
8149
  index: Math.max(0, dataProp.length - 1),
8045
8150
  preserveForBottomPadding: true,
8046
- viewOffset: -stylePaddingEndState,
8151
+ viewOffset: getEndAlignedViewOffset(stylePaddingEndState),
8047
8152
  viewPosition: 1
8048
8153
  } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
8049
8154
  index: (_b = initialScrollIndexProp.index) != null ? _b : 0,
8050
8155
  preserveForBottomPadding: initialScrollIndexProp.viewOffset === void 0 && initialScrollIndexProp.viewPosition === 1 ? true : void 0,
8051
- viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingEndState : 0,
8156
+ viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? getEndAlignedViewOffset(stylePaddingEndState) : 0,
8052
8157
  viewPosition: (_d = initialScrollIndexProp.viewPosition) != null ? _d : 0
8053
8158
  } : {
8054
8159
  index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
8055
8160
  preserveForBottomPadding: shouldBottomAlignNumericInitialScrollIndex ? true : void 0,
8056
- viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : shouldBottomAlignNumericInitialScrollIndex ? -stylePaddingEndState : 0,
8161
+ viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : shouldBottomAlignNumericInitialScrollIndex ? getEndAlignedViewOffset(stylePaddingEndState) : 0,
8057
8162
  viewPosition: shouldBottomAlignNumericInitialScrollIndex ? 1 : void 0
8058
8163
  } : initialScrollUsesOffsetOnly ? {
8059
8164
  contentOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0,
@@ -8131,11 +8236,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8131
8236
  lastLayout: void 0,
8132
8237
  lastScrollDelta: 0,
8133
8238
  loadStartTime: Date.now(),
8134
- minIndexSizeChanged: 0,
8135
8239
  nativeContentInset: void 0,
8136
8240
  nativeMarginTop: 0,
8137
8241
  pendingDataComparison: void 0,
8138
8242
  pendingNativeMVCPAdjust: void 0,
8243
+ positionRecalculationStartIndex: 0,
8139
8244
  positions: [],
8140
8245
  props: {},
8141
8246
  queuedCalculateItemsInView: 0,
@@ -8238,8 +8343,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8238
8343
  onItemSizeChanged,
8239
8344
  onLoad,
8240
8345
  onMomentumScrollEnd,
8346
+ onReady,
8241
8347
  onScroll: throttleScrollFn,
8242
8348
  onScrollBeginDrag,
8349
+ onScrollEndDrag,
8243
8350
  onStartReached,
8244
8351
  onStartReachedThreshold,
8245
8352
  onStickyHeaderChange,
@@ -8527,11 +8634,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8527
8634
  onScroll: (event) => onScroll(ctx, event),
8528
8635
  onScrollBeginDrag: (event) => {
8529
8636
  var _a4, _b2;
8637
+ state.isDragging = true;
8530
8638
  interruptMaintainScrollAtEnd(ctx);
8531
8639
  prepareReachedEdgeForNextUserScroll(ctx);
8532
8640
  (_b2 = (_a4 = state.props).onScrollBeginDrag) == null ? void 0 : _b2.call(_a4, event);
8533
8641
  },
8534
- onScrollEnd: () => prepareReachedEdgeForNextUserScroll(ctx)
8642
+ onScrollEnd: () => prepareReachedEdgeForNextUserScroll(ctx),
8643
+ onScrollEndDrag: (event) => {
8644
+ var _a4, _b2;
8645
+ state.isDragging = false;
8646
+ (_b2 = (_a4 = state.props).onScrollEndDrag) == null ? void 0 : _b2.call(_a4, event);
8647
+ }
8535
8648
  }),
8536
8649
  []
8537
8650
  );
@@ -8555,6 +8668,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8555
8668
  ListHeaderComponent,
8556
8669
  onInternalScrollBeginDrag: fns.onScrollBeginDrag,
8557
8670
  onInternalScrollEnd: fns.onScrollEnd,
8671
+ onInternalScrollEndDrag: fns.onScrollEndDrag,
8558
8672
  onLayout,
8559
8673
  onLayoutFooter,
8560
8674
  onMomentumScrollEnd: fns.onMomentumScrollEnd,