@legendapp/list 3.0.0-beta.43 → 3.0.0-beta.44

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.
@@ -940,7 +940,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
940
940
  const ref = React3.useRef(null);
941
941
  const ctx = useStateContext();
942
942
  const columnWrapperStyle = ctx.columnWrapperStyle;
943
- const [totalSize, otherAxisSize] = useArr$(["totalSize", "otherAxisSize"]);
943
+ const [otherAxisSize, totalSize] = useArr$(["otherAxisSize", "totalSize"]);
944
944
  useDOMOrder(ref);
945
945
  const style = horizontal ? { minHeight: otherAxisSize, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, position: "relative" };
946
946
  if (columnWrapperStyle && numColumns > 1) {
@@ -969,7 +969,6 @@ var Containers = typedMemo(function Containers2({
969
969
  horizontal,
970
970
  recycleItems,
971
971
  ItemSeparatorComponent,
972
- waitForInitialLayout,
973
972
  updateItemSize: updateItemSize2,
974
973
  getRenderedItem: getRenderedItem2,
975
974
  stickyHeaderConfig
@@ -993,7 +992,7 @@ var Containers = typedMemo(function Containers2({
993
992
  )
994
993
  );
995
994
  }
996
- return /* @__PURE__ */ React3__namespace.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
995
+ return /* @__PURE__ */ React3__namespace.createElement(ContainersInner, { horizontal, numColumns }, containers);
997
996
  });
998
997
 
999
998
  // src/platform/StyleSheet.tsx
@@ -1444,7 +1443,6 @@ var ListComponent = typedMemo(function ListComponent2({
1444
1443
  recycleItems,
1445
1444
  ItemSeparatorComponent,
1446
1445
  alignItemsAtEnd: _alignItemsAtEnd,
1447
- waitForInitialLayout,
1448
1446
  onScroll: onScroll2,
1449
1447
  onLayout,
1450
1448
  ListHeaderComponent,
@@ -1507,7 +1505,7 @@ var ListComponent = typedMemo(function ListComponent2({
1507
1505
  height: "100%"
1508
1506
  } : {}
1509
1507
  ],
1510
- contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1508
+ contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1511
1509
  horizontal,
1512
1510
  maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
1513
1511
  onLayout,
@@ -1527,8 +1525,7 @@ var ListComponent = typedMemo(function ListComponent2({
1527
1525
  ItemSeparatorComponent,
1528
1526
  recycleItems,
1529
1527
  stickyHeaderConfig,
1530
- updateItemSize: updateItemSize2,
1531
- waitForInitialLayout
1528
+ updateItemSize: updateItemSize2
1532
1529
  }
1533
1530
  ),
1534
1531
  ListFooterComponent && /* @__PURE__ */ React3__namespace.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
@@ -1641,6 +1638,13 @@ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1641
1638
  setSize(ctx, key, size);
1642
1639
  return size;
1643
1640
  }
1641
+ function getItemSizeAtIndex(ctx, index) {
1642
+ if (index === void 0 || index < 0) {
1643
+ return void 0;
1644
+ }
1645
+ const targetId = getId(ctx.state, index);
1646
+ return getItemSize(ctx, targetId, index, ctx.state.props.data[index]);
1647
+ }
1644
1648
 
1645
1649
  // src/core/calculateOffsetWithOffsetPosition.ts
1646
1650
  function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
@@ -1691,6 +1695,373 @@ function clampScrollOffset(ctx, offset, scrollTarget) {
1691
1695
  return clampedOffset;
1692
1696
  }
1693
1697
 
1698
+ // src/core/deferredPublicOnScroll.ts
1699
+ function withResolvedContentOffset(state, event, resolvedOffset) {
1700
+ return {
1701
+ ...event,
1702
+ nativeEvent: {
1703
+ ...event.nativeEvent,
1704
+ contentOffset: state.props.horizontal ? { x: resolvedOffset, y: 0 } : { x: 0, y: resolvedOffset }
1705
+ }
1706
+ };
1707
+ }
1708
+ function releaseDeferredPublicOnScroll(ctx, resolvedOffset) {
1709
+ var _a3, _b, _c, _d;
1710
+ const state = ctx.state;
1711
+ const deferredEvent = state.deferredPublicOnScrollEvent;
1712
+ state.deferredPublicOnScrollEvent = void 0;
1713
+ if (deferredEvent) {
1714
+ (_d = (_c = state.props).onScroll) == null ? void 0 : _d.call(
1715
+ _c,
1716
+ withResolvedContentOffset(
1717
+ state,
1718
+ deferredEvent,
1719
+ (_b = (_a3 = resolvedOffset != null ? resolvedOffset : state.scrollPending) != null ? _a3 : state.scroll) != null ? _b : 0
1720
+ )
1721
+ );
1722
+ }
1723
+ }
1724
+
1725
+ // src/core/initialScrollSession.ts
1726
+ var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
1727
+ function hasInitialScrollSessionCompletion(completion) {
1728
+ return !!((completion == null ? void 0 : completion.didDispatchNativeScroll) || (completion == null ? void 0 : completion.didRetrySilentInitialScroll) || (completion == null ? void 0 : completion.watchdog));
1729
+ }
1730
+ function clearInitialScrollSession(state) {
1731
+ state.initialScrollSession = void 0;
1732
+ return void 0;
1733
+ }
1734
+ function createInitialScrollSession(options) {
1735
+ const { bootstrap, completion, kind, previousDataLength } = options;
1736
+ return kind === "offset" ? {
1737
+ completion,
1738
+ kind,
1739
+ previousDataLength
1740
+ } : {
1741
+ bootstrap,
1742
+ completion,
1743
+ kind,
1744
+ previousDataLength
1745
+ };
1746
+ }
1747
+ function ensureInitialScrollSessionCompletion(state, kind = ((_b) => (_b = ((_a3) => (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind)()) != null ? _b : "bootstrap")()) {
1748
+ var _a4, _b2;
1749
+ if (!state.initialScrollSession) {
1750
+ state.initialScrollSession = createInitialScrollSession({
1751
+ completion: {},
1752
+ kind,
1753
+ previousDataLength: 0
1754
+ });
1755
+ } else if (state.initialScrollSession.kind !== kind) {
1756
+ state.initialScrollSession = createInitialScrollSession({
1757
+ bootstrap: state.initialScrollSession.kind === "bootstrap" ? state.initialScrollSession.bootstrap : void 0,
1758
+ completion: state.initialScrollSession.completion,
1759
+ kind,
1760
+ previousDataLength: state.initialScrollSession.previousDataLength
1761
+ });
1762
+ }
1763
+ (_b2 = (_a4 = state.initialScrollSession).completion) != null ? _b2 : _a4.completion = {};
1764
+ return state.initialScrollSession.completion;
1765
+ }
1766
+ var initialScrollCompletion = {
1767
+ didDispatchNativeScroll(state) {
1768
+ var _a3, _b;
1769
+ return !!((_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.didDispatchNativeScroll);
1770
+ },
1771
+ didRetrySilentInitialScroll(state) {
1772
+ var _a3, _b;
1773
+ return !!((_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.didRetrySilentInitialScroll);
1774
+ },
1775
+ markInitialScrollNativeDispatch(state) {
1776
+ ensureInitialScrollSessionCompletion(state).didDispatchNativeScroll = true;
1777
+ },
1778
+ markSilentInitialScrollRetry(state) {
1779
+ ensureInitialScrollSessionCompletion(state).didRetrySilentInitialScroll = true;
1780
+ },
1781
+ resetFlags(state) {
1782
+ if (!state.initialScrollSession) {
1783
+ return;
1784
+ }
1785
+ const completion = ensureInitialScrollSessionCompletion(state, state.initialScrollSession.kind);
1786
+ completion.didDispatchNativeScroll = void 0;
1787
+ completion.didRetrySilentInitialScroll = void 0;
1788
+ }
1789
+ };
1790
+ var initialScrollWatchdog = {
1791
+ clear(state) {
1792
+ initialScrollWatchdog.set(state, void 0);
1793
+ },
1794
+ didObserveProgress(newScroll, watchdog) {
1795
+ const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
1796
+ const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
1797
+ return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET || nextDistance + INITIAL_SCROLL_MIN_TARGET_OFFSET < previousDistance;
1798
+ },
1799
+ get(state) {
1800
+ var _a3, _b;
1801
+ return (_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.watchdog;
1802
+ },
1803
+ hasNonZeroTargetOffset(targetOffset) {
1804
+ return targetOffset !== void 0 && targetOffset > INITIAL_SCROLL_MIN_TARGET_OFFSET;
1805
+ },
1806
+ isAtZeroTargetOffset(targetOffset) {
1807
+ return targetOffset <= INITIAL_SCROLL_MIN_TARGET_OFFSET;
1808
+ },
1809
+ set(state, watchdog) {
1810
+ var _a3, _b;
1811
+ if (!watchdog && !((_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.watchdog)) {
1812
+ return;
1813
+ }
1814
+ const completion = ensureInitialScrollSessionCompletion(state);
1815
+ completion.watchdog = watchdog ? {
1816
+ startScroll: watchdog.startScroll,
1817
+ targetOffset: watchdog.targetOffset
1818
+ } : void 0;
1819
+ }
1820
+ };
1821
+ function setInitialScrollSession(state, options = {}) {
1822
+ var _a3, _b, _c;
1823
+ const existingSession = state.initialScrollSession;
1824
+ const kind = (_a3 = options.kind) != null ? _a3 : existingSession == null ? void 0 : existingSession.kind;
1825
+ const completion = existingSession == null ? void 0 : existingSession.completion;
1826
+ const hasBootstrapOverride = Object.hasOwn(options, "bootstrap");
1827
+ const bootstrap = kind === "bootstrap" ? hasBootstrapOverride ? options.bootstrap : (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0 : void 0;
1828
+ if (!kind) {
1829
+ return clearInitialScrollSession(state);
1830
+ }
1831
+ if (!state.initialScroll && !bootstrap && !hasInitialScrollSessionCompletion(completion)) {
1832
+ return clearInitialScrollSession(state);
1833
+ }
1834
+ const previousDataLength = (_c = (_b = options.previousDataLength) != null ? _b : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _c : 0;
1835
+ state.initialScrollSession = createInitialScrollSession({
1836
+ bootstrap,
1837
+ completion,
1838
+ kind,
1839
+ previousDataLength
1840
+ });
1841
+ return state.initialScrollSession;
1842
+ }
1843
+
1844
+ // src/core/finishScrollTo.ts
1845
+ function finishScrollTo(ctx) {
1846
+ var _a3, _b;
1847
+ const state = ctx.state;
1848
+ if (state == null ? void 0 : state.scrollingTo) {
1849
+ const resolvePendingScroll = state.pendingScrollResolve;
1850
+ state.pendingScrollResolve = void 0;
1851
+ const scrollingTo = state.scrollingTo;
1852
+ state.scrollHistory.length = 0;
1853
+ state.scrollingTo = void 0;
1854
+ if (state.pendingTotalSize !== void 0) {
1855
+ addTotalSize(ctx, null, state.pendingTotalSize);
1856
+ }
1857
+ {
1858
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1859
+ }
1860
+ if (scrollingTo.isInitialScroll || state.initialScroll) {
1861
+ const isOffsetSession = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
1862
+ finishInitialScroll(ctx, {
1863
+ onFinished: resolvePendingScroll,
1864
+ preserveTarget: isOffsetSession && state.props.data.length === 0 || !!scrollingTo.isInitialScroll && !!((_b = state.initialScroll) == null ? void 0 : _b.preserveForFooterLayout),
1865
+ recalculateItems: true,
1866
+ syncObservedOffset: isOffsetSession,
1867
+ waitForCompletionFrame: !!scrollingTo.waitForInitialScrollCompletionFrame
1868
+ });
1869
+ return;
1870
+ }
1871
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
1872
+ }
1873
+ }
1874
+
1875
+ // src/core/doScrollTo.ts
1876
+ var SCROLL_END_IDLE_MS = 80;
1877
+ var SCROLL_END_MAX_MS = 1500;
1878
+ var SMOOTH_SCROLL_DURATION_MS = 320;
1879
+ var SCROLL_END_TARGET_EPSILON = 1;
1880
+ function doScrollTo(ctx, params) {
1881
+ const state = ctx.state;
1882
+ const { animated, horizontal, offset } = params;
1883
+ const scroller = state.refScroller.current;
1884
+ const node = scroller == null ? void 0 : scroller.getScrollableNode();
1885
+ if (!scroller || !node) {
1886
+ return;
1887
+ }
1888
+ const isAnimated = !!animated;
1889
+ const isHorizontal = !!horizontal;
1890
+ const left = isHorizontal ? offset : 0;
1891
+ const top = isHorizontal ? 0 : offset;
1892
+ scroller.scrollTo({ animated: isAnimated, x: left, y: top });
1893
+ if (isAnimated) {
1894
+ const target = scroller.getScrollEventTarget();
1895
+ listenForScrollEnd(ctx, {
1896
+ readOffset: () => scroller.getCurrentScrollOffset(),
1897
+ target,
1898
+ targetOffset: offset
1899
+ });
1900
+ } else {
1901
+ state.scroll = offset;
1902
+ setTimeout(() => {
1903
+ finishScrollTo(ctx);
1904
+ }, 100);
1905
+ }
1906
+ }
1907
+ function listenForScrollEnd(ctx, params) {
1908
+ const { readOffset, target, targetOffset } = params;
1909
+ if (!target) {
1910
+ finishScrollTo(ctx);
1911
+ return;
1912
+ }
1913
+ const supportsScrollEnd = "onscrollend" in target;
1914
+ let idleTimeout;
1915
+ let settled = false;
1916
+ const targetToken = ctx.state.scrollingTo;
1917
+ const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1918
+ const cleanup = () => {
1919
+ target.removeEventListener("scroll", onScroll2);
1920
+ if (supportsScrollEnd) {
1921
+ target.removeEventListener("scrollend", onScrollEnd);
1922
+ }
1923
+ if (idleTimeout) {
1924
+ clearTimeout(idleTimeout);
1925
+ }
1926
+ clearTimeout(maxTimeout);
1927
+ };
1928
+ const finish = (reason) => {
1929
+ if (settled) return;
1930
+ if (targetToken !== ctx.state.scrollingTo) {
1931
+ settled = true;
1932
+ cleanup();
1933
+ return;
1934
+ }
1935
+ const currentOffset = readOffset();
1936
+ const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
1937
+ if (reason === "scrollend" && !isNearTarget) {
1938
+ return;
1939
+ }
1940
+ settled = true;
1941
+ cleanup();
1942
+ finishScrollTo(ctx);
1943
+ };
1944
+ const onScroll2 = () => {
1945
+ if (idleTimeout) {
1946
+ clearTimeout(idleTimeout);
1947
+ }
1948
+ idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
1949
+ };
1950
+ const onScrollEnd = () => finish("scrollend");
1951
+ target.addEventListener("scroll", onScroll2);
1952
+ if (supportsScrollEnd) {
1953
+ target.addEventListener("scrollend", onScrollEnd);
1954
+ } else {
1955
+ idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1956
+ }
1957
+ }
1958
+
1959
+ // src/core/scrollTo.ts
1960
+ function syncInitialScrollNativeWatchdog(state, options) {
1961
+ var _a3;
1962
+ const { isInitialScroll, requestedOffset, targetOffset } = options;
1963
+ const existingWatchdog = initialScrollWatchdog.get(state);
1964
+ const shouldWatchInitialNativeScroll = !state.didFinishInitialScroll && (isInitialScroll || !!existingWatchdog) && initialScrollWatchdog.hasNonZeroTargetOffset(targetOffset);
1965
+ const shouldClearInitialNativeScrollWatchdog = !state.didFinishInitialScroll && !!existingWatchdog && initialScrollWatchdog.isAtZeroTargetOffset(requestedOffset);
1966
+ if (shouldWatchInitialNativeScroll) {
1967
+ state.hasScrolled = false;
1968
+ initialScrollWatchdog.set(state, {
1969
+ startScroll: (_a3 = existingWatchdog == null ? void 0 : existingWatchdog.startScroll) != null ? _a3 : state.scroll,
1970
+ targetOffset
1971
+ });
1972
+ return;
1973
+ }
1974
+ if (shouldClearInitialNativeScrollWatchdog) {
1975
+ initialScrollWatchdog.clear(state);
1976
+ }
1977
+ }
1978
+ function scrollTo(ctx, params) {
1979
+ var _a3;
1980
+ const state = ctx.state;
1981
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1982
+ const {
1983
+ animated,
1984
+ isInitialScroll,
1985
+ offset: scrollTargetOffset,
1986
+ precomputedWithViewOffset,
1987
+ waitForInitialScrollCompletionFrame
1988
+ } = scrollTarget;
1989
+ const {
1990
+ props: { horizontal }
1991
+ } = state;
1992
+ if (state.animFrameCheckFinishedScroll) {
1993
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1994
+ }
1995
+ if (state.timeoutCheckFinishedScrollFallback) {
1996
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1997
+ }
1998
+ const requestedOffset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1999
+ const shouldPreserveRawInitialOffsetRequest = !!isInitialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2000
+ const targetOffset = clampScrollOffset(ctx, requestedOffset, scrollTarget);
2001
+ const offset = shouldPreserveRawInitialOffsetRequest ? requestedOffset : targetOffset;
2002
+ state.scrollHistory.length = 0;
2003
+ if (!noScrollingTo) {
2004
+ if (isInitialScroll) {
2005
+ initialScrollCompletion.resetFlags(state);
2006
+ }
2007
+ state.scrollingTo = {
2008
+ ...scrollTarget,
2009
+ targetOffset,
2010
+ waitForInitialScrollCompletionFrame
2011
+ };
2012
+ }
2013
+ state.scrollPending = targetOffset;
2014
+ syncInitialScrollNativeWatchdog(state, { isInitialScroll, requestedOffset: offset, targetOffset });
2015
+ if (forceScroll || !isInitialScroll || Platform.OS === "android") {
2016
+ doScrollTo(ctx, { animated, horizontal, offset });
2017
+ } else {
2018
+ state.scroll = offset;
2019
+ }
2020
+ }
2021
+
2022
+ // src/core/scrollToIndex.ts
2023
+ function clampScrollIndex(index, dataLength) {
2024
+ if (dataLength <= 0) {
2025
+ return -1;
2026
+ }
2027
+ if (index >= dataLength) {
2028
+ return dataLength - 1;
2029
+ }
2030
+ if (index < 0) {
2031
+ return 0;
2032
+ }
2033
+ return index;
2034
+ }
2035
+ function scrollToIndex(ctx, {
2036
+ index,
2037
+ viewOffset = 0,
2038
+ animated = true,
2039
+ forceScroll,
2040
+ isInitialScroll,
2041
+ viewPosition
2042
+ }) {
2043
+ const state = ctx.state;
2044
+ const { data } = state.props;
2045
+ index = clampScrollIndex(index, data.length);
2046
+ const itemSize = getItemSizeAtIndex(ctx, index);
2047
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2048
+ const isLast = index === data.length - 1;
2049
+ if (isLast && viewPosition === void 0) {
2050
+ viewPosition = 1;
2051
+ }
2052
+ state.scrollForNextCalculateItemsInView = void 0;
2053
+ scrollTo(ctx, {
2054
+ animated,
2055
+ forceScroll,
2056
+ index,
2057
+ isInitialScroll,
2058
+ itemSize,
2059
+ offset: firstIndexOffset,
2060
+ viewOffset,
2061
+ viewPosition: viewPosition != null ? viewPosition : 0
2062
+ });
2063
+ }
2064
+
1694
2065
  // src/utils/checkThreshold.ts
1695
2066
  var HYSTERESIS_MULTIPLIER = 1.3;
1696
2067
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot, allowReentryOnChange) => {
@@ -1859,202 +2230,867 @@ function setInitialRenderState(ctx, {
1859
2230
  }
1860
2231
  }
1861
2232
 
1862
- // src/core/finishScrollTo.ts
1863
- function finishScrollTo(ctx) {
1864
- var _a3, _b;
2233
+ // src/core/initialScroll.ts
2234
+ function syncInitialScrollOffset(state, offset) {
2235
+ state.scroll = offset;
2236
+ state.scrollPending = offset;
2237
+ state.scrollPrev = offset;
2238
+ }
2239
+ function dispatchInitialScroll(ctx, params) {
2240
+ const { forceScroll, resolvedOffset, target, waitForCompletionFrame } = params;
2241
+ const requestedIndex = target.index;
2242
+ const index = requestedIndex !== void 0 ? clampScrollIndex(requestedIndex, ctx.state.props.data.length) : void 0;
2243
+ const itemSize = getItemSizeAtIndex(ctx, index);
2244
+ scrollTo(ctx, {
2245
+ animated: false,
2246
+ forceScroll,
2247
+ index: index !== void 0 && index >= 0 ? index : void 0,
2248
+ isInitialScroll: true,
2249
+ itemSize,
2250
+ offset: resolvedOffset,
2251
+ precomputedWithViewOffset: true,
2252
+ viewOffset: target.viewOffset,
2253
+ viewPosition: target.viewPosition,
2254
+ waitForInitialScrollCompletionFrame: waitForCompletionFrame
2255
+ });
2256
+ }
2257
+ function setInitialScrollTarget(state, target, options) {
2258
+ var _a3;
2259
+ state.initialScroll = target;
2260
+ if ((options == null ? void 0 : options.resetDidFinish) && state.didFinishInitialScroll) {
2261
+ state.didFinishInitialScroll = false;
2262
+ }
2263
+ setInitialScrollSession(state, {
2264
+ kind: ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset" ? "offset" : "bootstrap"
2265
+ });
2266
+ }
2267
+ function finishInitialScroll(ctx, options) {
2268
+ var _a3, _b, _c;
1865
2269
  const state = ctx.state;
1866
- if (state == null ? void 0 : state.scrollingTo) {
1867
- const resolvePendingScroll = state.pendingScrollResolve;
1868
- state.pendingScrollResolve = void 0;
1869
- const scrollingTo = state.scrollingTo;
1870
- state.scrollHistory.length = 0;
1871
- state.initialScroll = void 0;
1872
- state.initialScrollUsesOffset = false;
1873
- state.initialAnchor = void 0;
1874
- state.initialNativeScrollWatchdog = void 0;
1875
- state.scrollingTo = void 0;
1876
- if (state.pendingTotalSize !== void 0) {
1877
- addTotalSize(ctx, null, state.pendingTotalSize);
1878
- }
1879
- if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1880
- (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1881
- }
1882
- {
1883
- state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
2270
+ if ((options == null ? void 0 : options.resolvedOffset) !== void 0) {
2271
+ syncInitialScrollOffset(state, options.resolvedOffset);
2272
+ } else if ((options == null ? void 0 : options.syncObservedOffset) && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset") {
2273
+ const observedOffset = (_c = (_b = state.refScroller.current) == null ? void 0 : _b.getCurrentScrollOffset) == null ? void 0 : _c.call(_b);
2274
+ if (typeof observedOffset === "number" && Number.isFinite(observedOffset)) {
2275
+ syncInitialScrollOffset(state, observedOffset);
2276
+ }
2277
+ }
2278
+ const complete = () => {
2279
+ var _a4, _b2, _c2, _d, _e, _f, _g;
2280
+ const shouldReleaseDeferredPublicOnScroll = ((_a4 = state.initialScrollSession) == null ? void 0 : _a4.kind) === "bootstrap";
2281
+ const finalScrollOffset = (_d = (_c2 = (_b2 = options == null ? void 0 : options.resolvedOffset) != null ? _b2 : state.scrollPending) != null ? _c2 : state.scroll) != null ? _d : 0;
2282
+ initialScrollWatchdog.clear(state);
2283
+ if (!(options == null ? void 0 : options.preserveTarget)) {
2284
+ state.initialScroll = void 0;
2285
+ }
2286
+ setInitialScrollSession(state);
2287
+ if ((options == null ? void 0 : options.recalculateItems) && ((_e = state.props) == null ? void 0 : _e.data)) {
2288
+ (_f = state.triggerCalculateItemsInView) == null ? void 0 : _f.call(state, { forceFullItemPositions: true });
2289
+ }
2290
+ if (options == null ? void 0 : options.recalculateItems) {
2291
+ checkThresholds(ctx);
1884
2292
  }
1885
2293
  setInitialRenderState(ctx, { didInitialScroll: true });
1886
- checkThresholds(ctx);
1887
- resolvePendingScroll == null ? void 0 : resolvePendingScroll();
2294
+ if (shouldReleaseDeferredPublicOnScroll) {
2295
+ releaseDeferredPublicOnScroll(ctx, finalScrollOffset);
2296
+ }
2297
+ (_g = options == null ? void 0 : options.onFinished) == null ? void 0 : _g.call(options);
2298
+ };
2299
+ if (options == null ? void 0 : options.waitForCompletionFrame) {
2300
+ requestAnimationFrame(complete);
2301
+ return;
1888
2302
  }
2303
+ complete();
1889
2304
  }
1890
-
1891
- // src/core/doScrollTo.ts
1892
- var SCROLL_END_IDLE_MS = 80;
1893
- var SCROLL_END_MAX_MS = 1500;
1894
- var SMOOTH_SCROLL_DURATION_MS = 320;
1895
- var SCROLL_END_TARGET_EPSILON = 1;
1896
- function doScrollTo(ctx, params) {
2305
+ function resolveInitialScrollOffset(ctx, initialScroll) {
2306
+ var _a3, _b;
1897
2307
  const state = ctx.state;
1898
- const { animated, horizontal, offset } = params;
1899
- const scroller = state.refScroller.current;
1900
- const node = scroller == null ? void 0 : scroller.getScrollableNode();
1901
- if (!scroller || !node) {
2308
+ if (((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset") {
2309
+ return (_b = initialScroll.contentOffset) != null ? _b : 0;
2310
+ }
2311
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
2312
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
2313
+ return clampScrollOffset(ctx, resolvedOffset, initialScroll);
2314
+ }
2315
+ function getAdvanceableInitialScrollState(state, options) {
2316
+ const { didFinishInitialScroll, queuedInitialLayout, scrollingTo } = state;
2317
+ const initialScroll = state.initialScroll;
2318
+ const isInitialScrollInProgress = !!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll);
2319
+ const shouldWaitForInitialLayout = !!(options == null ? void 0 : options.requiresMeasuredLayout) && !queuedInitialLayout && !isInitialScrollInProgress;
2320
+ if (!initialScroll || shouldWaitForInitialLayout || didFinishInitialScroll || scrollingTo && !isInitialScrollInProgress) {
2321
+ return void 0;
2322
+ }
2323
+ return {
2324
+ initialScroll,
2325
+ isInitialScrollInProgress,
2326
+ queuedInitialLayout,
2327
+ scrollingTo
2328
+ };
2329
+ }
2330
+ function advanceMeasuredInitialScroll(ctx, options) {
2331
+ var _a3, _b, _c;
2332
+ const state = ctx.state;
2333
+ const advanceableState = getAdvanceableInitialScrollState(state, {
2334
+ requiresMeasuredLayout: true
2335
+ });
2336
+ if (!advanceableState) {
2337
+ return false;
2338
+ }
2339
+ const { initialScroll, isInitialScrollInProgress, queuedInitialLayout } = advanceableState;
2340
+ const scrollingTo = isInitialScrollInProgress ? advanceableState.scrollingTo : void 0;
2341
+ const resolvedOffset = resolveInitialScrollOffset(ctx, initialScroll);
2342
+ const activeInitialTargetOffset = scrollingTo ? (_a3 = scrollingTo.targetOffset) != null ? _a3 : scrollingTo.offset : void 0;
2343
+ const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - resolvedOffset) > 1;
2344
+ const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - resolvedOffset) > 1;
2345
+ const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - activeInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - activeInitialTargetOffset) <= 1;
2346
+ if (!(options == null ? void 0 : options.forceScroll) && !didOffsetChange && isInitialScrollInProgress && !didActiveInitialTargetChange) {
2347
+ return false;
2348
+ }
2349
+ if ((options == null ? void 0 : options.forceScroll) && isAlreadyAtDesiredInitialTarget) {
2350
+ return false;
2351
+ }
2352
+ if (didOffsetChange && ((_b = state.initialScrollSession) == null ? void 0 : _b.kind) !== "offset") {
2353
+ setInitialScrollTarget(state, { ...initialScroll, contentOffset: resolvedOffset });
2354
+ }
2355
+ const forceScroll = (_c = options == null ? void 0 : options.forceScroll) != null ? _c : !!queuedInitialLayout || isInitialScrollInProgress && didOffsetChange;
2356
+ dispatchInitialScroll(ctx, {
2357
+ forceScroll,
2358
+ resolvedOffset,
2359
+ target: initialScroll
2360
+ });
2361
+ return true;
2362
+ }
2363
+ function advanceOffsetInitialScroll(ctx, options) {
2364
+ var _a3, _b;
2365
+ const state = ctx.state;
2366
+ const advanceableState = getAdvanceableInitialScrollState(state);
2367
+ if (!advanceableState) {
2368
+ return false;
2369
+ }
2370
+ const { initialScroll, queuedInitialLayout } = advanceableState;
2371
+ const resolvedOffset = (_a3 = initialScroll.contentOffset) != null ? _a3 : 0;
2372
+ const isAlreadyAtDesiredInitialTarget = Math.abs(state.scroll - resolvedOffset) <= 1 && Math.abs(state.scrollPending - resolvedOffset) <= 1;
2373
+ if ((options == null ? void 0 : options.forceScroll) && isAlreadyAtDesiredInitialTarget) {
2374
+ return false;
2375
+ }
2376
+ const hasMeasuredScrollLayout = !!state.lastLayout && state.scrollLength > 0;
2377
+ const forceScroll = (_b = options == null ? void 0 : options.forceScroll) != null ? _b : hasMeasuredScrollLayout || !!queuedInitialLayout;
2378
+ dispatchInitialScroll(ctx, {
2379
+ forceScroll,
2380
+ resolvedOffset,
2381
+ target: initialScroll
2382
+ });
2383
+ return true;
2384
+ }
2385
+ function advanceCurrentInitialScrollSession(ctx, options) {
2386
+ var _a3;
2387
+ return ((_a3 = ctx.state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset" ? advanceOffsetInitialScroll(ctx, {
2388
+ forceScroll: options == null ? void 0 : options.forceScroll
2389
+ }) : advanceMeasuredInitialScroll(ctx, {
2390
+ forceScroll: options == null ? void 0 : options.forceScroll
2391
+ });
2392
+ }
2393
+
2394
+ // src/utils/checkAllSizesKnown.ts
2395
+ function isNullOrUndefined2(value) {
2396
+ return value === null || value === void 0;
2397
+ }
2398
+ function getMountedBufferedIndices(state) {
2399
+ const { startBuffered, endBuffered } = state;
2400
+ if (!isNullOrUndefined2(endBuffered) && !isNullOrUndefined2(startBuffered) && startBuffered >= 0 && endBuffered >= 0) {
2401
+ return Array.from(state.containerItemKeys.keys()).map((key) => state.indexByKey.get(key)).filter((index) => index !== void 0 && index >= startBuffered && index <= endBuffered).sort((a, b) => a - b);
2402
+ }
2403
+ return [];
2404
+ }
2405
+ function checkAllSizesKnown(state, indices = getMountedBufferedIndices(state)) {
2406
+ return indices.length > 0 && indices.every((index) => {
2407
+ const key = getId(state, index);
2408
+ return state.sizesKnown.has(key);
2409
+ });
2410
+ }
2411
+
2412
+ // src/core/bootstrapInitialScroll.ts
2413
+ var DEFAULT_BOOTSTRAP_REVEAL_EPSILON = 1;
2414
+ var DEFAULT_BOOTSTRAP_REVEAL_MAX_FRAMES = 8;
2415
+ var DEFAULT_BOOTSTRAP_REVEAL_MAX_PASSES = 24;
2416
+ var BOOTSTRAP_REVEAL_ABORT_WARNING = "LegendList bootstrap initial scroll aborted after exceeding convergence bounds.";
2417
+ function getBootstrapInitialScrollSession(state) {
2418
+ var _a3;
2419
+ return ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
2420
+ }
2421
+ function isOffsetInitialScrollSession(state) {
2422
+ var _a3;
2423
+ return ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2424
+ }
2425
+ function doVisibleIndicesMatch(previous, next) {
2426
+ if (!previous || previous.length !== next.length) {
2427
+ return false;
2428
+ }
2429
+ for (let i = 0; i < previous.length; i++) {
2430
+ if (previous[i] !== next[i]) {
2431
+ return false;
2432
+ }
2433
+ }
2434
+ return true;
2435
+ }
2436
+ function getBootstrapRevealVisibleIndices(options) {
2437
+ const { dataLength, getSize, offset, positions, scrollLength, startIndex: requestedStartIndex } = options;
2438
+ const endOffset = offset + scrollLength;
2439
+ const visibleIndices = [];
2440
+ let index = requestedStartIndex !== void 0 ? Math.max(0, Math.min(dataLength - 1, requestedStartIndex)) : 0;
2441
+ while (index > 0) {
2442
+ const previousIndex = index - 1;
2443
+ const previousPosition = positions[previousIndex];
2444
+ if (previousPosition === void 0) {
2445
+ index = previousIndex;
2446
+ continue;
2447
+ }
2448
+ const previousSize = getSize(previousIndex);
2449
+ if (previousSize === void 0) {
2450
+ index = previousIndex;
2451
+ continue;
2452
+ }
2453
+ if (previousPosition + previousSize <= offset) {
2454
+ break;
2455
+ }
2456
+ index = previousIndex;
2457
+ }
2458
+ for (; index < dataLength; index++) {
2459
+ const position = positions[index];
2460
+ if (position === void 0) {
2461
+ continue;
2462
+ }
2463
+ const size = getSize(index);
2464
+ if (size === void 0) {
2465
+ continue;
2466
+ }
2467
+ if (position < endOffset && position + size > offset) {
2468
+ visibleIndices.push(index);
2469
+ } else if (visibleIndices.length > 0 && position >= endOffset) {
2470
+ break;
2471
+ }
2472
+ }
2473
+ return visibleIndices;
2474
+ }
2475
+ function shouldAbortBootstrapReveal(options) {
2476
+ const {
2477
+ mountFrameCount,
2478
+ maxFrames = DEFAULT_BOOTSTRAP_REVEAL_MAX_FRAMES,
2479
+ maxPasses = DEFAULT_BOOTSTRAP_REVEAL_MAX_PASSES,
2480
+ passCount
2481
+ } = options;
2482
+ return mountFrameCount >= maxFrames || passCount >= maxPasses;
2483
+ }
2484
+ function abortBootstrapRevealIfNeeded(ctx, options) {
2485
+ if (!shouldAbortBootstrapReveal(options)) {
2486
+ return false;
2487
+ }
2488
+ if (IS_DEV) {
2489
+ console.warn(BOOTSTRAP_REVEAL_ABORT_WARNING);
2490
+ }
2491
+ abortBootstrapInitialScroll(ctx);
2492
+ return true;
2493
+ }
2494
+ function clearBootstrapInitialScrollSession(state) {
2495
+ var _a3;
2496
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2497
+ const frameHandle = bootstrapInitialScroll == null ? void 0 : bootstrapInitialScroll.frameHandle;
2498
+ if (frameHandle !== void 0 && typeof cancelAnimationFrame === "function") {
2499
+ cancelAnimationFrame(frameHandle);
2500
+ }
2501
+ if (bootstrapInitialScroll) {
2502
+ bootstrapInitialScroll.frameHandle = void 0;
2503
+ }
2504
+ setInitialScrollSession(state, {
2505
+ bootstrap: void 0,
2506
+ kind: (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind
2507
+ });
2508
+ }
2509
+ function startBootstrapInitialScrollSession(state, options) {
2510
+ var _a3, _b, _c;
2511
+ const previousBootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2512
+ setInitialScrollSession(state, {
2513
+ bootstrap: {
2514
+ frameHandle: previousBootstrapInitialScroll == null ? void 0 : previousBootstrapInitialScroll.frameHandle,
2515
+ // Re-arming during the initial mount should spend from the same watchdog budget.
2516
+ mountFrameCount: (_a3 = previousBootstrapInitialScroll == null ? void 0 : previousBootstrapInitialScroll.mountFrameCount) != null ? _a3 : 0,
2517
+ passCount: 0,
2518
+ previousResolvedOffset: void 0,
2519
+ scroll: options.scroll,
2520
+ seedContentOffset: (_c = (_b = options.seedContentOffset) != null ? _b : previousBootstrapInitialScroll == null ? void 0 : previousBootstrapInitialScroll.seedContentOffset) != null ? _c : options.scroll,
2521
+ targetIndexSeed: options.targetIndexSeed,
2522
+ visibleIndices: void 0
2523
+ },
2524
+ kind: "bootstrap"
2525
+ });
2526
+ }
2527
+ function resetBootstrapInitialScrollSession(state, options) {
2528
+ var _a3, _b, _c;
2529
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2530
+ if (!bootstrapInitialScroll) {
2531
+ if ((options == null ? void 0 : options.scroll) !== void 0) {
2532
+ startBootstrapInitialScrollSession(state, {
2533
+ scroll: options.scroll,
2534
+ seedContentOffset: options.seedContentOffset,
2535
+ targetIndexSeed: options.targetIndexSeed
2536
+ });
2537
+ }
2538
+ } else {
2539
+ bootstrapInitialScroll.passCount = 0;
2540
+ bootstrapInitialScroll.previousResolvedOffset = void 0;
2541
+ bootstrapInitialScroll.scroll = (_a3 = options == null ? void 0 : options.scroll) != null ? _a3 : bootstrapInitialScroll.scroll;
2542
+ bootstrapInitialScroll.seedContentOffset = (_b = options == null ? void 0 : options.seedContentOffset) != null ? _b : bootstrapInitialScroll.seedContentOffset;
2543
+ bootstrapInitialScroll.targetIndexSeed = (_c = options == null ? void 0 : options.targetIndexSeed) != null ? _c : bootstrapInitialScroll.targetIndexSeed;
2544
+ bootstrapInitialScroll.visibleIndices = void 0;
2545
+ setInitialScrollSession(state, {
2546
+ bootstrap: bootstrapInitialScroll,
2547
+ kind: "bootstrap"
2548
+ });
2549
+ }
2550
+ }
2551
+ function queueBootstrapInitialScrollReevaluation(state) {
2552
+ requestAnimationFrame(() => {
2553
+ var _a3;
2554
+ if (getBootstrapInitialScrollSession(state)) {
2555
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { forceFullItemPositions: true });
2556
+ }
2557
+ });
2558
+ }
2559
+ function ensureBootstrapInitialScrollFrameTicker(ctx) {
2560
+ const state = ctx.state;
2561
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2562
+ if (!bootstrapInitialScroll || bootstrapInitialScroll.frameHandle !== void 0) {
1902
2563
  return;
1903
2564
  }
1904
- const isAnimated = !!animated;
1905
- const isHorizontal = !!horizontal;
1906
- const left = isHorizontal ? offset : 0;
1907
- const top = isHorizontal ? 0 : offset;
1908
- scroller.scrollTo({ animated: isAnimated, x: left, y: top });
1909
- if (isAnimated) {
1910
- const target = scroller.getScrollEventTarget();
1911
- listenForScrollEnd(ctx, {
1912
- readOffset: () => scroller.getCurrentScrollOffset(),
1913
- target,
1914
- targetOffset: offset
2565
+ const tick = () => {
2566
+ const activeBootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2567
+ if (!activeBootstrapInitialScroll) {
2568
+ return;
2569
+ }
2570
+ activeBootstrapInitialScroll.frameHandle = void 0;
2571
+ activeBootstrapInitialScroll.mountFrameCount += 1;
2572
+ if (abortBootstrapRevealIfNeeded(ctx, {
2573
+ mountFrameCount: activeBootstrapInitialScroll.mountFrameCount,
2574
+ passCount: activeBootstrapInitialScroll.passCount
2575
+ })) {
2576
+ return;
2577
+ }
2578
+ ensureBootstrapInitialScrollFrameTicker(ctx);
2579
+ };
2580
+ bootstrapInitialScroll.frameHandle = requestAnimationFrame(tick);
2581
+ }
2582
+ function rearmBootstrapInitialScroll(ctx, options) {
2583
+ resetBootstrapInitialScrollSession(ctx.state, options);
2584
+ ensureBootstrapInitialScrollFrameTicker(ctx);
2585
+ queueBootstrapInitialScrollReevaluation(ctx.state);
2586
+ }
2587
+ function createInitialScrollAtEndTarget(options) {
2588
+ const { dataLength, footerSize, preserveForFooterLayout, stylePaddingBottom } = options;
2589
+ return {
2590
+ contentOffset: void 0,
2591
+ index: Math.max(0, dataLength - 1),
2592
+ preserveForBottomPadding: true,
2593
+ preserveForFooterLayout,
2594
+ viewOffset: -stylePaddingBottom - footerSize,
2595
+ viewPosition: 1
2596
+ };
2597
+ }
2598
+ function shouldPreserveInitialScrollForBottomPadding(target) {
2599
+ return !!(target == null ? void 0 : target.preserveForBottomPadding);
2600
+ }
2601
+ function shouldPreserveInitialScrollForFooterLayout(target) {
2602
+ return !!(target == null ? void 0 : target.preserveForFooterLayout);
2603
+ }
2604
+ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2605
+ return !!(target && target.viewPosition === 1 && (shouldPreserveInitialScrollForBottomPadding(target) || shouldPreserveInitialScrollForFooterLayout(target)));
2606
+ }
2607
+ function createRetargetedBottomAlignedInitialScroll(options) {
2608
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom, target } = options;
2609
+ const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2610
+ return {
2611
+ ...target,
2612
+ contentOffset: void 0,
2613
+ index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2614
+ preserveForBottomPadding: true,
2615
+ preserveForFooterLayout,
2616
+ viewOffset: -stylePaddingBottom - (preserveForFooterLayout ? footerSize : 0),
2617
+ viewPosition: 1
2618
+ };
2619
+ }
2620
+ function areEquivalentBootstrapInitialScrollTargets(current, next) {
2621
+ return current.index === next.index && current.preserveForBottomPadding === next.preserveForBottomPadding && current.preserveForFooterLayout === next.preserveForFooterLayout && current.viewOffset === next.viewOffset && current.viewPosition === next.viewPosition;
2622
+ }
2623
+ function clearPendingInitialScrollFooterLayout(state, target) {
2624
+ if (!shouldPreserveInitialScrollForFooterLayout(target)) {
2625
+ return;
2626
+ }
2627
+ if (state.didFinishInitialScroll && !getBootstrapInitialScrollSession(state)) {
2628
+ state.initialScroll = void 0;
2629
+ setInitialScrollSession(state);
2630
+ return;
2631
+ }
2632
+ setInitialScrollTarget(state, { ...target, preserveForFooterLayout: void 0 });
2633
+ }
2634
+ function didFinishedInitialScrollMoveAwayFromTarget(ctx, target, epsilon = DEFAULT_BOOTSTRAP_REVEAL_EPSILON) {
2635
+ const state = ctx.state;
2636
+ if (!state.didFinishInitialScroll) {
2637
+ return false;
2638
+ }
2639
+ const currentOffset = getObservedBootstrapInitialScrollOffset(state);
2640
+ return Math.abs(currentOffset - resolveInitialScrollOffset(ctx, target)) > epsilon;
2641
+ }
2642
+ function getObservedBootstrapInitialScrollOffset(state) {
2643
+ var _a3, _b, _c, _d;
2644
+ const observedOffset = (_b = (_a3 = state.refScroller.current) == null ? void 0 : _a3.getCurrentScrollOffset) == null ? void 0 : _b.call(_a3);
2645
+ return typeof observedOffset === "number" && Number.isFinite(observedOffset) ? observedOffset : (_d = (_c = state.scrollPending) != null ? _c : state.scroll) != null ? _d : 0;
2646
+ }
2647
+ function startBootstrapInitialScrollOnMount(ctx, options) {
2648
+ var _a3, _b, _c;
2649
+ const { initialScrollAtEnd, target } = options;
2650
+ const state = ctx.state;
2651
+ const offset = resolveInitialScrollOffset(ctx, target);
2652
+ const shouldFinishAtOrigin = offset === 0 && !initialScrollAtEnd && (isOffsetInitialScrollSession(state) ? Math.abs((_a3 = target.contentOffset) != null ? _a3 : 0) <= 1 : target.index === 0 && ((_b = target.viewPosition) != null ? _b : 0) === 0 && Math.abs((_c = target.viewOffset) != null ? _c : 0) <= 1);
2653
+ const shouldFinishWithPreservedTarget = state.props.data.length === 0 && target.index !== void 0;
2654
+ if (shouldFinishAtOrigin) {
2655
+ clearBootstrapInitialScrollSession(state);
2656
+ finishInitialScroll(ctx, {
2657
+ resolvedOffset: offset
2658
+ });
2659
+ } else if (shouldFinishWithPreservedTarget) {
2660
+ clearBootstrapInitialScrollSession(state);
2661
+ finishInitialScroll(ctx, {
2662
+ preserveTarget: true,
2663
+ resolvedOffset: offset
1915
2664
  });
1916
2665
  } else {
1917
- state.scroll = offset;
1918
- setTimeout(() => {
1919
- finishScrollTo(ctx);
1920
- }, 100);
2666
+ startBootstrapInitialScrollSession(state, {
2667
+ scroll: offset,
2668
+ seedContentOffset: 0 ,
2669
+ targetIndexSeed: target.index
2670
+ });
2671
+ ensureBootstrapInitialScrollFrameTicker(ctx);
1921
2672
  }
1922
2673
  }
1923
- function listenForScrollEnd(ctx, params) {
1924
- const { readOffset, target, targetOffset } = params;
1925
- if (!target) {
1926
- finishScrollTo(ctx);
2674
+ function handleBootstrapInitialScrollDataChange(ctx, options) {
2675
+ const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingBottom } = options;
2676
+ const state = ctx.state;
2677
+ const initialScroll = state.initialScroll;
2678
+ if (isOffsetInitialScrollSession(state) || !initialScroll) {
1927
2679
  return;
1928
2680
  }
1929
- const supportsScrollEnd = "onscrollend" in target;
1930
- let idleTimeout;
1931
- let settled = false;
1932
- const targetToken = ctx.state.scrollingTo;
1933
- const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1934
- const cleanup = () => {
1935
- target.removeEventListener("scroll", onScroll2);
1936
- if (supportsScrollEnd) {
1937
- target.removeEventListener("scrollend", onScrollEnd);
2681
+ const shouldResetDidFinish = !!(state.didFinishInitialScroll && previousDataLength === 0 && dataLength > 0 && initialScroll.index !== void 0);
2682
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2683
+ const shouldRetargetBottomAligned = dataLength > 0 && (initialScrollAtEnd || isRetargetableBottomAlignedInitialScrollTarget(initialScroll));
2684
+ if (!didDataChange && !shouldResetDidFinish && !shouldRetargetBottomAligned) {
2685
+ return;
2686
+ }
2687
+ if (shouldRetargetBottomAligned) {
2688
+ if (!shouldResetDidFinish && didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2689
+ clearPendingInitialScrollFooterLayout(state, initialScroll);
2690
+ return;
1938
2691
  }
1939
- if (idleTimeout) {
1940
- clearTimeout(idleTimeout);
2692
+ const updatedInitialScroll = initialScrollAtEnd ? createInitialScrollAtEndTarget({
2693
+ dataLength,
2694
+ footerSize: peek$(ctx, "footerSize") || 0,
2695
+ preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2696
+ stylePaddingBottom
2697
+ }) : createRetargetedBottomAlignedInitialScroll({
2698
+ dataLength,
2699
+ footerSize: peek$(ctx, "footerSize") || 0,
2700
+ initialScrollAtEnd,
2701
+ stylePaddingBottom,
2702
+ target: initialScroll
2703
+ });
2704
+ if (!areEquivalentBootstrapInitialScrollTargets(initialScroll, updatedInitialScroll) || !!bootstrapInitialScroll || shouldResetDidFinish || didDataChange) {
2705
+ setInitialScrollTarget(state, updatedInitialScroll, {
2706
+ resetDidFinish: shouldResetDidFinish
2707
+ });
2708
+ rearmBootstrapInitialScroll(ctx, {
2709
+ scroll: resolveInitialScrollOffset(ctx, updatedInitialScroll),
2710
+ seedContentOffset: shouldResetDidFinish && !bootstrapInitialScroll ? getObservedBootstrapInitialScrollOffset(state) : void 0,
2711
+ targetIndexSeed: updatedInitialScroll.index
2712
+ });
2713
+ return;
1941
2714
  }
1942
- clearTimeout(maxTimeout);
1943
- };
1944
- const finish = (reason) => {
1945
- if (settled) return;
1946
- if (targetToken !== ctx.state.scrollingTo) {
1947
- settled = true;
1948
- cleanup();
2715
+ }
2716
+ if (!didDataChange) {
2717
+ return;
2718
+ }
2719
+ if (bootstrapInitialScroll || shouldResetDidFinish) {
2720
+ setInitialScrollTarget(state, initialScroll, {
2721
+ resetDidFinish: shouldResetDidFinish
2722
+ });
2723
+ rearmBootstrapInitialScroll(ctx, {
2724
+ scroll: resolveInitialScrollOffset(ctx, initialScroll),
2725
+ seedContentOffset: shouldResetDidFinish && !bootstrapInitialScroll ? getObservedBootstrapInitialScrollOffset(state) : void 0,
2726
+ targetIndexSeed: initialScroll.index
2727
+ });
2728
+ }
2729
+ }
2730
+ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2731
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom } = options;
2732
+ const state = ctx.state;
2733
+ if (!initialScrollAtEnd) {
2734
+ return;
2735
+ }
2736
+ const initialScroll = state.initialScroll;
2737
+ if (isOffsetInitialScrollSession(state) || dataLength === 0 || !initialScroll) {
2738
+ return;
2739
+ }
2740
+ const shouldProcessFooterLayout = !!getBootstrapInitialScrollSession(state) || shouldPreserveInitialScrollForFooterLayout(initialScroll);
2741
+ if (!shouldProcessFooterLayout) {
2742
+ return;
2743
+ }
2744
+ if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2745
+ clearPendingInitialScrollFooterLayout(state, initialScroll);
2746
+ } else {
2747
+ const updatedInitialScroll = createInitialScrollAtEndTarget({
2748
+ dataLength,
2749
+ footerSize,
2750
+ preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2751
+ stylePaddingBottom
2752
+ });
2753
+ const didTargetChange = initialScroll.index !== updatedInitialScroll.index || initialScroll.viewPosition !== updatedInitialScroll.viewPosition || initialScroll.viewOffset !== updatedInitialScroll.viewOffset;
2754
+ if (!didTargetChange) {
2755
+ clearPendingInitialScrollFooterLayout(state, initialScroll);
2756
+ } else {
2757
+ setInitialScrollTarget(state, updatedInitialScroll, {
2758
+ resetDidFinish: !!state.didFinishInitialScroll
2759
+ });
2760
+ rearmBootstrapInitialScroll(ctx, {
2761
+ scroll: resolveInitialScrollOffset(ctx, updatedInitialScroll),
2762
+ targetIndexSeed: updatedInitialScroll.index
2763
+ });
2764
+ }
2765
+ }
2766
+ }
2767
+ function evaluateBootstrapInitialScroll(ctx) {
2768
+ var _a3, _b;
2769
+ const state = ctx.state;
2770
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2771
+ const initialScroll = state.initialScroll;
2772
+ if (!bootstrapInitialScroll || !initialScroll || isOffsetInitialScrollSession(state) || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll)) {
2773
+ return;
2774
+ }
2775
+ bootstrapInitialScroll.passCount += 1;
2776
+ if (abortBootstrapRevealIfNeeded(ctx, {
2777
+ mountFrameCount: bootstrapInitialScroll.mountFrameCount,
2778
+ passCount: bootstrapInitialScroll.passCount
2779
+ })) {
2780
+ return;
2781
+ }
2782
+ if (initialScroll.index !== void 0 && state.startBuffered >= 0 && state.endBuffered >= 0 && initialScroll.index >= state.startBuffered && initialScroll.index <= state.endBuffered) {
2783
+ bootstrapInitialScroll.targetIndexSeed = void 0;
2784
+ }
2785
+ const resolvedOffset = resolveInitialScrollOffset(ctx, initialScroll);
2786
+ const mountedBufferedIndices = getMountedBufferedIndices(state);
2787
+ const areMountedBufferedIndicesMeasured = checkAllSizesKnown(state, mountedBufferedIndices);
2788
+ const didResolvedOffsetChange = Math.abs(bootstrapInitialScroll.scroll - resolvedOffset) > 1;
2789
+ const { data } = state.props;
2790
+ const visibleIndices = getBootstrapRevealVisibleIndices({
2791
+ dataLength: data.length,
2792
+ getSize: (index) => {
2793
+ var _a4, _b2;
2794
+ const id = (_a4 = state.idCache[index]) != null ? _a4 : getId(state, index);
2795
+ return (_b2 = state.sizes.get(id)) != null ? _b2 : getItemSize(ctx, id, index, data[index]);
2796
+ },
2797
+ offset: resolvedOffset,
2798
+ positions: state.positions,
2799
+ scrollLength: state.scrollLength,
2800
+ startIndex: (_b = bootstrapInitialScroll.targetIndexSeed) != null ? _b : state.startBuffered >= 0 ? state.startBuffered : void 0
2801
+ });
2802
+ const areVisibleIndicesMeasured = visibleIndices.length > 0 && visibleIndices.every((index) => {
2803
+ var _a4;
2804
+ const id = (_a4 = state.idCache[index]) != null ? _a4 : getId(state, index);
2805
+ return state.sizesKnown.has(id);
2806
+ });
2807
+ const previousResolvedOffset = bootstrapInitialScroll.previousResolvedOffset;
2808
+ const previousVisibleIndices = bootstrapInitialScroll.visibleIndices;
2809
+ bootstrapInitialScroll.previousResolvedOffset = resolvedOffset;
2810
+ bootstrapInitialScroll.visibleIndices = visibleIndices;
2811
+ if (didResolvedOffsetChange) {
2812
+ bootstrapInitialScroll.scroll = resolvedOffset;
2813
+ queueBootstrapInitialScrollReevaluation(state);
2814
+ return;
2815
+ }
2816
+ if (!areMountedBufferedIndicesMeasured || !areVisibleIndicesMeasured) {
2817
+ return;
2818
+ }
2819
+ const didRevealSettle = previousResolvedOffset !== void 0 && Math.abs(previousResolvedOffset - resolvedOffset) <= DEFAULT_BOOTSTRAP_REVEAL_EPSILON && doVisibleIndicesMatch(previousVisibleIndices, visibleIndices);
2820
+ if (!didRevealSettle) {
2821
+ queueBootstrapInitialScrollReevaluation(state);
2822
+ return;
2823
+ }
2824
+ {
2825
+ clearBootstrapInitialScrollSession(state);
2826
+ dispatchInitialScroll(ctx, {
2827
+ forceScroll: true,
2828
+ resolvedOffset,
2829
+ target: initialScroll,
2830
+ waitForCompletionFrame: Platform.OS === "web"
2831
+ });
2832
+ }
2833
+ }
2834
+ function finishBootstrapInitialScrollWithoutScroll(ctx, resolvedOffset) {
2835
+ const state = ctx.state;
2836
+ clearBootstrapInitialScrollSession(state);
2837
+ finishInitialScroll(ctx, {
2838
+ preserveTarget: shouldPreserveInitialScrollForFooterLayout(state.initialScroll),
2839
+ recalculateItems: true,
2840
+ resolvedOffset
2841
+ });
2842
+ }
2843
+ function abortBootstrapInitialScroll(ctx) {
2844
+ var _a3, _b, _c, _d;
2845
+ const state = ctx.state;
2846
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2847
+ const initialScroll = state.initialScroll;
2848
+ if (bootstrapInitialScroll && initialScroll && !isOffsetInitialScrollSession(state) && state.refScroller.current) {
2849
+ clearBootstrapInitialScrollSession(state);
2850
+ dispatchInitialScroll(ctx, {
2851
+ forceScroll: true,
2852
+ resolvedOffset: bootstrapInitialScroll.scroll,
2853
+ target: initialScroll,
2854
+ waitForCompletionFrame: Platform.OS === "web"
2855
+ });
2856
+ } else {
2857
+ finishBootstrapInitialScrollWithoutScroll(
2858
+ ctx,
2859
+ (_d = (_c = (_b = (_a3 = getBootstrapInitialScrollSession(state)) == null ? void 0 : _a3.scroll) != null ? _b : state.scrollPending) != null ? _c : state.scroll) != null ? _d : 0
2860
+ );
2861
+ }
2862
+ }
2863
+
2864
+ // src/core/checkFinishedScroll.ts
2865
+ var INITIAL_SCROLL_MAX_FALLBACK_CHECKS = 20;
2866
+ var INITIAL_SCROLL_COMPLETION_TARGET_EPSILON = 1;
2867
+ var INITIAL_SCROLL_ZERO_TARGET_EPSILON = 1;
2868
+ var SILENT_INITIAL_SCROLL_RETRY_DELAY_MS = 16;
2869
+ function checkFinishedScroll(ctx, options) {
2870
+ const scrollingTo = ctx.state.scrollingTo;
2871
+ if (options == null ? void 0 : options.onlyIfAligned) {
2872
+ if (!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || scrollingTo.animated) {
1949
2873
  return;
1950
2874
  }
1951
- const currentOffset = readOffset();
1952
- const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
1953
- if (reason === "scrollend" && !isNearTarget) {
2875
+ if (!getResolvedScrollCompletionState(ctx, scrollingTo).isAtResolvedTarget) {
1954
2876
  return;
1955
2877
  }
1956
- settled = true;
1957
- cleanup();
1958
- finishScrollTo(ctx);
2878
+ }
2879
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2880
+ }
2881
+ function hasScrollCompletionOwnership(state, options) {
2882
+ const { clampedTargetOffset, scrollingTo } = options;
2883
+ return !scrollingTo.isInitialScroll || state.hasScrolled || clampedTargetOffset <= INITIAL_SCROLL_COMPLETION_TARGET_EPSILON;
2884
+ }
2885
+ function isSilentInitialDispatch(state, scrollingTo) {
2886
+ return !!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && initialScrollCompletion.didDispatchNativeScroll(state) && !state.hasScrolled;
2887
+ }
2888
+ function getInitialScrollWatchdogTargetOffset(state) {
2889
+ var _a3;
2890
+ return (_a3 = initialScrollWatchdog.get(state)) == null ? void 0 : _a3.targetOffset;
2891
+ }
2892
+ function isNativeInitialNonZeroTarget(state) {
2893
+ const targetOffset = getInitialScrollWatchdogTargetOffset(state);
2894
+ return !state.didFinishInitialScroll && initialScrollWatchdog.hasNonZeroTargetOffset(targetOffset);
2895
+ }
2896
+ function shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) {
2897
+ var _a3, _b;
2898
+ if (!scrollingTo.isInitialScroll || scrollingTo.animated || !state.didContainersLayout) {
2899
+ return false;
2900
+ }
2901
+ if (((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap") {
2902
+ return false;
2903
+ }
2904
+ const targetOffset = (_b = scrollingTo.targetOffset) != null ? _b : scrollingTo.offset;
2905
+ if (initialScrollWatchdog.hasNonZeroTargetOffset(targetOffset) && initialScrollCompletion.didDispatchNativeScroll(state) && !state.hasScrolled) {
2906
+ return false;
2907
+ }
2908
+ if (initialScrollWatchdog.isAtZeroTargetOffset(targetOffset) || Math.abs(state.scroll - targetOffset) > 1 || Math.abs(state.scrollPending - targetOffset) > 1) {
2909
+ return false;
2910
+ }
2911
+ return !!scrollingTo.waitForInitialScrollCompletionFrame || isNativeInitialNonZeroTarget(state);
2912
+ }
2913
+ function shouldFinishInitialZeroTargetScroll(ctx) {
2914
+ var _a3;
2915
+ const { state } = ctx;
2916
+ return !!((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) && state.props.data.length > 0 && getContentSize(ctx) <= state.scrollLength && state.scrollPending <= INITIAL_SCROLL_ZERO_TARGET_EPSILON;
2917
+ }
2918
+ function getResolvedScrollCompletionState(ctx, scrollingTo) {
2919
+ var _a3;
2920
+ const { state } = ctx;
2921
+ const scroll = state.scrollPending;
2922
+ const adjust = state.scrollAdjustHandler.getAdjust();
2923
+ const clampedTargetOffset = (_a3 = scrollingTo.targetOffset) != null ? _a3 : clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0), scrollingTo);
2924
+ const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
2925
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
2926
+ const diff2 = Math.abs(diff1 - adjust);
2927
+ return {
2928
+ clampedTargetOffset,
2929
+ isAtResolvedTarget: Math.abs(scroll - maxOffset) < 1 && (diff1 < 1 || !scrollingTo.animated && diff2 < 1)
1959
2930
  };
1960
- const onScroll2 = () => {
1961
- if (idleTimeout) {
1962
- clearTimeout(idleTimeout);
2931
+ }
2932
+ function checkFinishedScrollFrame(ctx) {
2933
+ const scrollingTo = ctx.state.scrollingTo;
2934
+ if (!scrollingTo) {
2935
+ return;
2936
+ }
2937
+ const { state } = ctx;
2938
+ state.animFrameCheckFinishedScroll = void 0;
2939
+ const completionState = getResolvedScrollCompletionState(ctx, scrollingTo);
2940
+ if (completionState.isAtResolvedTarget && hasScrollCompletionOwnership(state, {
2941
+ clampedTargetOffset: completionState.clampedTargetOffset,
2942
+ scrollingTo
2943
+ })) {
2944
+ finishScrollTo(ctx);
2945
+ }
2946
+ }
2947
+ function scrollToFallbackOffset(ctx, offset) {
2948
+ var _a3;
2949
+ (_a3 = ctx.state.refScroller.current) == null ? void 0 : _a3.scrollTo({
2950
+ animated: false,
2951
+ x: ctx.state.props.horizontal ? offset : 0,
2952
+ y: ctx.state.props.horizontal ? 0 : offset
2953
+ });
2954
+ }
2955
+ function checkFinishedScrollFallback(ctx) {
2956
+ const state = ctx.state;
2957
+ const scrollingTo = state.scrollingTo;
2958
+ const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
2959
+ const silentInitialDispatch = isSilentInitialDispatch(state, scrollingTo);
2960
+ const canFinishInitialWithoutNativeProgress = scrollingTo !== void 0 ? shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) : false;
2961
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget && !canFinishInitialWithoutNativeProgress || !state.didContainersLayout;
2962
+ const initialDelay = shouldFinishInitialZeroTarget || canFinishInitialWithoutNativeProgress ? 0 : silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : slowTimeout ? 500 : 100;
2963
+ state.timeoutCheckFinishedScrollFallback = setTimeout(() => {
2964
+ let numChecks = 0;
2965
+ const scheduleFallbackCheck = (delay) => {
2966
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
2967
+ };
2968
+ const checkHasScrolled = () => {
2969
+ var _c;
2970
+ state.timeoutCheckFinishedScrollFallback = void 0;
2971
+ const isStillScrollingTo = state.scrollingTo;
2972
+ if (isStillScrollingTo) {
2973
+ numChecks++;
2974
+ const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
2975
+ const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
2976
+ const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
2977
+ const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
2978
+ state,
2979
+ isStillScrollingTo
2980
+ );
2981
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
2982
+ const canFinishAfterSilentNativeDispatch = silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
2983
+ if (shouldFinishZeroTarget || state.hasScrolled || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
2984
+ finishScrollTo(ctx);
2985
+ } else if (isNativeInitialPending && numChecks <= maxChecks) {
2986
+ const targetOffset = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : state.scrollPending;
2987
+ scrollToFallbackOffset(ctx, targetOffset);
2988
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2989
+ } else {
2990
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2991
+ }
2992
+ }
2993
+ };
2994
+ checkHasScrolled();
2995
+ }, initialDelay);
2996
+ }
2997
+
2998
+ // src/core/initialScrollLifecycle.ts
2999
+ function handleInitialScrollLayoutReady(ctx) {
3000
+ var _a3;
3001
+ if (!ctx.state.initialScroll) {
3002
+ return;
3003
+ }
3004
+ const runScroll = () => advanceCurrentInitialScrollSession(ctx, { forceScroll: true });
3005
+ runScroll();
3006
+ if (((_a3 = ctx.state.initialScrollSession) == null ? void 0 : _a3.kind) !== "offset") {
3007
+ requestAnimationFrame(runScroll);
3008
+ }
3009
+ checkFinishedScroll(ctx, { onlyIfAligned: true });
3010
+ }
3011
+ function initializeInitialScrollOnMount(ctx, options) {
3012
+ var _a3, _b;
3013
+ const { dataLength, hasFooterComponent, initialContentOffset, initialScrollAtEnd, useBootstrapInitialScroll } = options;
3014
+ const state = ctx.state;
3015
+ const initialScroll = state.initialScroll;
3016
+ const resolvedInitialContentOffset = initialContentOffset != null ? initialContentOffset : 0;
3017
+ const preserveForFooterLayout = useBootstrapInitialScroll && initialScrollAtEnd && hasFooterComponent;
3018
+ if (initialScroll && (initialScroll.contentOffset === void 0 || !!initialScroll.preserveForFooterLayout !== preserveForFooterLayout && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) !== "offset")) {
3019
+ setInitialScrollTarget(state, {
3020
+ ...initialScroll,
3021
+ contentOffset: resolvedInitialContentOffset,
3022
+ preserveForFooterLayout
3023
+ });
3024
+ }
3025
+ if (useBootstrapInitialScroll && initialScroll && ((_b = state.initialScrollSession) == null ? void 0 : _b.kind) !== "offset") {
3026
+ startBootstrapInitialScrollOnMount(ctx, {
3027
+ initialScrollAtEnd,
3028
+ target: state.initialScroll
3029
+ });
3030
+ return;
3031
+ }
3032
+ const hasPendingDataDependentInitialScroll = !!initialScroll && dataLength === 0 && !(resolvedInitialContentOffset === 0 && !initialScrollAtEnd);
3033
+ if (!resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
3034
+ if (initialScroll && !initialScrollAtEnd) {
3035
+ finishInitialScroll(ctx, {
3036
+ resolvedOffset: resolvedInitialContentOffset
3037
+ });
3038
+ } else {
3039
+ setInitialRenderState(ctx, { didInitialScroll: true });
1963
3040
  }
1964
- idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
1965
- };
1966
- const onScrollEnd = () => finish("scrollend");
1967
- target.addEventListener("scroll", onScroll2);
1968
- if (supportsScrollEnd) {
1969
- target.addEventListener("scrollend", onScrollEnd);
1970
- } else {
1971
- idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1972
3041
  }
1973
3042
  }
1974
-
1975
- // src/core/scrollTo.ts
1976
- var WATCHDOG_OFFSET_EPSILON = 1;
1977
- function scrollTo(ctx, params) {
1978
- var _a3, _b;
3043
+ function handleInitialScrollDataChange(ctx, options) {
3044
+ var _a3, _b, _c;
3045
+ const { dataLength, didDataChange, initialScrollAtEnd, stylePaddingBottom, useBootstrapInitialScroll } = options;
1979
3046
  const state = ctx.state;
1980
- const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1981
- const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1982
- const {
1983
- props: { horizontal }
1984
- } = state;
1985
- if (state.animFrameCheckFinishedScroll) {
1986
- cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1987
- }
1988
- if (state.timeoutCheckFinishedScrollFallback) {
1989
- clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
3047
+ const previousDataLength = (_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.previousDataLength) != null ? _b : 0;
3048
+ if (state.initialScrollSession) {
3049
+ state.initialScrollSession.previousDataLength = dataLength;
1990
3050
  }
1991
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1992
- offset = clampScrollOffset(ctx, offset, scrollTarget);
1993
- state.scrollHistory.length = 0;
1994
- if (!noScrollingTo) {
1995
- state.scrollingTo = {
1996
- ...scrollTarget,
1997
- targetOffset: offset
1998
- };
3051
+ setInitialScrollSession(state);
3052
+ if (useBootstrapInitialScroll) {
3053
+ handleBootstrapInitialScrollDataChange(ctx, {
3054
+ dataLength,
3055
+ didDataChange,
3056
+ initialScrollAtEnd,
3057
+ previousDataLength,
3058
+ stylePaddingBottom
3059
+ });
3060
+ return;
1999
3061
  }
2000
- state.scrollPending = offset;
2001
- const shouldWatchInitialNativeScroll = !state.didFinishInitialScroll && (isInitialScroll || !!state.initialNativeScrollWatchdog) && offset > WATCHDOG_OFFSET_EPSILON;
2002
- const shouldClearInitialNativeScrollWatchdog = !state.didFinishInitialScroll && !!state.initialNativeScrollWatchdog && offset <= WATCHDOG_OFFSET_EPSILON;
2003
- if (shouldWatchInitialNativeScroll) {
2004
- state.hasScrolled = false;
2005
- state.initialNativeScrollWatchdog = {
2006
- startScroll: (_b = (_a3 = state.initialNativeScrollWatchdog) == null ? void 0 : _a3.startScroll) != null ? _b : state.scroll,
2007
- targetOffset: offset
2008
- };
2009
- } else if (shouldClearInitialNativeScrollWatchdog) {
2010
- state.initialNativeScrollWatchdog = void 0;
3062
+ const shouldReplayFinishedOffsetInitialScroll = previousDataLength === 0 && dataLength > 0 && !!state.initialScroll && ((_c = ctx.state.initialScrollSession) == null ? void 0 : _c.kind) === "offset" && !!state.didFinishInitialScroll;
3063
+ if (previousDataLength !== 0 || dataLength === 0 || !state.initialScroll || !state.queuedInitialLayout || state.didFinishInitialScroll && !shouldReplayFinishedOffsetInitialScroll) {
3064
+ return;
2011
3065
  }
2012
- if (forceScroll || !isInitialScroll || Platform.OS === "android") {
2013
- doScrollTo(ctx, { animated, horizontal, offset });
2014
- } else {
2015
- state.scroll = offset;
3066
+ if (shouldReplayFinishedOffsetInitialScroll) {
3067
+ state.didFinishInitialScroll = false;
2016
3068
  }
3069
+ advanceCurrentInitialScrollSession(ctx);
2017
3070
  }
2018
3071
 
2019
- // src/core/doMaintainScrollAtEnd.ts
2020
- function doMaintainScrollAtEnd(ctx) {
3072
+ // src/utils/requestAdjust.ts
3073
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2021
3074
  const state = ctx.state;
2022
- const {
2023
- didContainersLayout,
2024
- isAtEnd,
2025
- pendingNativeMVCPAdjust,
2026
- refScroller,
2027
- props: { maintainScrollAtEnd }
2028
- } = state;
2029
- const shouldMaintainScrollAtEnd = !!(isAtEnd && maintainScrollAtEnd && didContainersLayout);
2030
- if (pendingNativeMVCPAdjust) {
2031
- state.pendingMaintainScrollAtEnd = shouldMaintainScrollAtEnd;
2032
- return false;
2033
- }
2034
- state.pendingMaintainScrollAtEnd = false;
2035
- if (shouldMaintainScrollAtEnd) {
2036
- const contentSize = getContentSize(ctx);
2037
- if (contentSize < state.scrollLength) {
2038
- state.scroll = 0;
2039
- }
2040
- requestAnimationFrame(() => {
2041
- var _a3;
2042
- if (state.isAtEnd) {
2043
- state.maintainingScrollAtEnd = true;
2044
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2045
- animated: maintainScrollAtEnd.animated
2046
- });
2047
- setTimeout(
2048
- () => {
2049
- state.maintainingScrollAtEnd = false;
2050
- },
2051
- maintainScrollAtEnd.animated ? 500 : 0
2052
- );
3075
+ if (Math.abs(positionDiff) > 0.1) {
3076
+ const doit = () => {
3077
+ {
3078
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
3079
+ if (state.adjustingFromInitialMount) {
3080
+ state.adjustingFromInitialMount--;
3081
+ }
2053
3082
  }
2054
- });
2055
- return true;
3083
+ };
3084
+ state.scroll += positionDiff;
3085
+ state.scrollForNextCalculateItemsInView = void 0;
3086
+ const readyToRender = peek$(ctx, "readyToRender");
3087
+ if (readyToRender) {
3088
+ doit();
3089
+ } else {
3090
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
3091
+ requestAnimationFrame(doit);
3092
+ }
2056
3093
  }
2057
- return false;
2058
3094
  }
2059
3095
 
2060
3096
  // src/core/mvcp.ts
@@ -2336,94 +3372,6 @@ function prepareMVCP(ctx, dataChanged) {
2336
3372
  }
2337
3373
  }
2338
3374
 
2339
- // src/core/updateScroll.ts
2340
- function updateScroll(ctx, newScroll, forceUpdate) {
2341
- var _a3;
2342
- const state = ctx.state;
2343
- const { ignoreScrollFromMVCP, lastScrollAdjustForHistory, scrollAdjustHandler, scrollHistory, scrollingTo } = state;
2344
- const prevScroll = state.scroll;
2345
- state.hasScrolled = true;
2346
- state.lastBatchingAction = Date.now();
2347
- const currentTime = Date.now();
2348
- const adjust = scrollAdjustHandler.getAdjust();
2349
- const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
2350
- if (adjustChanged) {
2351
- scrollHistory.length = 0;
2352
- }
2353
- state.lastScrollAdjustForHistory = adjust;
2354
- if (scrollingTo === void 0 && !(scrollHistory.length === 0 && newScroll === state.scroll)) {
2355
- if (!adjustChanged) {
2356
- scrollHistory.push({ scroll: newScroll, time: currentTime });
2357
- }
2358
- }
2359
- if (scrollHistory.length > 5) {
2360
- scrollHistory.shift();
2361
- }
2362
- if (ignoreScrollFromMVCP && !scrollingTo) {
2363
- const { lt, gt } = ignoreScrollFromMVCP;
2364
- if (lt && newScroll < lt || gt && newScroll > gt) {
2365
- state.ignoreScrollFromMVCPIgnored = true;
2366
- return;
2367
- }
2368
- }
2369
- state.scrollPrev = prevScroll;
2370
- state.scrollPrevTime = state.scrollTime;
2371
- state.scroll = newScroll;
2372
- state.scrollTime = currentTime;
2373
- const scrollDelta = Math.abs(newScroll - prevScroll);
2374
- const didResolvePendingNativeMVCPAdjust = resolvePendingNativeMVCPAdjust(ctx, newScroll);
2375
- const scrollLength = state.scrollLength;
2376
- const lastCalculated = state.scrollLastCalculate;
2377
- const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
2378
- const shouldUpdate = useAggressiveItemRecalculation || didResolvePendingNativeMVCPAdjust || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
2379
- if (shouldUpdate) {
2380
- state.scrollLastCalculate = state.scroll;
2381
- state.ignoreScrollFromMVCPIgnored = false;
2382
- state.lastScrollDelta = scrollDelta;
2383
- const runCalculateItems = () => {
2384
- var _a4;
2385
- (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0 });
2386
- checkThresholds(ctx);
2387
- };
2388
- if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
2389
- ReactDOM.flushSync(runCalculateItems);
2390
- } else {
2391
- runCalculateItems();
2392
- }
2393
- const shouldMaintainScrollAtEndAfterPendingSettle = !!state.pendingMaintainScrollAtEnd || !!((_a3 = state.props.maintainScrollAtEnd) == null ? void 0 : _a3.onDataChange);
2394
- if (didResolvePendingNativeMVCPAdjust && shouldMaintainScrollAtEndAfterPendingSettle) {
2395
- state.pendingMaintainScrollAtEnd = false;
2396
- doMaintainScrollAtEnd(ctx);
2397
- }
2398
- state.dataChangeNeedsScrollUpdate = false;
2399
- state.lastScrollDelta = 0;
2400
- }
2401
- }
2402
-
2403
- // src/utils/requestAdjust.ts
2404
- function requestAdjust(ctx, positionDiff, dataChanged) {
2405
- const state = ctx.state;
2406
- if (Math.abs(positionDiff) > 0.1) {
2407
- const doit = () => {
2408
- {
2409
- state.scrollAdjustHandler.requestAdjust(positionDiff);
2410
- if (state.adjustingFromInitialMount) {
2411
- state.adjustingFromInitialMount--;
2412
- }
2413
- }
2414
- };
2415
- state.scroll += positionDiff;
2416
- state.scrollForNextCalculateItemsInView = void 0;
2417
- const readyToRender = peek$(ctx, "readyToRender");
2418
- if (readyToRender) {
2419
- doit();
2420
- } else {
2421
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2422
- requestAnimationFrame(doit);
2423
- }
2424
- }
2425
- }
2426
-
2427
3375
  // src/core/prepareColumnStartState.ts
2428
3376
  function prepareColumnStartState(ctx, startIndex, useAverageSize) {
2429
3377
  var _a3;
@@ -2937,23 +3885,6 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
2937
3885
  var unstableBatchedUpdates = ReactDOM__namespace.unstable_batchedUpdates;
2938
3886
  var batchedUpdates = typeof unstableBatchedUpdates === "function" ? unstableBatchedUpdates : (fn) => fn();
2939
3887
 
2940
- // src/utils/checkAllSizesKnown.ts
2941
- function isNullOrUndefined2(value) {
2942
- return value === null || value === void 0;
2943
- }
2944
- function checkAllSizesKnown(state) {
2945
- const { startBuffered, endBuffered, sizesKnown } = state;
2946
- if (!isNullOrUndefined2(endBuffered) && !isNullOrUndefined2(startBuffered) && startBuffered >= 0 && endBuffered >= 0) {
2947
- let areAllKnown = true;
2948
- for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
2949
- const key = getId(state, i);
2950
- areAllKnown && (areAllKnown = sizesKnown.has(key));
2951
- }
2952
- return areAllKnown;
2953
- }
2954
- return false;
2955
- }
2956
-
2957
3888
  // src/utils/findAvailableContainers.ts
2958
3889
  function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2959
3890
  const numContainers = peek$(ctx, "numContainers");
@@ -3076,97 +4007,11 @@ function comparatorByDistance(a, b) {
3076
4007
  return b.distance - a.distance;
3077
4008
  }
3078
4009
 
3079
- // src/core/scrollToIndex.ts
3080
- function scrollToIndex(ctx, {
3081
- index,
3082
- viewOffset = 0,
3083
- animated = true,
3084
- forceScroll,
3085
- isInitialScroll,
3086
- viewPosition
3087
- }) {
3088
- const state = ctx.state;
3089
- const { data } = state.props;
3090
- if (index >= data.length) {
3091
- index = data.length - 1;
3092
- } else if (index < 0) {
3093
- index = 0;
3094
- }
3095
- const firstIndexOffset = calculateOffsetForIndex(ctx, index);
3096
- const isLast = index === data.length - 1;
3097
- if (isLast && viewPosition === void 0) {
3098
- viewPosition = 1;
3099
- }
3100
- state.scrollForNextCalculateItemsInView = void 0;
3101
- const targetId = getId(state, index);
3102
- const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
3103
- scrollTo(ctx, {
3104
- animated,
3105
- forceScroll,
3106
- index,
3107
- isInitialScroll,
3108
- itemSize,
3109
- offset: firstIndexOffset,
3110
- viewOffset,
3111
- viewPosition: viewPosition != null ? viewPosition : 0
3112
- });
3113
- }
3114
-
3115
- // src/utils/performInitialScroll.ts
3116
- function performInitialScroll(ctx, params) {
3117
- var _a3;
3118
- const { forceScroll, initialScrollUsesOffset, resolvedOffset, target } = params;
3119
- if (initialScrollUsesOffset || resolvedOffset !== void 0) {
3120
- scrollTo(ctx, {
3121
- animated: false,
3122
- forceScroll,
3123
- index: initialScrollUsesOffset ? void 0 : target.index,
3124
- isInitialScroll: true,
3125
- offset: (_a3 = resolvedOffset != null ? resolvedOffset : target.contentOffset) != null ? _a3 : 0,
3126
- precomputedWithViewOffset: resolvedOffset !== void 0
3127
- });
3128
- return;
3129
- }
3130
- if (target.index === void 0) {
3131
- return;
3132
- }
3133
- scrollToIndex(ctx, {
3134
- ...target,
3135
- animated: false,
3136
- forceScroll,
3137
- isInitialScroll: true
3138
- });
3139
- }
3140
-
3141
4010
  // src/utils/setDidLayout.ts
3142
4011
  function setDidLayout(ctx) {
3143
4012
  const state = ctx.state;
3144
- const { initialScroll } = state;
3145
4013
  state.queuedInitialLayout = true;
3146
4014
  checkAtBottom(ctx);
3147
- if (initialScroll) {
3148
- const runScroll = () => {
3149
- var _a3, _b;
3150
- const target = state.initialScroll;
3151
- if (!target) {
3152
- return;
3153
- }
3154
- const activeInitialTargetOffset = ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) ? (_b = state.scrollingTo.targetOffset) != null ? _b : state.scrollingTo.offset : void 0;
3155
- const desiredInitialTargetOffset = state.initialScrollUsesOffset ? target.contentOffset : activeInitialTargetOffset;
3156
- const isAlreadyAtDesiredInitialTarget = desiredInitialTargetOffset !== void 0 && Math.abs(state.scroll - desiredInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - desiredInitialTargetOffset) <= 1;
3157
- if (!isAlreadyAtDesiredInitialTarget) {
3158
- performInitialScroll(ctx, {
3159
- forceScroll: true,
3160
- initialScrollUsesOffset: state.initialScrollUsesOffset,
3161
- // Offset-based initial scrolls do not need item lookup, so they can run even before data exists.
3162
- // Re-run on the next frame to pick up measured viewport size without waiting for index resolution.
3163
- target
3164
- });
3165
- }
3166
- };
3167
- runScroll();
3168
- requestAnimationFrame(runScroll);
3169
- }
3170
4015
  setInitialRenderState(ctx, { didLayout: true });
3171
4016
  }
3172
4017
 
@@ -3241,7 +4086,7 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
3241
4086
  function calculateItemsInView(ctx, params = {}) {
3242
4087
  const state = ctx.state;
3243
4088
  batchedUpdates(() => {
3244
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
4089
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
3245
4090
  const {
3246
4091
  columns,
3247
4092
  columnSpans,
@@ -3249,7 +4094,6 @@ function calculateItemsInView(ctx, params = {}) {
3249
4094
  enableScrollForNextCalculateItemsInView,
3250
4095
  idCache,
3251
4096
  indexByKey,
3252
- initialScroll,
3253
4097
  minIndexSizeChanged,
3254
4098
  positions,
3255
4099
  props: {
@@ -3273,6 +4117,8 @@ function calculateItemsInView(ctx, params = {}) {
3273
4117
  const alwaysRenderArr = alwaysRenderIndicesArr || [];
3274
4118
  const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
3275
4119
  const { dataChanged, doMVCP, forceFullItemPositions } = params;
4120
+ const bootstrapInitialScrollState = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
4121
+ const suppressInitialScrollSideEffects = !!bootstrapInitialScrollState;
3276
4122
  const prevNumContainers = peek$(ctx, "numContainers");
3277
4123
  if (!data || scrollLength === 0 || !prevNumContainers) {
3278
4124
  return;
@@ -3283,16 +4129,12 @@ function calculateItemsInView(ctx, params = {}) {
3283
4129
  const speed = getScrollVelocity(state);
3284
4130
  const scrollExtra = 0;
3285
4131
  const { queuedInitialLayout } = state;
3286
- let { scroll: scrollState } = state;
3287
- if (!queuedInitialLayout && initialScroll) {
3288
- const updatedOffset = state.initialScrollUsesOffset ? (_a3 = initialScroll.contentOffset) != null ? _a3 : 0 : calculateOffsetWithOffsetPosition(
3289
- ctx,
3290
- calculateOffsetForIndex(ctx, initialScroll.index),
3291
- initialScroll
3292
- );
3293
- scrollState = updatedOffset;
3294
- }
3295
- const scrollAdjustPending = (_b = peek$(ctx, "scrollAdjustPending")) != null ? _b : 0;
4132
+ const scrollState = suppressInitialScrollSideEffects ? (_b = bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.scroll) != null ? _b : state.scroll : !queuedInitialLayout && state.initialScroll ? (
4133
+ // Before the initial layout settles, keep viewport math anchored to the
4134
+ // current initial-scroll target instead of transient native adjustments.
4135
+ resolveInitialScrollOffset(ctx, state.initialScroll)
4136
+ ) : state.scroll;
4137
+ const scrollAdjustPending = (_c = peek$(ctx, "scrollAdjustPending")) != null ? _c : 0;
3296
4138
  const scrollAdjustPad = scrollAdjustPending - topPad;
3297
4139
  let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
3298
4140
  if (scroll + scrollLength > totalSize) {
@@ -3316,7 +4158,7 @@ function calculateItemsInView(ctx, params = {}) {
3316
4158
  const scrollTopBuffered = scroll - scrollBufferTop;
3317
4159
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
3318
4160
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
3319
- if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
4161
+ if (!suppressInitialScrollSideEffects && !dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
3320
4162
  const { top, bottom } = scrollForNextCalculateItemsInView;
3321
4163
  if (top === null && bottom === null) {
3322
4164
  state.scrollForNextCalculateItemsInView = void 0;
@@ -3326,7 +4168,7 @@ function calculateItemsInView(ctx, params = {}) {
3326
4168
  }
3327
4169
  }
3328
4170
  }
3329
- const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
4171
+ const checkMVCP = doMVCP && !suppressInitialScrollSideEffects ? prepareMVCP(ctx, dataChanged) : void 0;
3330
4172
  if (dataChanged) {
3331
4173
  indexByKey.clear();
3332
4174
  idCache.length = 0;
@@ -3334,7 +4176,7 @@ function calculateItemsInView(ctx, params = {}) {
3334
4176
  columns.length = 0;
3335
4177
  columnSpans.length = 0;
3336
4178
  }
3337
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4179
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_d = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _d : 0;
3338
4180
  updateItemPositions(ctx, dataChanged, {
3339
4181
  doMVCP,
3340
4182
  forceFullUpdate: !!forceFullItemPositions,
@@ -3351,11 +4193,11 @@ function calculateItemsInView(ctx, params = {}) {
3351
4193
  let startBufferedId = null;
3352
4194
  let endNoBuffer = null;
3353
4195
  let endBuffered = null;
3354
- let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4196
+ let loopStart = (_e = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _e : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
3355
4197
  for (let i = loopStart; i >= 0; i--) {
3356
- const id = (_d = idCache[i]) != null ? _d : getId(state, i);
4198
+ const id = (_f = idCache[i]) != null ? _f : getId(state, i);
3357
4199
  const top = positions[i];
3358
- const size = (_e = sizes.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i]);
4200
+ const size = (_g = sizes.get(id)) != null ? _g : getItemSize(ctx, id, i, data[i]);
3359
4201
  const bottom = top + size;
3360
4202
  if (bottom > scroll - scrollBufferTop) {
3361
4203
  loopStart = i;
@@ -3386,8 +4228,8 @@ function calculateItemsInView(ctx, params = {}) {
3386
4228
  let firstFullyOnScreenIndex;
3387
4229
  const dataLength = data.length;
3388
4230
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
3389
- const id = (_f = idCache[i]) != null ? _f : getId(state, i);
3390
- const size = (_g = sizes.get(id)) != null ? _g : getItemSize(ctx, id, i, data[i]);
4231
+ const id = (_h = idCache[i]) != null ? _h : getId(state, i);
4232
+ const size = (_i = sizes.get(id)) != null ? _i : getItemSize(ctx, id, i, data[i]);
3391
4233
  const top = positions[i];
3392
4234
  if (!foundEnd) {
3393
4235
  if (startNoBuffer === null && top + size > scroll) {
@@ -3426,7 +4268,7 @@ function calculateItemsInView(ctx, params = {}) {
3426
4268
  const firstVisibleAnchorIndex = firstFullyOnScreenIndex != null ? firstFullyOnScreenIndex : startNoBuffer;
3427
4269
  if (firstVisibleAnchorIndex !== null && firstVisibleAnchorIndex !== void 0 && endNoBuffer !== null) {
3428
4270
  for (let i = firstVisibleAnchorIndex; i <= endNoBuffer; i++) {
3429
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
4271
+ const id = (_j = idCache[i]) != null ? _j : getId(state, i);
3430
4272
  idsInView.push(id);
3431
4273
  }
3432
4274
  }
@@ -3459,7 +4301,7 @@ function calculateItemsInView(ctx, params = {}) {
3459
4301
  const needNewContainers = [];
3460
4302
  const needNewContainersSet = /* @__PURE__ */ new Set();
3461
4303
  for (let i = startBuffered; i <= endBuffered; i++) {
3462
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
4304
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
3463
4305
  if (!containerItemKeys.has(id)) {
3464
4306
  needNewContainersSet.add(i);
3465
4307
  needNewContainers.push(i);
@@ -3468,7 +4310,7 @@ function calculateItemsInView(ctx, params = {}) {
3468
4310
  if (alwaysRenderArr.length > 0) {
3469
4311
  for (const index of alwaysRenderArr) {
3470
4312
  if (index < 0 || index >= dataLength) continue;
3471
- const id = (_j = idCache[index]) != null ? _j : getId(state, index);
4313
+ const id = (_l = idCache[index]) != null ? _l : getId(state, index);
3472
4314
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
3473
4315
  needNewContainersSet.add(index);
3474
4316
  needNewContainers.push(index);
@@ -3506,7 +4348,7 @@ function calculateItemsInView(ctx, params = {}) {
3506
4348
  for (let idx = 0; idx < needNewContainers.length; idx++) {
3507
4349
  const i = needNewContainers[idx];
3508
4350
  const containerIndex = availableContainers[idx];
3509
- const id = (_k = idCache[i]) != null ? _k : getId(state, i);
4351
+ const id = (_m = idCache[i]) != null ? _m : getId(state, i);
3510
4352
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
3511
4353
  if (oldKey && oldKey !== id) {
3512
4354
  containerItemKeys.delete(oldKey);
@@ -3547,7 +4389,7 @@ function calculateItemsInView(ctx, params = {}) {
3547
4389
  if (alwaysRenderArr.length > 0) {
3548
4390
  for (const index of alwaysRenderArr) {
3549
4391
  if (index < 0 || index >= dataLength) continue;
3550
- const id = (_l = idCache[index]) != null ? _l : getId(state, index);
4392
+ const id = (_n = idCache[index]) != null ? _n : getId(state, index);
3551
4393
  const containerIndex = containerItemKeys.get(id);
3552
4394
  if (containerIndex !== void 0) {
3553
4395
  state.stickyContainerPool.add(containerIndex);
@@ -3618,13 +4460,23 @@ function calculateItemsInView(ctx, params = {}) {
3618
4460
  if (didChangePositions) {
3619
4461
  set$(ctx, "lastPositionUpdate", Date.now());
3620
4462
  }
3621
- if (!queuedInitialLayout && endBuffered !== null) {
3622
- if (checkAllSizesKnown(state)) {
3623
- setDidLayout(ctx);
3624
- }
4463
+ if (suppressInitialScrollSideEffects) {
4464
+ evaluateBootstrapInitialScroll(ctx);
4465
+ return;
3625
4466
  }
3626
- if (viewabilityConfigCallbackPairs) {
3627
- updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollLength, startNoBuffer, endNoBuffer);
4467
+ if (!queuedInitialLayout && endBuffered !== null && checkAllSizesKnown(state)) {
4468
+ setDidLayout(ctx);
4469
+ handleInitialScrollLayoutReady(ctx);
4470
+ }
4471
+ if (viewabilityConfigCallbackPairs && startNoBuffer !== null && endNoBuffer !== null) {
4472
+ updateViewableItems(
4473
+ ctx.state,
4474
+ ctx,
4475
+ viewabilityConfigCallbackPairs,
4476
+ scrollLength,
4477
+ startNoBuffer,
4478
+ endNoBuffer
4479
+ );
3628
4480
  }
3629
4481
  if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
3630
4482
  const item = data[nextActiveStickyIndex];
@@ -3655,79 +4507,45 @@ function checkActualChange(state, dataProp, previousData) {
3655
4507
  return false;
3656
4508
  }
3657
4509
 
3658
- // src/core/checkFinishedScroll.ts
3659
- var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
3660
- var INITIAL_SCROLL_MAX_FALLBACK_CHECKS = 20;
3661
- var INITIAL_SCROLL_ZERO_TARGET_EPSILON = 1;
3662
- function checkFinishedScroll(ctx) {
3663
- ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
3664
- }
3665
- function checkFinishedScrollFrame(ctx) {
3666
- var _a3;
3667
- const scrollingTo = ctx.state.scrollingTo;
3668
- if (scrollingTo) {
3669
- const { state } = ctx;
3670
- state.animFrameCheckFinishedScroll = void 0;
3671
- const scroll = state.scrollPending;
3672
- const adjust = state.scrollAdjustHandler.getAdjust();
3673
- const clampedTargetOffset = (_a3 = scrollingTo.targetOffset) != null ? _a3 : clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0), scrollingTo);
3674
- const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
3675
- const diff1 = Math.abs(scroll - clampedTargetOffset);
3676
- const diff2 = Math.abs(diff1 - adjust);
3677
- const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
3678
- const isAtTarget = diff1 < 1 || !scrollingTo.animated && diff2 < 1;
3679
- if (isNotOverscrolled && isAtTarget) {
3680
- finishScrollTo(ctx);
4510
+ // src/core/doMaintainScrollAtEnd.ts
4511
+ function doMaintainScrollAtEnd(ctx) {
4512
+ const state = ctx.state;
4513
+ const {
4514
+ didContainersLayout,
4515
+ isAtEnd,
4516
+ pendingNativeMVCPAdjust,
4517
+ refScroller,
4518
+ props: { maintainScrollAtEnd }
4519
+ } = state;
4520
+ const shouldMaintainScrollAtEnd = !!(isAtEnd && maintainScrollAtEnd && didContainersLayout);
4521
+ if (pendingNativeMVCPAdjust) {
4522
+ state.pendingMaintainScrollAtEnd = shouldMaintainScrollAtEnd;
4523
+ return false;
4524
+ }
4525
+ state.pendingMaintainScrollAtEnd = false;
4526
+ if (shouldMaintainScrollAtEnd) {
4527
+ const contentSize = getContentSize(ctx);
4528
+ if (contentSize < state.scrollLength) {
4529
+ state.scroll = 0;
3681
4530
  }
4531
+ requestAnimationFrame(() => {
4532
+ var _a3;
4533
+ if (state.isAtEnd) {
4534
+ state.maintainingScrollAtEnd = true;
4535
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
4536
+ animated: maintainScrollAtEnd.animated
4537
+ });
4538
+ setTimeout(
4539
+ () => {
4540
+ state.maintainingScrollAtEnd = false;
4541
+ },
4542
+ maintainScrollAtEnd.animated ? 500 : 0
4543
+ );
4544
+ }
4545
+ });
4546
+ return true;
3682
4547
  }
3683
- }
3684
- function checkFinishedScrollFallback(ctx) {
3685
- const state = ctx.state;
3686
- const scrollingTo = state.scrollingTo;
3687
- const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
3688
- const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget || !state.didContainersLayout;
3689
- state.timeoutCheckFinishedScrollFallback = setTimeout(
3690
- () => {
3691
- let numChecks = 0;
3692
- const checkHasScrolled = () => {
3693
- var _a3, _b;
3694
- state.timeoutCheckFinishedScrollFallback = void 0;
3695
- const isStillScrollingTo = state.scrollingTo;
3696
- if (isStillScrollingTo) {
3697
- numChecks++;
3698
- const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
3699
- const maxChecks = isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
3700
- const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
3701
- if (shouldFinishZeroTarget || state.hasScrolled || numChecks > maxChecks) {
3702
- finishScrollTo(ctx);
3703
- } else if (isNativeInitialPending && numChecks <= maxChecks) {
3704
- const targetOffset = (_b = (_a3 = state.initialNativeScrollWatchdog) == null ? void 0 : _a3.targetOffset) != null ? _b : state.scrollPending;
3705
- const scroller = state.refScroller.current;
3706
- if (scroller) {
3707
- scroller.scrollTo({
3708
- animated: false,
3709
- x: state.props.horizontal ? targetOffset : 0,
3710
- y: state.props.horizontal ? 0 : targetOffset
3711
- });
3712
- }
3713
- state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
3714
- } else {
3715
- state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
3716
- }
3717
- }
3718
- };
3719
- checkHasScrolled();
3720
- },
3721
- slowTimeout ? 500 : 100
3722
- );
3723
- }
3724
- function isNativeInitialNonZeroTarget(state) {
3725
- return !state.didFinishInitialScroll && !!state.initialNativeScrollWatchdog && state.initialNativeScrollWatchdog.targetOffset > INITIAL_SCROLL_MIN_TARGET_OFFSET;
3726
- }
3727
- function shouldFinishInitialZeroTargetScroll(ctx) {
3728
- var _a3;
3729
- const { state } = ctx;
3730
- return !!((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) && state.props.data.length > 0 && getContentSize(ctx) <= state.scrollLength && state.scrollPending <= INITIAL_SCROLL_ZERO_TARGET_EPSILON;
4548
+ return false;
3731
4549
  }
3732
4550
 
3733
4551
  // src/utils/updateAveragesOnDataChange.ts
@@ -3917,20 +4735,102 @@ function handleLayout(ctx, layoutParam, setCanRender) {
3917
4735
  setCanRender(true);
3918
4736
  }
3919
4737
 
4738
+ // src/core/updateScroll.ts
4739
+ function updateScroll(ctx, newScroll, forceUpdate) {
4740
+ var _a3;
4741
+ const state = ctx.state;
4742
+ const { ignoreScrollFromMVCP, lastScrollAdjustForHistory, scrollAdjustHandler, scrollHistory, scrollingTo } = state;
4743
+ const prevScroll = state.scroll;
4744
+ state.hasScrolled = true;
4745
+ state.lastBatchingAction = Date.now();
4746
+ const currentTime = Date.now();
4747
+ const adjust = scrollAdjustHandler.getAdjust();
4748
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
4749
+ if (adjustChanged) {
4750
+ scrollHistory.length = 0;
4751
+ }
4752
+ state.lastScrollAdjustForHistory = adjust;
4753
+ if (scrollingTo === void 0 && !(scrollHistory.length === 0 && newScroll === state.scroll)) {
4754
+ if (!adjustChanged) {
4755
+ scrollHistory.push({ scroll: newScroll, time: currentTime });
4756
+ }
4757
+ }
4758
+ if (scrollHistory.length > 5) {
4759
+ scrollHistory.shift();
4760
+ }
4761
+ if (ignoreScrollFromMVCP && !scrollingTo) {
4762
+ const { lt, gt } = ignoreScrollFromMVCP;
4763
+ if (lt && newScroll < lt || gt && newScroll > gt) {
4764
+ state.ignoreScrollFromMVCPIgnored = true;
4765
+ return;
4766
+ }
4767
+ }
4768
+ state.scrollPrev = prevScroll;
4769
+ state.scrollPrevTime = state.scrollTime;
4770
+ state.scroll = newScroll;
4771
+ state.scrollTime = currentTime;
4772
+ const scrollDelta = Math.abs(newScroll - prevScroll);
4773
+ const didResolvePendingNativeMVCPAdjust = resolvePendingNativeMVCPAdjust(ctx, newScroll);
4774
+ const scrollLength = state.scrollLength;
4775
+ const lastCalculated = state.scrollLastCalculate;
4776
+ const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
4777
+ const shouldUpdate = useAggressiveItemRecalculation || didResolvePendingNativeMVCPAdjust || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
4778
+ if (shouldUpdate) {
4779
+ state.scrollLastCalculate = state.scroll;
4780
+ state.ignoreScrollFromMVCPIgnored = false;
4781
+ state.lastScrollDelta = scrollDelta;
4782
+ const runCalculateItems = () => {
4783
+ var _a4;
4784
+ (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0 });
4785
+ checkThresholds(ctx);
4786
+ };
4787
+ if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
4788
+ ReactDOM.flushSync(runCalculateItems);
4789
+ } else {
4790
+ runCalculateItems();
4791
+ }
4792
+ const shouldMaintainScrollAtEndAfterPendingSettle = !!state.pendingMaintainScrollAtEnd || !!((_a3 = state.props.maintainScrollAtEnd) == null ? void 0 : _a3.onDataChange);
4793
+ if (didResolvePendingNativeMVCPAdjust && shouldMaintainScrollAtEndAfterPendingSettle) {
4794
+ state.pendingMaintainScrollAtEnd = false;
4795
+ doMaintainScrollAtEnd(ctx);
4796
+ }
4797
+ state.dataChangeNeedsScrollUpdate = false;
4798
+ state.lastScrollDelta = 0;
4799
+ }
4800
+ }
4801
+
3920
4802
  // src/core/onScroll.ts
3921
- var INITIAL_SCROLL_PROGRESS_EPSILON = 1;
3922
- function didObserveInitialScrollProgress(newScroll, watchdog) {
3923
- const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
3924
- const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
3925
- return nextDistance <= INITIAL_SCROLL_PROGRESS_EPSILON || nextDistance + INITIAL_SCROLL_PROGRESS_EPSILON < previousDistance;
4803
+ function trackInitialScrollNativeProgress(state, newScroll) {
4804
+ const initialNativeScrollWatchdog = initialScrollWatchdog.get(state);
4805
+ const didInitialScrollProgress = !!initialNativeScrollWatchdog && initialScrollWatchdog.didObserveProgress(newScroll, initialNativeScrollWatchdog);
4806
+ if (didInitialScrollProgress) {
4807
+ initialScrollWatchdog.clear(state);
4808
+ return;
4809
+ }
4810
+ if (initialNativeScrollWatchdog) {
4811
+ state.hasScrolled = false;
4812
+ initialScrollWatchdog.set(state, {
4813
+ startScroll: initialNativeScrollWatchdog.startScroll,
4814
+ targetOffset: initialNativeScrollWatchdog.targetOffset
4815
+ });
4816
+ }
4817
+ }
4818
+ function shouldDeferPublicOnScroll(state) {
4819
+ var _a3;
4820
+ return !!state.initialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" && !state.didFinishInitialScroll;
4821
+ }
4822
+ function cloneScrollEvent(event) {
4823
+ return {
4824
+ ...event,
4825
+ nativeEvent: {
4826
+ ...event.nativeEvent
4827
+ }
4828
+ };
3926
4829
  }
3927
4830
  function onScroll(ctx, event) {
3928
4831
  var _a3, _b, _c, _d;
3929
4832
  const state = ctx.state;
3930
- const {
3931
- scrollProcessingEnabled,
3932
- props: { onScroll: onScrollProp }
3933
- } = state;
4833
+ const { scrollProcessingEnabled } = state;
3934
4834
  if (scrollProcessingEnabled === false) {
3935
4835
  return;
3936
4836
  }
@@ -3961,20 +4861,18 @@ function onScroll(ctx, event) {
3961
4861
  }
3962
4862
  }
3963
4863
  state.scrollPending = newScroll;
3964
- const initialNativeScrollWatchdog = state.initialNativeScrollWatchdog;
3965
- const didInitialScrollProgress = !!initialNativeScrollWatchdog && didObserveInitialScrollProgress(newScroll, initialNativeScrollWatchdog);
3966
- if (didInitialScrollProgress) {
3967
- state.initialNativeScrollWatchdog = void 0;
3968
- }
3969
4864
  updateScroll(ctx, newScroll, insetChanged);
3970
- if (initialNativeScrollWatchdog && !didInitialScrollProgress) {
3971
- state.hasScrolled = false;
3972
- state.initialNativeScrollWatchdog = initialNativeScrollWatchdog;
3973
- }
4865
+ trackInitialScrollNativeProgress(state, newScroll);
3974
4866
  if (state.scrollingTo) {
3975
4867
  checkFinishedScroll(ctx);
3976
4868
  }
3977
- onScrollProp == null ? void 0 : onScrollProp(event);
4869
+ if (state.props.onScroll) {
4870
+ if (shouldDeferPublicOnScroll(state)) {
4871
+ state.deferredPublicOnScrollEvent = cloneScrollEvent(event);
4872
+ } else {
4873
+ state.props.onScroll(event);
4874
+ }
4875
+ }
3978
4876
  }
3979
4877
 
3980
4878
  // src/core/ScrollAdjustHandler.ts
@@ -4615,7 +5513,7 @@ var LegendList = typedMemo(
4615
5513
  })
4616
5514
  );
4617
5515
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
4618
- var _a3, _b, _c, _d, _e, _f, _g, _h;
5516
+ var _a3, _b, _c, _d, _e, _f, _g;
4619
5517
  const {
4620
5518
  alignItemsAtEnd = false,
4621
5519
  alwaysRender,
@@ -4639,6 +5537,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4639
5537
  itemsAreEqual,
4640
5538
  keyExtractor: keyExtractorProp,
4641
5539
  ListEmptyComponent,
5540
+ ListFooterComponent,
5541
+ ListFooterComponentStyle,
4642
5542
  ListHeaderComponent,
4643
5543
  maintainScrollAtEnd = false,
4644
5544
  maintainScrollAtEndThreshold = 0.1,
@@ -4675,7 +5575,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4675
5575
  useWindowScroll = false,
4676
5576
  viewabilityConfig,
4677
5577
  viewabilityConfigCallbackPairs,
4678
- waitForInitialLayout = true,
4679
5578
  ...rest
4680
5579
  } = props;
4681
5580
  const animatedPropsInternal = props.animatedPropsInternal;
@@ -4708,8 +5607,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4708
5607
  const hasInitialScrollIndex = initialScrollIndexProp !== void 0 && initialScrollIndexProp !== null;
4709
5608
  const hasInitialScrollOffset = initialScrollOffsetProp !== void 0 && initialScrollOffsetProp !== null;
4710
5609
  const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && hasInitialScrollOffset;
4711
- const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState, viewPosition: 1 } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
5610
+ const usesBootstrapInitialScroll = initialScrollAtEnd || hasInitialScrollIndex;
5611
+ const initialScrollProp = initialScrollAtEnd ? {
5612
+ index: Math.max(0, dataProp.length - 1),
5613
+ preserveForBottomPadding: true,
5614
+ viewOffset: -stylePaddingBottomState,
5615
+ viewPosition: 1
5616
+ } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
4712
5617
  index: (_a3 = initialScrollIndexProp.index) != null ? _a3 : 0,
5618
+ preserveForBottomPadding: initialScrollIndexProp.viewOffset === void 0 && initialScrollIndexProp.viewPosition === 1 ? true : void 0,
4713
5619
  viewOffset: (_b = initialScrollIndexProp.viewOffset) != null ? _b : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingBottomState : 0,
4714
5620
  viewPosition: (_c = initialScrollIndexProp.viewPosition) != null ? _c : 0
4715
5621
  } : {
@@ -4778,22 +5684,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4778
5684
  idCache: [],
4779
5685
  idsInView: [],
4780
5686
  indexByKey: /* @__PURE__ */ new Map(),
4781
- initialAnchor: !initialScrollUsesOffsetOnly && (initialScrollProp == null ? void 0 : initialScrollProp.index) !== void 0 && (initialScrollProp == null ? void 0 : initialScrollProp.viewPosition) !== void 0 ? {
4782
- attempts: 0,
4783
- index: initialScrollProp.index,
4784
- settledTicks: 0,
4785
- viewOffset: (_f = initialScrollProp.viewOffset) != null ? _f : 0,
4786
- viewPosition: initialScrollProp.viewPosition
4787
- } : void 0,
4788
- initialNativeScrollWatchdog: void 0,
4789
5687
  initialScroll: initialScrollProp,
4790
- initialScrollLastDidFinish: false,
4791
- initialScrollLastTarget: initialScrollProp,
4792
- initialScrollLastTargetUsesOffset: initialScrollUsesOffsetOnly,
4793
- initialScrollPreviousDataLength: dataProp.length,
4794
- initialScrollRetryLastLength: void 0,
4795
- initialScrollRetryWindowUntil: 0,
4796
- initialScrollUsesOffset: initialScrollUsesOffsetOnly,
5688
+ initialScrollSession: initialScrollProp ? {
5689
+ kind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
5690
+ previousDataLength: dataProp.length
5691
+ } : void 0,
4797
5692
  isAtEnd: false,
4798
5693
  isAtStart: false,
4799
5694
  isEndReached: null,
@@ -4836,6 +5731,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4836
5731
  };
4837
5732
  const internalState = ctx.state;
4838
5733
  internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
5734
+ internalState.reprocessCurrentScroll = () => updateScroll(ctx, internalState.scroll, true);
4839
5735
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
4840
5736
  set$(ctx, "extraData", extraData);
4841
5737
  }
@@ -4922,96 +5818,23 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4922
5818
  true
4923
5819
  );
4924
5820
  }
4925
- const resolveInitialScrollOffset = React3.useCallback((initialScroll) => {
4926
- var _a4;
4927
- if (state.initialScrollUsesOffset) {
4928
- return clampScrollOffset(ctx, (_a4 = initialScroll.contentOffset) != null ? _a4 : 0);
4929
- }
4930
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
4931
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
4932
- return clampScrollOffset(ctx, resolvedOffset, initialScroll);
4933
- }, []);
4934
- const finishInitialScrollWithoutScroll = React3.useCallback(() => {
4935
- refState.current.initialAnchor = void 0;
4936
- refState.current.initialScroll = void 0;
4937
- state.initialAnchor = void 0;
4938
- state.initialScroll = void 0;
4939
- state.initialScrollUsesOffset = false;
4940
- state.initialScrollLastTarget = void 0;
4941
- state.initialScrollLastTargetUsesOffset = false;
4942
- setInitialRenderState(ctx, { didInitialScroll: true });
4943
- }, []);
4944
- const setActiveInitialScrollTarget = React3.useCallback(
4945
- (target, options) => {
4946
- const usesOffset = !!(options == null ? void 0 : options.usesOffset);
4947
- state.initialScrollUsesOffset = usesOffset;
4948
- state.initialScrollLastTarget = target;
4949
- state.initialScrollLastTargetUsesOffset = usesOffset;
4950
- refState.current.initialScroll = target;
4951
- state.initialScroll = target;
4952
- if ((options == null ? void 0 : options.resetDidFinish) && state.didFinishInitialScroll) {
4953
- state.didFinishInitialScroll = false;
4954
- }
4955
- if (!(options == null ? void 0 : options.syncAnchor)) {
4956
- return;
4957
- }
4958
- },
4959
- []
4960
- );
4961
- const shouldFinishInitialScrollAtOrigin = React3.useCallback(
4962
- (initialScroll, offset) => {
4963
- var _a4, _b2, _c2;
4964
- if (offset !== 0 || initialScrollAtEnd) {
4965
- return false;
4966
- }
4967
- if (state.initialScrollUsesOffset) {
4968
- return Math.abs((_a4 = initialScroll.contentOffset) != null ? _a4 : 0) <= 1;
4969
- }
4970
- return initialScroll.index === 0 && ((_b2 = initialScroll.viewPosition) != null ? _b2 : 0) === 0 && Math.abs((_c2 = initialScroll.viewOffset) != null ? _c2 : 0) <= 1;
4971
- },
4972
- [initialScrollAtEnd]
4973
- );
4974
- const shouldFinishEmptyInitialScrollAtEnd = React3.useCallback(
4975
- (initialScroll, offset) => {
4976
- return dataProp.length === 0 && initialScrollAtEnd && offset === 0 && initialScroll.viewPosition === 1;
4977
- },
4978
- [dataProp.length, initialScrollAtEnd]
4979
- );
4980
- const shouldRearmFinishedEmptyInitialScrollAtEnd = React3.useCallback(
4981
- (initialScroll) => {
4982
- var _a4;
4983
- return !!(state.didFinishInitialScroll && dataProp.length > 0 && initialScroll && !state.initialScrollUsesOffset && initialScroll.index === 0 && initialScroll.viewPosition === 1 && ((_a4 = initialScroll.contentOffset) != null ? _a4 : 0) === 0);
4984
- },
4985
- [dataProp.length]
4986
- );
4987
5821
  const initialContentOffset = React3.useMemo(() => {
4988
- let value;
4989
- const { initialScroll, initialAnchor } = refState.current;
4990
- if (initialScroll) {
4991
- if (!state.initialScrollUsesOffset && !IsNewArchitecture) ;
4992
- if (initialScroll.contentOffset !== void 0) {
4993
- value = initialScroll.contentOffset;
4994
- } else {
4995
- const clampedOffset = resolveInitialScrollOffset(initialScroll);
4996
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
4997
- setActiveInitialScrollTarget(updatedInitialScroll, {
4998
- usesOffset: state.initialScrollUsesOffset
4999
- });
5000
- value = clampedOffset;
5001
- }
5002
- } else {
5003
- refState.current.initialAnchor = void 0;
5004
- value = 0;
5005
- }
5006
- const hasPendingDataDependentInitialScroll = !!initialScroll && dataProp.length === 0 && !shouldFinishInitialScrollAtOrigin(initialScroll, value) && !shouldFinishEmptyInitialScrollAtEnd(initialScroll, value);
5007
- if (!value && !hasPendingDataDependentInitialScroll) {
5008
- if (initialScroll && shouldFinishInitialScrollAtOrigin(initialScroll, value)) {
5009
- finishInitialScrollWithoutScroll();
5010
- } else {
5011
- setInitialRenderState(ctx, { didInitialScroll: true });
5012
- }
5822
+ var _a4, _b2;
5823
+ const initialScroll = state.initialScroll;
5824
+ if (!initialScroll) {
5825
+ return void 0;
5013
5826
  }
5014
- return value;
5827
+ const resolvedOffset = (_a4 = initialScroll.contentOffset) != null ? _a4 : resolveInitialScrollOffset(ctx, initialScroll);
5828
+ return usesBootstrapInitialScroll && ((_b2 = state.initialScrollSession) == null ? void 0 : _b2.kind) === "bootstrap" && Platform.OS === "web" ? void 0 : resolvedOffset;
5829
+ }, [usesBootstrapInitialScroll]);
5830
+ React3.useLayoutEffect(() => {
5831
+ initializeInitialScrollOnMount(ctx, {
5832
+ dataLength: dataProp.length,
5833
+ hasFooterComponent: !!ListFooterComponent,
5834
+ initialContentOffset,
5835
+ initialScrollAtEnd,
5836
+ useBootstrapInitialScroll: usesBootstrapInitialScroll
5837
+ });
5015
5838
  }, []);
5016
5839
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
5017
5840
  refState.current.lastBatchingAction = Date.now();
@@ -5026,188 +5849,39 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5026
5849
  set$(ctx, "totalSize", 0);
5027
5850
  }
5028
5851
  }
5029
- const doInitialScroll = React3.useCallback((options) => {
5030
- var _a4, _b2;
5031
- const allowPostFinishRetry = !!(options == null ? void 0 : options.allowPostFinishRetry);
5032
- const { didFinishInitialScroll, queuedInitialLayout, scrollingTo } = state;
5033
- const initialScroll = (_a4 = state.initialScroll) != null ? _a4 : allowPostFinishRetry ? state.initialScrollLastTarget : void 0;
5034
- const isInitialScrollInProgress = !!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll);
5035
- const needsContainerLayoutForInitialScroll = !state.initialScrollUsesOffset;
5036
- const shouldWaitForInitialLayout = waitForInitialLayout && needsContainerLayoutForInitialScroll && !queuedInitialLayout && !allowPostFinishRetry && !isInitialScrollInProgress;
5037
- if (!initialScroll || shouldWaitForInitialLayout || didFinishInitialScroll && !allowPostFinishRetry || scrollingTo && !isInitialScrollInProgress) {
5038
- return;
5039
- }
5040
- if (allowPostFinishRetry && state.initialScrollLastTargetUsesOffset) {
5041
- return;
5042
- }
5043
- const didMoveAwayFromInitialTarget = allowPostFinishRetry && initialScroll.contentOffset !== void 0 && Math.abs(state.scroll - initialScroll.contentOffset) > 1;
5044
- if (didMoveAwayFromInitialTarget) {
5045
- state.initialScrollRetryWindowUntil = 0;
5046
- return;
5047
- }
5048
- const offset = resolveInitialScrollOffset(initialScroll);
5049
- const activeInitialTargetOffset = isInitialScrollInProgress ? (_b2 = scrollingTo.targetOffset) != null ? _b2 : scrollingTo.offset : void 0;
5050
- const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - offset) > 1;
5051
- const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - offset) > 1;
5052
- if (!didOffsetChange && (allowPostFinishRetry || isInitialScrollInProgress && !didActiveInitialTargetChange)) {
5053
- return;
5054
- }
5055
- if (didOffsetChange) {
5056
- const updatedInitialScroll = { ...initialScroll, contentOffset: offset };
5057
- if (!state.initialScrollUsesOffset) {
5058
- state.initialScrollLastTarget = updatedInitialScroll;
5059
- state.initialScrollLastTargetUsesOffset = false;
5060
- if (state.initialScroll) {
5061
- refState.current.initialScroll = updatedInitialScroll;
5062
- state.initialScroll = updatedInitialScroll;
5063
- }
5064
- }
5065
- }
5066
- const hasMeasuredScrollLayout = !!state.lastLayout && state.scrollLength > 0;
5067
- const shouldForceNativeInitialScroll = state.initialScrollUsesOffset && hasMeasuredScrollLayout || allowPostFinishRetry || !!queuedInitialLayout || isInitialScrollInProgress && didOffsetChange;
5068
- performInitialScroll(ctx, {
5069
- forceScroll: shouldForceNativeInitialScroll,
5070
- initialScrollUsesOffset: state.initialScrollUsesOffset,
5071
- resolvedOffset: offset,
5072
- target: initialScroll
5073
- });
5074
- }, []);
5075
- React3.useLayoutEffect(() => {
5076
- var _a4;
5077
- const previousDataLength = state.initialScrollPreviousDataLength;
5078
- state.initialScrollPreviousDataLength = dataProp.length;
5079
- if (previousDataLength !== 0 || dataProp.length === 0 || !state.initialScroll || !state.queuedInitialLayout) {
5080
- return;
5081
- }
5082
- if (initialScrollAtEnd) {
5083
- const lastIndex = Math.max(0, dataProp.length - 1);
5084
- const initialScroll = state.initialScroll;
5085
- const shouldRearm = shouldRearmFinishedEmptyInitialScrollAtEnd(initialScroll);
5086
- if (state.didFinishInitialScroll && !shouldRearm) {
5087
- return;
5088
- }
5089
- if (initialScroll && !state.initialScrollUsesOffset && initialScroll.index === lastIndex && initialScroll.viewPosition === 1 && !shouldRearm) {
5090
- return;
5091
- }
5092
- const updatedInitialScroll = {
5093
- contentOffset: void 0,
5094
- index: lastIndex,
5095
- viewOffset: (_a4 = initialScroll == null ? void 0 : initialScroll.viewOffset) != null ? _a4 : -stylePaddingBottomState,
5096
- viewPosition: 1
5097
- };
5098
- setActiveInitialScrollTarget(updatedInitialScroll, {
5099
- resetDidFinish: shouldRearm,
5100
- syncAnchor: true
5101
- });
5102
- doInitialScroll();
5103
- return;
5104
- }
5105
- if (state.didFinishInitialScroll) {
5106
- return;
5107
- }
5108
- doInitialScroll();
5109
- }, [
5110
- dataProp.length,
5111
- doInitialScroll,
5112
- initialScrollAtEnd,
5113
- shouldRearmFinishedEmptyInitialScrollAtEnd,
5114
- stylePaddingBottomState
5115
- ]);
5116
5852
  React3.useLayoutEffect(() => {
5117
- var _a4;
5118
- if (!initialScrollAtEnd) {
5119
- return;
5120
- }
5121
- const lastIndex = Math.max(0, dataProp.length - 1);
5122
- const initialScroll = state.initialScroll;
5123
- const shouldRearm = shouldRearmFinishedEmptyInitialScrollAtEnd(initialScroll);
5124
- if (state.didFinishInitialScroll && !shouldRearm) {
5125
- return;
5126
- }
5127
- if (shouldRearm) {
5128
- state.didFinishInitialScroll = false;
5129
- }
5130
- if (initialScroll && !state.initialScrollUsesOffset && initialScroll.index === lastIndex && initialScroll.viewPosition === 1 && !shouldRearm) {
5131
- return;
5132
- }
5133
- const updatedInitialScroll = {
5134
- contentOffset: void 0,
5135
- index: lastIndex,
5136
- viewOffset: (_a4 = initialScroll == null ? void 0 : initialScroll.viewOffset) != null ? _a4 : -stylePaddingBottomState,
5137
- viewPosition: 1
5138
- };
5139
- setActiveInitialScrollTarget(updatedInitialScroll, {
5140
- resetDidFinish: shouldRearm,
5141
- syncAnchor: true
5853
+ handleInitialScrollDataChange(ctx, {
5854
+ dataLength: dataProp.length,
5855
+ didDataChange: didDataChangeLocal,
5856
+ initialScrollAtEnd,
5857
+ stylePaddingBottom: stylePaddingBottomState,
5858
+ useBootstrapInitialScroll: usesBootstrapInitialScroll
5142
5859
  });
5143
- doInitialScroll();
5144
- }, [
5145
- dataProp.length,
5146
- doInitialScroll,
5147
- initialScrollAtEnd,
5148
- shouldRearmFinishedEmptyInitialScrollAtEnd,
5149
- stylePaddingBottomState
5150
- ]);
5860
+ }, [dataProp.length, didDataChangeLocal, initialScrollAtEnd, stylePaddingBottomState, usesBootstrapInitialScroll]);
5151
5861
  const onLayoutFooter = React3.useCallback(
5152
5862
  (layout) => {
5153
- var _a4;
5154
- if (!initialScrollAtEnd) {
5155
- return;
5156
- }
5157
- const { initialScroll } = state;
5158
- if (!initialScroll) {
5863
+ if (!usesBootstrapInitialScroll) {
5159
5864
  return;
5160
5865
  }
5161
- const lastIndex = Math.max(0, dataProp.length - 1);
5162
- if (initialScroll.index !== lastIndex || initialScroll.viewPosition !== 1) {
5866
+ handleBootstrapInitialScrollFooterLayout(ctx, {
5867
+ dataLength: dataProp.length,
5868
+ footerSize: layout[horizontal ? "width" : "height"],
5869
+ initialScrollAtEnd,
5870
+ stylePaddingBottom: stylePaddingBottomState
5871
+ });
5872
+ },
5873
+ [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingBottomState, usesBootstrapInitialScroll]
5874
+ );
5875
+ const onLayoutChange = React3.useCallback(
5876
+ (layout) => {
5877
+ handleLayout(ctx, layout, setCanRender);
5878
+ if (usesBootstrapInitialScroll) {
5163
5879
  return;
5164
5880
  }
5165
- const footerSize = layout[horizontal ? "width" : "height"];
5166
- const viewOffset = -stylePaddingBottomState - footerSize;
5167
- if (initialScroll.viewOffset !== viewOffset) {
5168
- const previousTargetOffset = (_a4 = initialScroll.contentOffset) != null ? _a4 : resolveInitialScrollOffset(initialScroll);
5169
- const didMoveAwayFromFinishedInitialTarget = state.didFinishInitialScroll && Math.abs(state.scroll - previousTargetOffset) > 1;
5170
- if (didMoveAwayFromFinishedInitialTarget) {
5171
- return;
5172
- }
5173
- const updatedInitialScroll = { ...initialScroll, viewOffset };
5174
- setActiveInitialScrollTarget(updatedInitialScroll, {
5175
- resetDidFinish: true
5176
- });
5177
- doInitialScroll();
5178
- }
5881
+ advanceCurrentInitialScrollSession(ctx);
5179
5882
  },
5180
- [
5181
- dataProp.length,
5182
- doInitialScroll,
5183
- horizontal,
5184
- initialScrollAtEnd,
5185
- resolveInitialScrollOffset,
5186
- stylePaddingBottomState
5187
- ]
5883
+ [usesBootstrapInitialScroll]
5188
5884
  );
5189
- const onLayoutChange = React3.useCallback((layout) => {
5190
- var _a4;
5191
- handleLayout(ctx, layout, setCanRender);
5192
- const SCROLL_LENGTH_RETRY_WINDOW_MS = 600;
5193
- const now = Date.now();
5194
- const didFinishInitialScroll = !!state.didFinishInitialScroll;
5195
- if (didFinishInitialScroll && !state.initialScrollLastDidFinish) {
5196
- state.initialScrollRetryWindowUntil = now + SCROLL_LENGTH_RETRY_WINDOW_MS;
5197
- }
5198
- state.initialScrollLastDidFinish = didFinishInitialScroll;
5199
- const previousScrollLength = state.initialScrollRetryLastLength;
5200
- const currentScrollLength = state.scrollLength;
5201
- const didScrollLengthChange = previousScrollLength === void 0 || Math.abs(currentScrollLength - previousScrollLength) > 1;
5202
- if (didScrollLengthChange) {
5203
- state.initialScrollRetryLastLength = currentScrollLength;
5204
- }
5205
- if (didFinishInitialScroll && didScrollLengthChange && now <= state.initialScrollRetryWindowUntil && !state.initialScrollLastTargetUsesOffset && ((_a4 = state.initialScrollLastTarget) == null ? void 0 : _a4.index) !== void 0) {
5206
- doInitialScroll({ allowPostFinishRetry: true });
5207
- return;
5208
- }
5209
- doInitialScroll();
5210
- }, []);
5211
5885
  const { onLayout } = useOnLayoutSync({
5212
5886
  onLayoutChange,
5213
5887
  onLayoutProp,
@@ -5281,7 +5955,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5281
5955
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
5282
5956
  React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
5283
5957
  {
5284
- React3.useEffect(doInitialScroll, []);
5958
+ React3.useEffect(() => {
5959
+ if (usesBootstrapInitialScroll) {
5960
+ return;
5961
+ }
5962
+ advanceCurrentInitialScrollSession(ctx);
5963
+ }, [usesBootstrapInitialScroll]);
5285
5964
  }
5286
5965
  const fns = React3.useMemo(
5287
5966
  () => ({
@@ -5311,6 +5990,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5311
5990
  horizontal,
5312
5991
  initialContentOffset,
5313
5992
  ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
5993
+ ListFooterComponent,
5994
+ ListFooterComponentStyle,
5314
5995
  ListHeaderComponent,
5315
5996
  onLayout,
5316
5997
  onLayoutFooter,
@@ -5318,7 +5999,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5318
5999
  onScroll: onScrollHandler,
5319
6000
  recycleItems,
5320
6001
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControlElement, {
5321
- progressViewOffset: ((_g = refreshControlElement.props.progressViewOffset) != null ? _g : 0) + stylePaddingTopState
6002
+ progressViewOffset: ((_f = refreshControlElement.props.progressViewOffset) != null ? _f : 0) + stylePaddingTopState
5322
6003
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React3__namespace.createElement(
5323
6004
  RefreshControl,
5324
6005
  {
@@ -5329,14 +6010,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5329
6010
  ),
5330
6011
  refScrollView: combinedRef,
5331
6012
  renderScrollComponent,
5332
- scrollAdjustHandler: (_h = refState.current) == null ? void 0 : _h.scrollAdjustHandler,
6013
+ scrollAdjustHandler: (_g = refState.current) == null ? void 0 : _g.scrollAdjustHandler,
5333
6014
  scrollEventThrottle: 0,
5334
6015
  snapToIndices,
5335
6016
  stickyHeaderIndices,
5336
6017
  style,
5337
6018
  updateItemSize: fns.updateItemSize,
5338
- useWindowScroll: useWindowScrollResolved,
5339
- waitForInitialLayout
6019
+ useWindowScroll: useWindowScrollResolved
5340
6020
  }
5341
6021
  ), IS_DEV && ENABLE_DEBUG_VIEW);
5342
6022
  });