@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.
package/index.mjs CHANGED
@@ -916,7 +916,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
916
916
  const ref = useRef(null);
917
917
  const ctx = useStateContext();
918
918
  const columnWrapperStyle = ctx.columnWrapperStyle;
919
- const [totalSize, otherAxisSize] = useArr$(["totalSize", "otherAxisSize"]);
919
+ const [otherAxisSize, totalSize] = useArr$(["otherAxisSize", "totalSize"]);
920
920
  useDOMOrder(ref);
921
921
  const style = horizontal ? { minHeight: otherAxisSize, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, position: "relative" };
922
922
  if (columnWrapperStyle && numColumns > 1) {
@@ -945,7 +945,6 @@ var Containers = typedMemo(function Containers2({
945
945
  horizontal,
946
946
  recycleItems,
947
947
  ItemSeparatorComponent,
948
- waitForInitialLayout,
949
948
  updateItemSize: updateItemSize2,
950
949
  getRenderedItem: getRenderedItem2,
951
950
  stickyHeaderConfig
@@ -969,7 +968,7 @@ var Containers = typedMemo(function Containers2({
969
968
  )
970
969
  );
971
970
  }
972
- return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
971
+ return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns }, containers);
973
972
  });
974
973
 
975
974
  // src/platform/StyleSheet.tsx
@@ -1420,7 +1419,6 @@ var ListComponent = typedMemo(function ListComponent2({
1420
1419
  recycleItems,
1421
1420
  ItemSeparatorComponent,
1422
1421
  alignItemsAtEnd: _alignItemsAtEnd,
1423
- waitForInitialLayout,
1424
1422
  onScroll: onScroll2,
1425
1423
  onLayout,
1426
1424
  ListHeaderComponent,
@@ -1483,7 +1481,7 @@ var ListComponent = typedMemo(function ListComponent2({
1483
1481
  height: "100%"
1484
1482
  } : {}
1485
1483
  ],
1486
- contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1484
+ contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1487
1485
  horizontal,
1488
1486
  maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
1489
1487
  onLayout,
@@ -1503,8 +1501,7 @@ var ListComponent = typedMemo(function ListComponent2({
1503
1501
  ItemSeparatorComponent,
1504
1502
  recycleItems,
1505
1503
  stickyHeaderConfig,
1506
- updateItemSize: updateItemSize2,
1507
- waitForInitialLayout
1504
+ updateItemSize: updateItemSize2
1508
1505
  }
1509
1506
  ),
1510
1507
  ListFooterComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
@@ -1617,6 +1614,13 @@ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1617
1614
  setSize(ctx, key, size);
1618
1615
  return size;
1619
1616
  }
1617
+ function getItemSizeAtIndex(ctx, index) {
1618
+ if (index === void 0 || index < 0) {
1619
+ return void 0;
1620
+ }
1621
+ const targetId = getId(ctx.state, index);
1622
+ return getItemSize(ctx, targetId, index, ctx.state.props.data[index]);
1623
+ }
1620
1624
 
1621
1625
  // src/core/calculateOffsetWithOffsetPosition.ts
1622
1626
  function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
@@ -1667,6 +1671,373 @@ function clampScrollOffset(ctx, offset, scrollTarget) {
1667
1671
  return clampedOffset;
1668
1672
  }
1669
1673
 
1674
+ // src/core/deferredPublicOnScroll.ts
1675
+ function withResolvedContentOffset(state, event, resolvedOffset) {
1676
+ return {
1677
+ ...event,
1678
+ nativeEvent: {
1679
+ ...event.nativeEvent,
1680
+ contentOffset: state.props.horizontal ? { x: resolvedOffset, y: 0 } : { x: 0, y: resolvedOffset }
1681
+ }
1682
+ };
1683
+ }
1684
+ function releaseDeferredPublicOnScroll(ctx, resolvedOffset) {
1685
+ var _a3, _b, _c, _d;
1686
+ const state = ctx.state;
1687
+ const deferredEvent = state.deferredPublicOnScrollEvent;
1688
+ state.deferredPublicOnScrollEvent = void 0;
1689
+ if (deferredEvent) {
1690
+ (_d = (_c = state.props).onScroll) == null ? void 0 : _d.call(
1691
+ _c,
1692
+ withResolvedContentOffset(
1693
+ state,
1694
+ deferredEvent,
1695
+ (_b = (_a3 = resolvedOffset != null ? resolvedOffset : state.scrollPending) != null ? _a3 : state.scroll) != null ? _b : 0
1696
+ )
1697
+ );
1698
+ }
1699
+ }
1700
+
1701
+ // src/core/initialScrollSession.ts
1702
+ var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
1703
+ function hasInitialScrollSessionCompletion(completion) {
1704
+ return !!((completion == null ? void 0 : completion.didDispatchNativeScroll) || (completion == null ? void 0 : completion.didRetrySilentInitialScroll) || (completion == null ? void 0 : completion.watchdog));
1705
+ }
1706
+ function clearInitialScrollSession(state) {
1707
+ state.initialScrollSession = void 0;
1708
+ return void 0;
1709
+ }
1710
+ function createInitialScrollSession(options) {
1711
+ const { bootstrap, completion, kind, previousDataLength } = options;
1712
+ return kind === "offset" ? {
1713
+ completion,
1714
+ kind,
1715
+ previousDataLength
1716
+ } : {
1717
+ bootstrap,
1718
+ completion,
1719
+ kind,
1720
+ previousDataLength
1721
+ };
1722
+ }
1723
+ function ensureInitialScrollSessionCompletion(state, kind = ((_b) => (_b = ((_a3) => (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind)()) != null ? _b : "bootstrap")()) {
1724
+ var _a4, _b2;
1725
+ if (!state.initialScrollSession) {
1726
+ state.initialScrollSession = createInitialScrollSession({
1727
+ completion: {},
1728
+ kind,
1729
+ previousDataLength: 0
1730
+ });
1731
+ } else if (state.initialScrollSession.kind !== kind) {
1732
+ state.initialScrollSession = createInitialScrollSession({
1733
+ bootstrap: state.initialScrollSession.kind === "bootstrap" ? state.initialScrollSession.bootstrap : void 0,
1734
+ completion: state.initialScrollSession.completion,
1735
+ kind,
1736
+ previousDataLength: state.initialScrollSession.previousDataLength
1737
+ });
1738
+ }
1739
+ (_b2 = (_a4 = state.initialScrollSession).completion) != null ? _b2 : _a4.completion = {};
1740
+ return state.initialScrollSession.completion;
1741
+ }
1742
+ var initialScrollCompletion = {
1743
+ didDispatchNativeScroll(state) {
1744
+ var _a3, _b;
1745
+ return !!((_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.didDispatchNativeScroll);
1746
+ },
1747
+ didRetrySilentInitialScroll(state) {
1748
+ var _a3, _b;
1749
+ return !!((_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.didRetrySilentInitialScroll);
1750
+ },
1751
+ markInitialScrollNativeDispatch(state) {
1752
+ ensureInitialScrollSessionCompletion(state).didDispatchNativeScroll = true;
1753
+ },
1754
+ markSilentInitialScrollRetry(state) {
1755
+ ensureInitialScrollSessionCompletion(state).didRetrySilentInitialScroll = true;
1756
+ },
1757
+ resetFlags(state) {
1758
+ if (!state.initialScrollSession) {
1759
+ return;
1760
+ }
1761
+ const completion = ensureInitialScrollSessionCompletion(state, state.initialScrollSession.kind);
1762
+ completion.didDispatchNativeScroll = void 0;
1763
+ completion.didRetrySilentInitialScroll = void 0;
1764
+ }
1765
+ };
1766
+ var initialScrollWatchdog = {
1767
+ clear(state) {
1768
+ initialScrollWatchdog.set(state, void 0);
1769
+ },
1770
+ didObserveProgress(newScroll, watchdog) {
1771
+ const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
1772
+ const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
1773
+ return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET || nextDistance + INITIAL_SCROLL_MIN_TARGET_OFFSET < previousDistance;
1774
+ },
1775
+ get(state) {
1776
+ var _a3, _b;
1777
+ return (_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.watchdog;
1778
+ },
1779
+ hasNonZeroTargetOffset(targetOffset) {
1780
+ return targetOffset !== void 0 && targetOffset > INITIAL_SCROLL_MIN_TARGET_OFFSET;
1781
+ },
1782
+ isAtZeroTargetOffset(targetOffset) {
1783
+ return targetOffset <= INITIAL_SCROLL_MIN_TARGET_OFFSET;
1784
+ },
1785
+ set(state, watchdog) {
1786
+ var _a3, _b;
1787
+ if (!watchdog && !((_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.watchdog)) {
1788
+ return;
1789
+ }
1790
+ const completion = ensureInitialScrollSessionCompletion(state);
1791
+ completion.watchdog = watchdog ? {
1792
+ startScroll: watchdog.startScroll,
1793
+ targetOffset: watchdog.targetOffset
1794
+ } : void 0;
1795
+ }
1796
+ };
1797
+ function setInitialScrollSession(state, options = {}) {
1798
+ var _a3, _b, _c;
1799
+ const existingSession = state.initialScrollSession;
1800
+ const kind = (_a3 = options.kind) != null ? _a3 : existingSession == null ? void 0 : existingSession.kind;
1801
+ const completion = existingSession == null ? void 0 : existingSession.completion;
1802
+ const hasBootstrapOverride = Object.hasOwn(options, "bootstrap");
1803
+ const bootstrap = kind === "bootstrap" ? hasBootstrapOverride ? options.bootstrap : (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0 : void 0;
1804
+ if (!kind) {
1805
+ return clearInitialScrollSession(state);
1806
+ }
1807
+ if (!state.initialScroll && !bootstrap && !hasInitialScrollSessionCompletion(completion)) {
1808
+ return clearInitialScrollSession(state);
1809
+ }
1810
+ const previousDataLength = (_c = (_b = options.previousDataLength) != null ? _b : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _c : 0;
1811
+ state.initialScrollSession = createInitialScrollSession({
1812
+ bootstrap,
1813
+ completion,
1814
+ kind,
1815
+ previousDataLength
1816
+ });
1817
+ return state.initialScrollSession;
1818
+ }
1819
+
1820
+ // src/core/finishScrollTo.ts
1821
+ function finishScrollTo(ctx) {
1822
+ var _a3, _b;
1823
+ const state = ctx.state;
1824
+ if (state == null ? void 0 : state.scrollingTo) {
1825
+ const resolvePendingScroll = state.pendingScrollResolve;
1826
+ state.pendingScrollResolve = void 0;
1827
+ const scrollingTo = state.scrollingTo;
1828
+ state.scrollHistory.length = 0;
1829
+ state.scrollingTo = void 0;
1830
+ if (state.pendingTotalSize !== void 0) {
1831
+ addTotalSize(ctx, null, state.pendingTotalSize);
1832
+ }
1833
+ {
1834
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1835
+ }
1836
+ if (scrollingTo.isInitialScroll || state.initialScroll) {
1837
+ const isOffsetSession = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
1838
+ finishInitialScroll(ctx, {
1839
+ onFinished: resolvePendingScroll,
1840
+ preserveTarget: isOffsetSession && state.props.data.length === 0 || !!scrollingTo.isInitialScroll && !!((_b = state.initialScroll) == null ? void 0 : _b.preserveForFooterLayout),
1841
+ recalculateItems: true,
1842
+ syncObservedOffset: isOffsetSession,
1843
+ waitForCompletionFrame: !!scrollingTo.waitForInitialScrollCompletionFrame
1844
+ });
1845
+ return;
1846
+ }
1847
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
1848
+ }
1849
+ }
1850
+
1851
+ // src/core/doScrollTo.ts
1852
+ var SCROLL_END_IDLE_MS = 80;
1853
+ var SCROLL_END_MAX_MS = 1500;
1854
+ var SMOOTH_SCROLL_DURATION_MS = 320;
1855
+ var SCROLL_END_TARGET_EPSILON = 1;
1856
+ function doScrollTo(ctx, params) {
1857
+ const state = ctx.state;
1858
+ const { animated, horizontal, offset } = params;
1859
+ const scroller = state.refScroller.current;
1860
+ const node = scroller == null ? void 0 : scroller.getScrollableNode();
1861
+ if (!scroller || !node) {
1862
+ return;
1863
+ }
1864
+ const isAnimated = !!animated;
1865
+ const isHorizontal = !!horizontal;
1866
+ const left = isHorizontal ? offset : 0;
1867
+ const top = isHorizontal ? 0 : offset;
1868
+ scroller.scrollTo({ animated: isAnimated, x: left, y: top });
1869
+ if (isAnimated) {
1870
+ const target = scroller.getScrollEventTarget();
1871
+ listenForScrollEnd(ctx, {
1872
+ readOffset: () => scroller.getCurrentScrollOffset(),
1873
+ target,
1874
+ targetOffset: offset
1875
+ });
1876
+ } else {
1877
+ state.scroll = offset;
1878
+ setTimeout(() => {
1879
+ finishScrollTo(ctx);
1880
+ }, 100);
1881
+ }
1882
+ }
1883
+ function listenForScrollEnd(ctx, params) {
1884
+ const { readOffset, target, targetOffset } = params;
1885
+ if (!target) {
1886
+ finishScrollTo(ctx);
1887
+ return;
1888
+ }
1889
+ const supportsScrollEnd = "onscrollend" in target;
1890
+ let idleTimeout;
1891
+ let settled = false;
1892
+ const targetToken = ctx.state.scrollingTo;
1893
+ const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1894
+ const cleanup = () => {
1895
+ target.removeEventListener("scroll", onScroll2);
1896
+ if (supportsScrollEnd) {
1897
+ target.removeEventListener("scrollend", onScrollEnd);
1898
+ }
1899
+ if (idleTimeout) {
1900
+ clearTimeout(idleTimeout);
1901
+ }
1902
+ clearTimeout(maxTimeout);
1903
+ };
1904
+ const finish = (reason) => {
1905
+ if (settled) return;
1906
+ if (targetToken !== ctx.state.scrollingTo) {
1907
+ settled = true;
1908
+ cleanup();
1909
+ return;
1910
+ }
1911
+ const currentOffset = readOffset();
1912
+ const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
1913
+ if (reason === "scrollend" && !isNearTarget) {
1914
+ return;
1915
+ }
1916
+ settled = true;
1917
+ cleanup();
1918
+ finishScrollTo(ctx);
1919
+ };
1920
+ const onScroll2 = () => {
1921
+ if (idleTimeout) {
1922
+ clearTimeout(idleTimeout);
1923
+ }
1924
+ idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
1925
+ };
1926
+ const onScrollEnd = () => finish("scrollend");
1927
+ target.addEventListener("scroll", onScroll2);
1928
+ if (supportsScrollEnd) {
1929
+ target.addEventListener("scrollend", onScrollEnd);
1930
+ } else {
1931
+ idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1932
+ }
1933
+ }
1934
+
1935
+ // src/core/scrollTo.ts
1936
+ function syncInitialScrollNativeWatchdog(state, options) {
1937
+ var _a3;
1938
+ const { isInitialScroll, requestedOffset, targetOffset } = options;
1939
+ const existingWatchdog = initialScrollWatchdog.get(state);
1940
+ const shouldWatchInitialNativeScroll = !state.didFinishInitialScroll && (isInitialScroll || !!existingWatchdog) && initialScrollWatchdog.hasNonZeroTargetOffset(targetOffset);
1941
+ const shouldClearInitialNativeScrollWatchdog = !state.didFinishInitialScroll && !!existingWatchdog && initialScrollWatchdog.isAtZeroTargetOffset(requestedOffset);
1942
+ if (shouldWatchInitialNativeScroll) {
1943
+ state.hasScrolled = false;
1944
+ initialScrollWatchdog.set(state, {
1945
+ startScroll: (_a3 = existingWatchdog == null ? void 0 : existingWatchdog.startScroll) != null ? _a3 : state.scroll,
1946
+ targetOffset
1947
+ });
1948
+ return;
1949
+ }
1950
+ if (shouldClearInitialNativeScrollWatchdog) {
1951
+ initialScrollWatchdog.clear(state);
1952
+ }
1953
+ }
1954
+ function scrollTo(ctx, params) {
1955
+ var _a3;
1956
+ const state = ctx.state;
1957
+ const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1958
+ const {
1959
+ animated,
1960
+ isInitialScroll,
1961
+ offset: scrollTargetOffset,
1962
+ precomputedWithViewOffset,
1963
+ waitForInitialScrollCompletionFrame
1964
+ } = scrollTarget;
1965
+ const {
1966
+ props: { horizontal }
1967
+ } = state;
1968
+ if (state.animFrameCheckFinishedScroll) {
1969
+ cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1970
+ }
1971
+ if (state.timeoutCheckFinishedScrollFallback) {
1972
+ clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
1973
+ }
1974
+ const requestedOffset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1975
+ const shouldPreserveRawInitialOffsetRequest = !!isInitialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
1976
+ const targetOffset = clampScrollOffset(ctx, requestedOffset, scrollTarget);
1977
+ const offset = shouldPreserveRawInitialOffsetRequest ? requestedOffset : targetOffset;
1978
+ state.scrollHistory.length = 0;
1979
+ if (!noScrollingTo) {
1980
+ if (isInitialScroll) {
1981
+ initialScrollCompletion.resetFlags(state);
1982
+ }
1983
+ state.scrollingTo = {
1984
+ ...scrollTarget,
1985
+ targetOffset,
1986
+ waitForInitialScrollCompletionFrame
1987
+ };
1988
+ }
1989
+ state.scrollPending = targetOffset;
1990
+ syncInitialScrollNativeWatchdog(state, { isInitialScroll, requestedOffset: offset, targetOffset });
1991
+ if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1992
+ doScrollTo(ctx, { animated, horizontal, offset });
1993
+ } else {
1994
+ state.scroll = offset;
1995
+ }
1996
+ }
1997
+
1998
+ // src/core/scrollToIndex.ts
1999
+ function clampScrollIndex(index, dataLength) {
2000
+ if (dataLength <= 0) {
2001
+ return -1;
2002
+ }
2003
+ if (index >= dataLength) {
2004
+ return dataLength - 1;
2005
+ }
2006
+ if (index < 0) {
2007
+ return 0;
2008
+ }
2009
+ return index;
2010
+ }
2011
+ function scrollToIndex(ctx, {
2012
+ index,
2013
+ viewOffset = 0,
2014
+ animated = true,
2015
+ forceScroll,
2016
+ isInitialScroll,
2017
+ viewPosition
2018
+ }) {
2019
+ const state = ctx.state;
2020
+ const { data } = state.props;
2021
+ index = clampScrollIndex(index, data.length);
2022
+ const itemSize = getItemSizeAtIndex(ctx, index);
2023
+ const firstIndexOffset = calculateOffsetForIndex(ctx, index);
2024
+ const isLast = index === data.length - 1;
2025
+ if (isLast && viewPosition === void 0) {
2026
+ viewPosition = 1;
2027
+ }
2028
+ state.scrollForNextCalculateItemsInView = void 0;
2029
+ scrollTo(ctx, {
2030
+ animated,
2031
+ forceScroll,
2032
+ index,
2033
+ isInitialScroll,
2034
+ itemSize,
2035
+ offset: firstIndexOffset,
2036
+ viewOffset,
2037
+ viewPosition: viewPosition != null ? viewPosition : 0
2038
+ });
2039
+ }
2040
+
1670
2041
  // src/utils/checkThreshold.ts
1671
2042
  var HYSTERESIS_MULTIPLIER = 1.3;
1672
2043
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot, allowReentryOnChange) => {
@@ -1835,202 +2206,867 @@ function setInitialRenderState(ctx, {
1835
2206
  }
1836
2207
  }
1837
2208
 
1838
- // src/core/finishScrollTo.ts
1839
- function finishScrollTo(ctx) {
1840
- var _a3, _b;
2209
+ // src/core/initialScroll.ts
2210
+ function syncInitialScrollOffset(state, offset) {
2211
+ state.scroll = offset;
2212
+ state.scrollPending = offset;
2213
+ state.scrollPrev = offset;
2214
+ }
2215
+ function dispatchInitialScroll(ctx, params) {
2216
+ const { forceScroll, resolvedOffset, target, waitForCompletionFrame } = params;
2217
+ const requestedIndex = target.index;
2218
+ const index = requestedIndex !== void 0 ? clampScrollIndex(requestedIndex, ctx.state.props.data.length) : void 0;
2219
+ const itemSize = getItemSizeAtIndex(ctx, index);
2220
+ scrollTo(ctx, {
2221
+ animated: false,
2222
+ forceScroll,
2223
+ index: index !== void 0 && index >= 0 ? index : void 0,
2224
+ isInitialScroll: true,
2225
+ itemSize,
2226
+ offset: resolvedOffset,
2227
+ precomputedWithViewOffset: true,
2228
+ viewOffset: target.viewOffset,
2229
+ viewPosition: target.viewPosition,
2230
+ waitForInitialScrollCompletionFrame: waitForCompletionFrame
2231
+ });
2232
+ }
2233
+ function setInitialScrollTarget(state, target, options) {
2234
+ var _a3;
2235
+ state.initialScroll = target;
2236
+ if ((options == null ? void 0 : options.resetDidFinish) && state.didFinishInitialScroll) {
2237
+ state.didFinishInitialScroll = false;
2238
+ }
2239
+ setInitialScrollSession(state, {
2240
+ kind: ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset" ? "offset" : "bootstrap"
2241
+ });
2242
+ }
2243
+ function finishInitialScroll(ctx, options) {
2244
+ var _a3, _b, _c;
1841
2245
  const state = ctx.state;
1842
- if (state == null ? void 0 : state.scrollingTo) {
1843
- const resolvePendingScroll = state.pendingScrollResolve;
1844
- state.pendingScrollResolve = void 0;
1845
- const scrollingTo = state.scrollingTo;
1846
- state.scrollHistory.length = 0;
1847
- state.initialScroll = void 0;
1848
- state.initialScrollUsesOffset = false;
1849
- state.initialAnchor = void 0;
1850
- state.initialNativeScrollWatchdog = void 0;
1851
- state.scrollingTo = void 0;
1852
- if (state.pendingTotalSize !== void 0) {
1853
- addTotalSize(ctx, null, state.pendingTotalSize);
1854
- }
1855
- if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1856
- (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1857
- }
1858
- {
1859
- state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
2246
+ if ((options == null ? void 0 : options.resolvedOffset) !== void 0) {
2247
+ syncInitialScrollOffset(state, options.resolvedOffset);
2248
+ } else if ((options == null ? void 0 : options.syncObservedOffset) && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset") {
2249
+ const observedOffset = (_c = (_b = state.refScroller.current) == null ? void 0 : _b.getCurrentScrollOffset) == null ? void 0 : _c.call(_b);
2250
+ if (typeof observedOffset === "number" && Number.isFinite(observedOffset)) {
2251
+ syncInitialScrollOffset(state, observedOffset);
2252
+ }
2253
+ }
2254
+ const complete = () => {
2255
+ var _a4, _b2, _c2, _d, _e, _f, _g;
2256
+ const shouldReleaseDeferredPublicOnScroll = ((_a4 = state.initialScrollSession) == null ? void 0 : _a4.kind) === "bootstrap";
2257
+ const finalScrollOffset = (_d = (_c2 = (_b2 = options == null ? void 0 : options.resolvedOffset) != null ? _b2 : state.scrollPending) != null ? _c2 : state.scroll) != null ? _d : 0;
2258
+ initialScrollWatchdog.clear(state);
2259
+ if (!(options == null ? void 0 : options.preserveTarget)) {
2260
+ state.initialScroll = void 0;
2261
+ }
2262
+ setInitialScrollSession(state);
2263
+ if ((options == null ? void 0 : options.recalculateItems) && ((_e = state.props) == null ? void 0 : _e.data)) {
2264
+ (_f = state.triggerCalculateItemsInView) == null ? void 0 : _f.call(state, { forceFullItemPositions: true });
2265
+ }
2266
+ if (options == null ? void 0 : options.recalculateItems) {
2267
+ checkThresholds(ctx);
1860
2268
  }
1861
2269
  setInitialRenderState(ctx, { didInitialScroll: true });
1862
- checkThresholds(ctx);
1863
- resolvePendingScroll == null ? void 0 : resolvePendingScroll();
2270
+ if (shouldReleaseDeferredPublicOnScroll) {
2271
+ releaseDeferredPublicOnScroll(ctx, finalScrollOffset);
2272
+ }
2273
+ (_g = options == null ? void 0 : options.onFinished) == null ? void 0 : _g.call(options);
2274
+ };
2275
+ if (options == null ? void 0 : options.waitForCompletionFrame) {
2276
+ requestAnimationFrame(complete);
2277
+ return;
1864
2278
  }
2279
+ complete();
1865
2280
  }
1866
-
1867
- // src/core/doScrollTo.ts
1868
- var SCROLL_END_IDLE_MS = 80;
1869
- var SCROLL_END_MAX_MS = 1500;
1870
- var SMOOTH_SCROLL_DURATION_MS = 320;
1871
- var SCROLL_END_TARGET_EPSILON = 1;
1872
- function doScrollTo(ctx, params) {
2281
+ function resolveInitialScrollOffset(ctx, initialScroll) {
2282
+ var _a3, _b;
1873
2283
  const state = ctx.state;
1874
- const { animated, horizontal, offset } = params;
1875
- const scroller = state.refScroller.current;
1876
- const node = scroller == null ? void 0 : scroller.getScrollableNode();
1877
- if (!scroller || !node) {
2284
+ if (((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset") {
2285
+ return (_b = initialScroll.contentOffset) != null ? _b : 0;
2286
+ }
2287
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
2288
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
2289
+ return clampScrollOffset(ctx, resolvedOffset, initialScroll);
2290
+ }
2291
+ function getAdvanceableInitialScrollState(state, options) {
2292
+ const { didFinishInitialScroll, queuedInitialLayout, scrollingTo } = state;
2293
+ const initialScroll = state.initialScroll;
2294
+ const isInitialScrollInProgress = !!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll);
2295
+ const shouldWaitForInitialLayout = !!(options == null ? void 0 : options.requiresMeasuredLayout) && !queuedInitialLayout && !isInitialScrollInProgress;
2296
+ if (!initialScroll || shouldWaitForInitialLayout || didFinishInitialScroll || scrollingTo && !isInitialScrollInProgress) {
2297
+ return void 0;
2298
+ }
2299
+ return {
2300
+ initialScroll,
2301
+ isInitialScrollInProgress,
2302
+ queuedInitialLayout,
2303
+ scrollingTo
2304
+ };
2305
+ }
2306
+ function advanceMeasuredInitialScroll(ctx, options) {
2307
+ var _a3, _b, _c;
2308
+ const state = ctx.state;
2309
+ const advanceableState = getAdvanceableInitialScrollState(state, {
2310
+ requiresMeasuredLayout: true
2311
+ });
2312
+ if (!advanceableState) {
2313
+ return false;
2314
+ }
2315
+ const { initialScroll, isInitialScrollInProgress, queuedInitialLayout } = advanceableState;
2316
+ const scrollingTo = isInitialScrollInProgress ? advanceableState.scrollingTo : void 0;
2317
+ const resolvedOffset = resolveInitialScrollOffset(ctx, initialScroll);
2318
+ const activeInitialTargetOffset = scrollingTo ? (_a3 = scrollingTo.targetOffset) != null ? _a3 : scrollingTo.offset : void 0;
2319
+ const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - resolvedOffset) > 1;
2320
+ const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - resolvedOffset) > 1;
2321
+ const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - activeInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - activeInitialTargetOffset) <= 1;
2322
+ if (!(options == null ? void 0 : options.forceScroll) && !didOffsetChange && isInitialScrollInProgress && !didActiveInitialTargetChange) {
2323
+ return false;
2324
+ }
2325
+ if ((options == null ? void 0 : options.forceScroll) && isAlreadyAtDesiredInitialTarget) {
2326
+ return false;
2327
+ }
2328
+ if (didOffsetChange && ((_b = state.initialScrollSession) == null ? void 0 : _b.kind) !== "offset") {
2329
+ setInitialScrollTarget(state, { ...initialScroll, contentOffset: resolvedOffset });
2330
+ }
2331
+ const forceScroll = (_c = options == null ? void 0 : options.forceScroll) != null ? _c : !!queuedInitialLayout || isInitialScrollInProgress && didOffsetChange;
2332
+ dispatchInitialScroll(ctx, {
2333
+ forceScroll,
2334
+ resolvedOffset,
2335
+ target: initialScroll
2336
+ });
2337
+ return true;
2338
+ }
2339
+ function advanceOffsetInitialScroll(ctx, options) {
2340
+ var _a3, _b;
2341
+ const state = ctx.state;
2342
+ const advanceableState = getAdvanceableInitialScrollState(state);
2343
+ if (!advanceableState) {
2344
+ return false;
2345
+ }
2346
+ const { initialScroll, queuedInitialLayout } = advanceableState;
2347
+ const resolvedOffset = (_a3 = initialScroll.contentOffset) != null ? _a3 : 0;
2348
+ const isAlreadyAtDesiredInitialTarget = Math.abs(state.scroll - resolvedOffset) <= 1 && Math.abs(state.scrollPending - resolvedOffset) <= 1;
2349
+ if ((options == null ? void 0 : options.forceScroll) && isAlreadyAtDesiredInitialTarget) {
2350
+ return false;
2351
+ }
2352
+ const hasMeasuredScrollLayout = !!state.lastLayout && state.scrollLength > 0;
2353
+ const forceScroll = (_b = options == null ? void 0 : options.forceScroll) != null ? _b : hasMeasuredScrollLayout || !!queuedInitialLayout;
2354
+ dispatchInitialScroll(ctx, {
2355
+ forceScroll,
2356
+ resolvedOffset,
2357
+ target: initialScroll
2358
+ });
2359
+ return true;
2360
+ }
2361
+ function advanceCurrentInitialScrollSession(ctx, options) {
2362
+ var _a3;
2363
+ return ((_a3 = ctx.state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset" ? advanceOffsetInitialScroll(ctx, {
2364
+ forceScroll: options == null ? void 0 : options.forceScroll
2365
+ }) : advanceMeasuredInitialScroll(ctx, {
2366
+ forceScroll: options == null ? void 0 : options.forceScroll
2367
+ });
2368
+ }
2369
+
2370
+ // src/utils/checkAllSizesKnown.ts
2371
+ function isNullOrUndefined2(value) {
2372
+ return value === null || value === void 0;
2373
+ }
2374
+ function getMountedBufferedIndices(state) {
2375
+ const { startBuffered, endBuffered } = state;
2376
+ if (!isNullOrUndefined2(endBuffered) && !isNullOrUndefined2(startBuffered) && startBuffered >= 0 && endBuffered >= 0) {
2377
+ 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);
2378
+ }
2379
+ return [];
2380
+ }
2381
+ function checkAllSizesKnown(state, indices = getMountedBufferedIndices(state)) {
2382
+ return indices.length > 0 && indices.every((index) => {
2383
+ const key = getId(state, index);
2384
+ return state.sizesKnown.has(key);
2385
+ });
2386
+ }
2387
+
2388
+ // src/core/bootstrapInitialScroll.ts
2389
+ var DEFAULT_BOOTSTRAP_REVEAL_EPSILON = 1;
2390
+ var DEFAULT_BOOTSTRAP_REVEAL_MAX_FRAMES = 8;
2391
+ var DEFAULT_BOOTSTRAP_REVEAL_MAX_PASSES = 24;
2392
+ var BOOTSTRAP_REVEAL_ABORT_WARNING = "LegendList bootstrap initial scroll aborted after exceeding convergence bounds.";
2393
+ function getBootstrapInitialScrollSession(state) {
2394
+ var _a3;
2395
+ return ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
2396
+ }
2397
+ function isOffsetInitialScrollSession(state) {
2398
+ var _a3;
2399
+ return ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2400
+ }
2401
+ function doVisibleIndicesMatch(previous, next) {
2402
+ if (!previous || previous.length !== next.length) {
2403
+ return false;
2404
+ }
2405
+ for (let i = 0; i < previous.length; i++) {
2406
+ if (previous[i] !== next[i]) {
2407
+ return false;
2408
+ }
2409
+ }
2410
+ return true;
2411
+ }
2412
+ function getBootstrapRevealVisibleIndices(options) {
2413
+ const { dataLength, getSize, offset, positions, scrollLength, startIndex: requestedStartIndex } = options;
2414
+ const endOffset = offset + scrollLength;
2415
+ const visibleIndices = [];
2416
+ let index = requestedStartIndex !== void 0 ? Math.max(0, Math.min(dataLength - 1, requestedStartIndex)) : 0;
2417
+ while (index > 0) {
2418
+ const previousIndex = index - 1;
2419
+ const previousPosition = positions[previousIndex];
2420
+ if (previousPosition === void 0) {
2421
+ index = previousIndex;
2422
+ continue;
2423
+ }
2424
+ const previousSize = getSize(previousIndex);
2425
+ if (previousSize === void 0) {
2426
+ index = previousIndex;
2427
+ continue;
2428
+ }
2429
+ if (previousPosition + previousSize <= offset) {
2430
+ break;
2431
+ }
2432
+ index = previousIndex;
2433
+ }
2434
+ for (; index < dataLength; index++) {
2435
+ const position = positions[index];
2436
+ if (position === void 0) {
2437
+ continue;
2438
+ }
2439
+ const size = getSize(index);
2440
+ if (size === void 0) {
2441
+ continue;
2442
+ }
2443
+ if (position < endOffset && position + size > offset) {
2444
+ visibleIndices.push(index);
2445
+ } else if (visibleIndices.length > 0 && position >= endOffset) {
2446
+ break;
2447
+ }
2448
+ }
2449
+ return visibleIndices;
2450
+ }
2451
+ function shouldAbortBootstrapReveal(options) {
2452
+ const {
2453
+ mountFrameCount,
2454
+ maxFrames = DEFAULT_BOOTSTRAP_REVEAL_MAX_FRAMES,
2455
+ maxPasses = DEFAULT_BOOTSTRAP_REVEAL_MAX_PASSES,
2456
+ passCount
2457
+ } = options;
2458
+ return mountFrameCount >= maxFrames || passCount >= maxPasses;
2459
+ }
2460
+ function abortBootstrapRevealIfNeeded(ctx, options) {
2461
+ if (!shouldAbortBootstrapReveal(options)) {
2462
+ return false;
2463
+ }
2464
+ if (IS_DEV) {
2465
+ console.warn(BOOTSTRAP_REVEAL_ABORT_WARNING);
2466
+ }
2467
+ abortBootstrapInitialScroll(ctx);
2468
+ return true;
2469
+ }
2470
+ function clearBootstrapInitialScrollSession(state) {
2471
+ var _a3;
2472
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2473
+ const frameHandle = bootstrapInitialScroll == null ? void 0 : bootstrapInitialScroll.frameHandle;
2474
+ if (frameHandle !== void 0 && typeof cancelAnimationFrame === "function") {
2475
+ cancelAnimationFrame(frameHandle);
2476
+ }
2477
+ if (bootstrapInitialScroll) {
2478
+ bootstrapInitialScroll.frameHandle = void 0;
2479
+ }
2480
+ setInitialScrollSession(state, {
2481
+ bootstrap: void 0,
2482
+ kind: (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind
2483
+ });
2484
+ }
2485
+ function startBootstrapInitialScrollSession(state, options) {
2486
+ var _a3, _b, _c;
2487
+ const previousBootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2488
+ setInitialScrollSession(state, {
2489
+ bootstrap: {
2490
+ frameHandle: previousBootstrapInitialScroll == null ? void 0 : previousBootstrapInitialScroll.frameHandle,
2491
+ // Re-arming during the initial mount should spend from the same watchdog budget.
2492
+ mountFrameCount: (_a3 = previousBootstrapInitialScroll == null ? void 0 : previousBootstrapInitialScroll.mountFrameCount) != null ? _a3 : 0,
2493
+ passCount: 0,
2494
+ previousResolvedOffset: void 0,
2495
+ scroll: options.scroll,
2496
+ seedContentOffset: (_c = (_b = options.seedContentOffset) != null ? _b : previousBootstrapInitialScroll == null ? void 0 : previousBootstrapInitialScroll.seedContentOffset) != null ? _c : options.scroll,
2497
+ targetIndexSeed: options.targetIndexSeed,
2498
+ visibleIndices: void 0
2499
+ },
2500
+ kind: "bootstrap"
2501
+ });
2502
+ }
2503
+ function resetBootstrapInitialScrollSession(state, options) {
2504
+ var _a3, _b, _c;
2505
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2506
+ if (!bootstrapInitialScroll) {
2507
+ if ((options == null ? void 0 : options.scroll) !== void 0) {
2508
+ startBootstrapInitialScrollSession(state, {
2509
+ scroll: options.scroll,
2510
+ seedContentOffset: options.seedContentOffset,
2511
+ targetIndexSeed: options.targetIndexSeed
2512
+ });
2513
+ }
2514
+ } else {
2515
+ bootstrapInitialScroll.passCount = 0;
2516
+ bootstrapInitialScroll.previousResolvedOffset = void 0;
2517
+ bootstrapInitialScroll.scroll = (_a3 = options == null ? void 0 : options.scroll) != null ? _a3 : bootstrapInitialScroll.scroll;
2518
+ bootstrapInitialScroll.seedContentOffset = (_b = options == null ? void 0 : options.seedContentOffset) != null ? _b : bootstrapInitialScroll.seedContentOffset;
2519
+ bootstrapInitialScroll.targetIndexSeed = (_c = options == null ? void 0 : options.targetIndexSeed) != null ? _c : bootstrapInitialScroll.targetIndexSeed;
2520
+ bootstrapInitialScroll.visibleIndices = void 0;
2521
+ setInitialScrollSession(state, {
2522
+ bootstrap: bootstrapInitialScroll,
2523
+ kind: "bootstrap"
2524
+ });
2525
+ }
2526
+ }
2527
+ function queueBootstrapInitialScrollReevaluation(state) {
2528
+ requestAnimationFrame(() => {
2529
+ var _a3;
2530
+ if (getBootstrapInitialScrollSession(state)) {
2531
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { forceFullItemPositions: true });
2532
+ }
2533
+ });
2534
+ }
2535
+ function ensureBootstrapInitialScrollFrameTicker(ctx) {
2536
+ const state = ctx.state;
2537
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2538
+ if (!bootstrapInitialScroll || bootstrapInitialScroll.frameHandle !== void 0) {
1878
2539
  return;
1879
2540
  }
1880
- const isAnimated = !!animated;
1881
- const isHorizontal = !!horizontal;
1882
- const left = isHorizontal ? offset : 0;
1883
- const top = isHorizontal ? 0 : offset;
1884
- scroller.scrollTo({ animated: isAnimated, x: left, y: top });
1885
- if (isAnimated) {
1886
- const target = scroller.getScrollEventTarget();
1887
- listenForScrollEnd(ctx, {
1888
- readOffset: () => scroller.getCurrentScrollOffset(),
1889
- target,
1890
- targetOffset: offset
2541
+ const tick = () => {
2542
+ const activeBootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2543
+ if (!activeBootstrapInitialScroll) {
2544
+ return;
2545
+ }
2546
+ activeBootstrapInitialScroll.frameHandle = void 0;
2547
+ activeBootstrapInitialScroll.mountFrameCount += 1;
2548
+ if (abortBootstrapRevealIfNeeded(ctx, {
2549
+ mountFrameCount: activeBootstrapInitialScroll.mountFrameCount,
2550
+ passCount: activeBootstrapInitialScroll.passCount
2551
+ })) {
2552
+ return;
2553
+ }
2554
+ ensureBootstrapInitialScrollFrameTicker(ctx);
2555
+ };
2556
+ bootstrapInitialScroll.frameHandle = requestAnimationFrame(tick);
2557
+ }
2558
+ function rearmBootstrapInitialScroll(ctx, options) {
2559
+ resetBootstrapInitialScrollSession(ctx.state, options);
2560
+ ensureBootstrapInitialScrollFrameTicker(ctx);
2561
+ queueBootstrapInitialScrollReevaluation(ctx.state);
2562
+ }
2563
+ function createInitialScrollAtEndTarget(options) {
2564
+ const { dataLength, footerSize, preserveForFooterLayout, stylePaddingBottom } = options;
2565
+ return {
2566
+ contentOffset: void 0,
2567
+ index: Math.max(0, dataLength - 1),
2568
+ preserveForBottomPadding: true,
2569
+ preserveForFooterLayout,
2570
+ viewOffset: -stylePaddingBottom - footerSize,
2571
+ viewPosition: 1
2572
+ };
2573
+ }
2574
+ function shouldPreserveInitialScrollForBottomPadding(target) {
2575
+ return !!(target == null ? void 0 : target.preserveForBottomPadding);
2576
+ }
2577
+ function shouldPreserveInitialScrollForFooterLayout(target) {
2578
+ return !!(target == null ? void 0 : target.preserveForFooterLayout);
2579
+ }
2580
+ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2581
+ return !!(target && target.viewPosition === 1 && (shouldPreserveInitialScrollForBottomPadding(target) || shouldPreserveInitialScrollForFooterLayout(target)));
2582
+ }
2583
+ function createRetargetedBottomAlignedInitialScroll(options) {
2584
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom, target } = options;
2585
+ const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2586
+ return {
2587
+ ...target,
2588
+ contentOffset: void 0,
2589
+ index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2590
+ preserveForBottomPadding: true,
2591
+ preserveForFooterLayout,
2592
+ viewOffset: -stylePaddingBottom - (preserveForFooterLayout ? footerSize : 0),
2593
+ viewPosition: 1
2594
+ };
2595
+ }
2596
+ function areEquivalentBootstrapInitialScrollTargets(current, next) {
2597
+ return current.index === next.index && current.preserveForBottomPadding === next.preserveForBottomPadding && current.preserveForFooterLayout === next.preserveForFooterLayout && current.viewOffset === next.viewOffset && current.viewPosition === next.viewPosition;
2598
+ }
2599
+ function clearPendingInitialScrollFooterLayout(state, target) {
2600
+ if (!shouldPreserveInitialScrollForFooterLayout(target)) {
2601
+ return;
2602
+ }
2603
+ if (state.didFinishInitialScroll && !getBootstrapInitialScrollSession(state)) {
2604
+ state.initialScroll = void 0;
2605
+ setInitialScrollSession(state);
2606
+ return;
2607
+ }
2608
+ setInitialScrollTarget(state, { ...target, preserveForFooterLayout: void 0 });
2609
+ }
2610
+ function didFinishedInitialScrollMoveAwayFromTarget(ctx, target, epsilon = DEFAULT_BOOTSTRAP_REVEAL_EPSILON) {
2611
+ const state = ctx.state;
2612
+ if (!state.didFinishInitialScroll) {
2613
+ return false;
2614
+ }
2615
+ const currentOffset = getObservedBootstrapInitialScrollOffset(state);
2616
+ return Math.abs(currentOffset - resolveInitialScrollOffset(ctx, target)) > epsilon;
2617
+ }
2618
+ function getObservedBootstrapInitialScrollOffset(state) {
2619
+ var _a3, _b, _c, _d;
2620
+ const observedOffset = (_b = (_a3 = state.refScroller.current) == null ? void 0 : _a3.getCurrentScrollOffset) == null ? void 0 : _b.call(_a3);
2621
+ return typeof observedOffset === "number" && Number.isFinite(observedOffset) ? observedOffset : (_d = (_c = state.scrollPending) != null ? _c : state.scroll) != null ? _d : 0;
2622
+ }
2623
+ function startBootstrapInitialScrollOnMount(ctx, options) {
2624
+ var _a3, _b, _c;
2625
+ const { initialScrollAtEnd, target } = options;
2626
+ const state = ctx.state;
2627
+ const offset = resolveInitialScrollOffset(ctx, target);
2628
+ 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);
2629
+ const shouldFinishWithPreservedTarget = state.props.data.length === 0 && target.index !== void 0;
2630
+ if (shouldFinishAtOrigin) {
2631
+ clearBootstrapInitialScrollSession(state);
2632
+ finishInitialScroll(ctx, {
2633
+ resolvedOffset: offset
2634
+ });
2635
+ } else if (shouldFinishWithPreservedTarget) {
2636
+ clearBootstrapInitialScrollSession(state);
2637
+ finishInitialScroll(ctx, {
2638
+ preserveTarget: true,
2639
+ resolvedOffset: offset
1891
2640
  });
1892
2641
  } else {
1893
- state.scroll = offset;
1894
- setTimeout(() => {
1895
- finishScrollTo(ctx);
1896
- }, 100);
2642
+ startBootstrapInitialScrollSession(state, {
2643
+ scroll: offset,
2644
+ seedContentOffset: 0 ,
2645
+ targetIndexSeed: target.index
2646
+ });
2647
+ ensureBootstrapInitialScrollFrameTicker(ctx);
1897
2648
  }
1898
2649
  }
1899
- function listenForScrollEnd(ctx, params) {
1900
- const { readOffset, target, targetOffset } = params;
1901
- if (!target) {
1902
- finishScrollTo(ctx);
2650
+ function handleBootstrapInitialScrollDataChange(ctx, options) {
2651
+ const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingBottom } = options;
2652
+ const state = ctx.state;
2653
+ const initialScroll = state.initialScroll;
2654
+ if (isOffsetInitialScrollSession(state) || !initialScroll) {
1903
2655
  return;
1904
2656
  }
1905
- const supportsScrollEnd = "onscrollend" in target;
1906
- let idleTimeout;
1907
- let settled = false;
1908
- const targetToken = ctx.state.scrollingTo;
1909
- const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1910
- const cleanup = () => {
1911
- target.removeEventListener("scroll", onScroll2);
1912
- if (supportsScrollEnd) {
1913
- target.removeEventListener("scrollend", onScrollEnd);
2657
+ const shouldResetDidFinish = !!(state.didFinishInitialScroll && previousDataLength === 0 && dataLength > 0 && initialScroll.index !== void 0);
2658
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2659
+ const shouldRetargetBottomAligned = dataLength > 0 && (initialScrollAtEnd || isRetargetableBottomAlignedInitialScrollTarget(initialScroll));
2660
+ if (!didDataChange && !shouldResetDidFinish && !shouldRetargetBottomAligned) {
2661
+ return;
2662
+ }
2663
+ if (shouldRetargetBottomAligned) {
2664
+ if (!shouldResetDidFinish && didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2665
+ clearPendingInitialScrollFooterLayout(state, initialScroll);
2666
+ return;
1914
2667
  }
1915
- if (idleTimeout) {
1916
- clearTimeout(idleTimeout);
2668
+ const updatedInitialScroll = initialScrollAtEnd ? createInitialScrollAtEndTarget({
2669
+ dataLength,
2670
+ footerSize: peek$(ctx, "footerSize") || 0,
2671
+ preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2672
+ stylePaddingBottom
2673
+ }) : createRetargetedBottomAlignedInitialScroll({
2674
+ dataLength,
2675
+ footerSize: peek$(ctx, "footerSize") || 0,
2676
+ initialScrollAtEnd,
2677
+ stylePaddingBottom,
2678
+ target: initialScroll
2679
+ });
2680
+ if (!areEquivalentBootstrapInitialScrollTargets(initialScroll, updatedInitialScroll) || !!bootstrapInitialScroll || shouldResetDidFinish || didDataChange) {
2681
+ setInitialScrollTarget(state, updatedInitialScroll, {
2682
+ resetDidFinish: shouldResetDidFinish
2683
+ });
2684
+ rearmBootstrapInitialScroll(ctx, {
2685
+ scroll: resolveInitialScrollOffset(ctx, updatedInitialScroll),
2686
+ seedContentOffset: shouldResetDidFinish && !bootstrapInitialScroll ? getObservedBootstrapInitialScrollOffset(state) : void 0,
2687
+ targetIndexSeed: updatedInitialScroll.index
2688
+ });
2689
+ return;
1917
2690
  }
1918
- clearTimeout(maxTimeout);
1919
- };
1920
- const finish = (reason) => {
1921
- if (settled) return;
1922
- if (targetToken !== ctx.state.scrollingTo) {
1923
- settled = true;
1924
- cleanup();
2691
+ }
2692
+ if (!didDataChange) {
2693
+ return;
2694
+ }
2695
+ if (bootstrapInitialScroll || shouldResetDidFinish) {
2696
+ setInitialScrollTarget(state, initialScroll, {
2697
+ resetDidFinish: shouldResetDidFinish
2698
+ });
2699
+ rearmBootstrapInitialScroll(ctx, {
2700
+ scroll: resolveInitialScrollOffset(ctx, initialScroll),
2701
+ seedContentOffset: shouldResetDidFinish && !bootstrapInitialScroll ? getObservedBootstrapInitialScrollOffset(state) : void 0,
2702
+ targetIndexSeed: initialScroll.index
2703
+ });
2704
+ }
2705
+ }
2706
+ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2707
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom } = options;
2708
+ const state = ctx.state;
2709
+ if (!initialScrollAtEnd) {
2710
+ return;
2711
+ }
2712
+ const initialScroll = state.initialScroll;
2713
+ if (isOffsetInitialScrollSession(state) || dataLength === 0 || !initialScroll) {
2714
+ return;
2715
+ }
2716
+ const shouldProcessFooterLayout = !!getBootstrapInitialScrollSession(state) || shouldPreserveInitialScrollForFooterLayout(initialScroll);
2717
+ if (!shouldProcessFooterLayout) {
2718
+ return;
2719
+ }
2720
+ if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2721
+ clearPendingInitialScrollFooterLayout(state, initialScroll);
2722
+ } else {
2723
+ const updatedInitialScroll = createInitialScrollAtEndTarget({
2724
+ dataLength,
2725
+ footerSize,
2726
+ preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2727
+ stylePaddingBottom
2728
+ });
2729
+ const didTargetChange = initialScroll.index !== updatedInitialScroll.index || initialScroll.viewPosition !== updatedInitialScroll.viewPosition || initialScroll.viewOffset !== updatedInitialScroll.viewOffset;
2730
+ if (!didTargetChange) {
2731
+ clearPendingInitialScrollFooterLayout(state, initialScroll);
2732
+ } else {
2733
+ setInitialScrollTarget(state, updatedInitialScroll, {
2734
+ resetDidFinish: !!state.didFinishInitialScroll
2735
+ });
2736
+ rearmBootstrapInitialScroll(ctx, {
2737
+ scroll: resolveInitialScrollOffset(ctx, updatedInitialScroll),
2738
+ targetIndexSeed: updatedInitialScroll.index
2739
+ });
2740
+ }
2741
+ }
2742
+ }
2743
+ function evaluateBootstrapInitialScroll(ctx) {
2744
+ var _a3, _b;
2745
+ const state = ctx.state;
2746
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2747
+ const initialScroll = state.initialScroll;
2748
+ if (!bootstrapInitialScroll || !initialScroll || isOffsetInitialScrollSession(state) || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll)) {
2749
+ return;
2750
+ }
2751
+ bootstrapInitialScroll.passCount += 1;
2752
+ if (abortBootstrapRevealIfNeeded(ctx, {
2753
+ mountFrameCount: bootstrapInitialScroll.mountFrameCount,
2754
+ passCount: bootstrapInitialScroll.passCount
2755
+ })) {
2756
+ return;
2757
+ }
2758
+ if (initialScroll.index !== void 0 && state.startBuffered >= 0 && state.endBuffered >= 0 && initialScroll.index >= state.startBuffered && initialScroll.index <= state.endBuffered) {
2759
+ bootstrapInitialScroll.targetIndexSeed = void 0;
2760
+ }
2761
+ const resolvedOffset = resolveInitialScrollOffset(ctx, initialScroll);
2762
+ const mountedBufferedIndices = getMountedBufferedIndices(state);
2763
+ const areMountedBufferedIndicesMeasured = checkAllSizesKnown(state, mountedBufferedIndices);
2764
+ const didResolvedOffsetChange = Math.abs(bootstrapInitialScroll.scroll - resolvedOffset) > 1;
2765
+ const { data } = state.props;
2766
+ const visibleIndices = getBootstrapRevealVisibleIndices({
2767
+ dataLength: data.length,
2768
+ getSize: (index) => {
2769
+ var _a4, _b2;
2770
+ const id = (_a4 = state.idCache[index]) != null ? _a4 : getId(state, index);
2771
+ return (_b2 = state.sizes.get(id)) != null ? _b2 : getItemSize(ctx, id, index, data[index]);
2772
+ },
2773
+ offset: resolvedOffset,
2774
+ positions: state.positions,
2775
+ scrollLength: state.scrollLength,
2776
+ startIndex: (_b = bootstrapInitialScroll.targetIndexSeed) != null ? _b : state.startBuffered >= 0 ? state.startBuffered : void 0
2777
+ });
2778
+ const areVisibleIndicesMeasured = visibleIndices.length > 0 && visibleIndices.every((index) => {
2779
+ var _a4;
2780
+ const id = (_a4 = state.idCache[index]) != null ? _a4 : getId(state, index);
2781
+ return state.sizesKnown.has(id);
2782
+ });
2783
+ const previousResolvedOffset = bootstrapInitialScroll.previousResolvedOffset;
2784
+ const previousVisibleIndices = bootstrapInitialScroll.visibleIndices;
2785
+ bootstrapInitialScroll.previousResolvedOffset = resolvedOffset;
2786
+ bootstrapInitialScroll.visibleIndices = visibleIndices;
2787
+ if (didResolvedOffsetChange) {
2788
+ bootstrapInitialScroll.scroll = resolvedOffset;
2789
+ queueBootstrapInitialScrollReevaluation(state);
2790
+ return;
2791
+ }
2792
+ if (!areMountedBufferedIndicesMeasured || !areVisibleIndicesMeasured) {
2793
+ return;
2794
+ }
2795
+ const didRevealSettle = previousResolvedOffset !== void 0 && Math.abs(previousResolvedOffset - resolvedOffset) <= DEFAULT_BOOTSTRAP_REVEAL_EPSILON && doVisibleIndicesMatch(previousVisibleIndices, visibleIndices);
2796
+ if (!didRevealSettle) {
2797
+ queueBootstrapInitialScrollReevaluation(state);
2798
+ return;
2799
+ }
2800
+ {
2801
+ clearBootstrapInitialScrollSession(state);
2802
+ dispatchInitialScroll(ctx, {
2803
+ forceScroll: true,
2804
+ resolvedOffset,
2805
+ target: initialScroll,
2806
+ waitForCompletionFrame: Platform.OS === "web"
2807
+ });
2808
+ }
2809
+ }
2810
+ function finishBootstrapInitialScrollWithoutScroll(ctx, resolvedOffset) {
2811
+ const state = ctx.state;
2812
+ clearBootstrapInitialScrollSession(state);
2813
+ finishInitialScroll(ctx, {
2814
+ preserveTarget: shouldPreserveInitialScrollForFooterLayout(state.initialScroll),
2815
+ recalculateItems: true,
2816
+ resolvedOffset
2817
+ });
2818
+ }
2819
+ function abortBootstrapInitialScroll(ctx) {
2820
+ var _a3, _b, _c, _d;
2821
+ const state = ctx.state;
2822
+ const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2823
+ const initialScroll = state.initialScroll;
2824
+ if (bootstrapInitialScroll && initialScroll && !isOffsetInitialScrollSession(state) && state.refScroller.current) {
2825
+ clearBootstrapInitialScrollSession(state);
2826
+ dispatchInitialScroll(ctx, {
2827
+ forceScroll: true,
2828
+ resolvedOffset: bootstrapInitialScroll.scroll,
2829
+ target: initialScroll,
2830
+ waitForCompletionFrame: Platform.OS === "web"
2831
+ });
2832
+ } else {
2833
+ finishBootstrapInitialScrollWithoutScroll(
2834
+ ctx,
2835
+ (_d = (_c = (_b = (_a3 = getBootstrapInitialScrollSession(state)) == null ? void 0 : _a3.scroll) != null ? _b : state.scrollPending) != null ? _c : state.scroll) != null ? _d : 0
2836
+ );
2837
+ }
2838
+ }
2839
+
2840
+ // src/core/checkFinishedScroll.ts
2841
+ var INITIAL_SCROLL_MAX_FALLBACK_CHECKS = 20;
2842
+ var INITIAL_SCROLL_COMPLETION_TARGET_EPSILON = 1;
2843
+ var INITIAL_SCROLL_ZERO_TARGET_EPSILON = 1;
2844
+ var SILENT_INITIAL_SCROLL_RETRY_DELAY_MS = 16;
2845
+ function checkFinishedScroll(ctx, options) {
2846
+ const scrollingTo = ctx.state.scrollingTo;
2847
+ if (options == null ? void 0 : options.onlyIfAligned) {
2848
+ if (!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || scrollingTo.animated) {
1925
2849
  return;
1926
2850
  }
1927
- const currentOffset = readOffset();
1928
- const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
1929
- if (reason === "scrollend" && !isNearTarget) {
2851
+ if (!getResolvedScrollCompletionState(ctx, scrollingTo).isAtResolvedTarget) {
1930
2852
  return;
1931
2853
  }
1932
- settled = true;
1933
- cleanup();
1934
- finishScrollTo(ctx);
2854
+ }
2855
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2856
+ }
2857
+ function hasScrollCompletionOwnership(state, options) {
2858
+ const { clampedTargetOffset, scrollingTo } = options;
2859
+ return !scrollingTo.isInitialScroll || state.hasScrolled || clampedTargetOffset <= INITIAL_SCROLL_COMPLETION_TARGET_EPSILON;
2860
+ }
2861
+ function isSilentInitialDispatch(state, scrollingTo) {
2862
+ return !!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && initialScrollCompletion.didDispatchNativeScroll(state) && !state.hasScrolled;
2863
+ }
2864
+ function getInitialScrollWatchdogTargetOffset(state) {
2865
+ var _a3;
2866
+ return (_a3 = initialScrollWatchdog.get(state)) == null ? void 0 : _a3.targetOffset;
2867
+ }
2868
+ function isNativeInitialNonZeroTarget(state) {
2869
+ const targetOffset = getInitialScrollWatchdogTargetOffset(state);
2870
+ return !state.didFinishInitialScroll && initialScrollWatchdog.hasNonZeroTargetOffset(targetOffset);
2871
+ }
2872
+ function shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) {
2873
+ var _a3, _b;
2874
+ if (!scrollingTo.isInitialScroll || scrollingTo.animated || !state.didContainersLayout) {
2875
+ return false;
2876
+ }
2877
+ if (((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap") {
2878
+ return false;
2879
+ }
2880
+ const targetOffset = (_b = scrollingTo.targetOffset) != null ? _b : scrollingTo.offset;
2881
+ if (initialScrollWatchdog.hasNonZeroTargetOffset(targetOffset) && initialScrollCompletion.didDispatchNativeScroll(state) && !state.hasScrolled) {
2882
+ return false;
2883
+ }
2884
+ if (initialScrollWatchdog.isAtZeroTargetOffset(targetOffset) || Math.abs(state.scroll - targetOffset) > 1 || Math.abs(state.scrollPending - targetOffset) > 1) {
2885
+ return false;
2886
+ }
2887
+ return !!scrollingTo.waitForInitialScrollCompletionFrame || isNativeInitialNonZeroTarget(state);
2888
+ }
2889
+ function shouldFinishInitialZeroTargetScroll(ctx) {
2890
+ var _a3;
2891
+ const { state } = ctx;
2892
+ 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;
2893
+ }
2894
+ function getResolvedScrollCompletionState(ctx, scrollingTo) {
2895
+ var _a3;
2896
+ const { state } = ctx;
2897
+ const scroll = state.scrollPending;
2898
+ const adjust = state.scrollAdjustHandler.getAdjust();
2899
+ const clampedTargetOffset = (_a3 = scrollingTo.targetOffset) != null ? _a3 : clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0), scrollingTo);
2900
+ const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
2901
+ const diff1 = Math.abs(scroll - clampedTargetOffset);
2902
+ const diff2 = Math.abs(diff1 - adjust);
2903
+ return {
2904
+ clampedTargetOffset,
2905
+ isAtResolvedTarget: Math.abs(scroll - maxOffset) < 1 && (diff1 < 1 || !scrollingTo.animated && diff2 < 1)
1935
2906
  };
1936
- const onScroll2 = () => {
1937
- if (idleTimeout) {
1938
- clearTimeout(idleTimeout);
2907
+ }
2908
+ function checkFinishedScrollFrame(ctx) {
2909
+ const scrollingTo = ctx.state.scrollingTo;
2910
+ if (!scrollingTo) {
2911
+ return;
2912
+ }
2913
+ const { state } = ctx;
2914
+ state.animFrameCheckFinishedScroll = void 0;
2915
+ const completionState = getResolvedScrollCompletionState(ctx, scrollingTo);
2916
+ if (completionState.isAtResolvedTarget && hasScrollCompletionOwnership(state, {
2917
+ clampedTargetOffset: completionState.clampedTargetOffset,
2918
+ scrollingTo
2919
+ })) {
2920
+ finishScrollTo(ctx);
2921
+ }
2922
+ }
2923
+ function scrollToFallbackOffset(ctx, offset) {
2924
+ var _a3;
2925
+ (_a3 = ctx.state.refScroller.current) == null ? void 0 : _a3.scrollTo({
2926
+ animated: false,
2927
+ x: ctx.state.props.horizontal ? offset : 0,
2928
+ y: ctx.state.props.horizontal ? 0 : offset
2929
+ });
2930
+ }
2931
+ function checkFinishedScrollFallback(ctx) {
2932
+ const state = ctx.state;
2933
+ const scrollingTo = state.scrollingTo;
2934
+ const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
2935
+ const silentInitialDispatch = isSilentInitialDispatch(state, scrollingTo);
2936
+ const canFinishInitialWithoutNativeProgress = scrollingTo !== void 0 ? shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) : false;
2937
+ const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget && !canFinishInitialWithoutNativeProgress || !state.didContainersLayout;
2938
+ const initialDelay = shouldFinishInitialZeroTarget || canFinishInitialWithoutNativeProgress ? 0 : silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : slowTimeout ? 500 : 100;
2939
+ state.timeoutCheckFinishedScrollFallback = setTimeout(() => {
2940
+ let numChecks = 0;
2941
+ const scheduleFallbackCheck = (delay) => {
2942
+ state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
2943
+ };
2944
+ const checkHasScrolled = () => {
2945
+ var _c;
2946
+ state.timeoutCheckFinishedScrollFallback = void 0;
2947
+ const isStillScrollingTo = state.scrollingTo;
2948
+ if (isStillScrollingTo) {
2949
+ numChecks++;
2950
+ const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
2951
+ const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
2952
+ const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
2953
+ const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
2954
+ state,
2955
+ isStillScrollingTo
2956
+ );
2957
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
2958
+ const canFinishAfterSilentNativeDispatch = silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
2959
+ if (shouldFinishZeroTarget || state.hasScrolled || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
2960
+ finishScrollTo(ctx);
2961
+ } else if (isNativeInitialPending && numChecks <= maxChecks) {
2962
+ const targetOffset = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : state.scrollPending;
2963
+ scrollToFallbackOffset(ctx, targetOffset);
2964
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2965
+ } else {
2966
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2967
+ }
2968
+ }
2969
+ };
2970
+ checkHasScrolled();
2971
+ }, initialDelay);
2972
+ }
2973
+
2974
+ // src/core/initialScrollLifecycle.ts
2975
+ function handleInitialScrollLayoutReady(ctx) {
2976
+ var _a3;
2977
+ if (!ctx.state.initialScroll) {
2978
+ return;
2979
+ }
2980
+ const runScroll = () => advanceCurrentInitialScrollSession(ctx, { forceScroll: true });
2981
+ runScroll();
2982
+ if (((_a3 = ctx.state.initialScrollSession) == null ? void 0 : _a3.kind) !== "offset") {
2983
+ requestAnimationFrame(runScroll);
2984
+ }
2985
+ checkFinishedScroll(ctx, { onlyIfAligned: true });
2986
+ }
2987
+ function initializeInitialScrollOnMount(ctx, options) {
2988
+ var _a3, _b;
2989
+ const { dataLength, hasFooterComponent, initialContentOffset, initialScrollAtEnd, useBootstrapInitialScroll } = options;
2990
+ const state = ctx.state;
2991
+ const initialScroll = state.initialScroll;
2992
+ const resolvedInitialContentOffset = initialContentOffset != null ? initialContentOffset : 0;
2993
+ const preserveForFooterLayout = useBootstrapInitialScroll && initialScrollAtEnd && hasFooterComponent;
2994
+ if (initialScroll && (initialScroll.contentOffset === void 0 || !!initialScroll.preserveForFooterLayout !== preserveForFooterLayout && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) !== "offset")) {
2995
+ setInitialScrollTarget(state, {
2996
+ ...initialScroll,
2997
+ contentOffset: resolvedInitialContentOffset,
2998
+ preserveForFooterLayout
2999
+ });
3000
+ }
3001
+ if (useBootstrapInitialScroll && initialScroll && ((_b = state.initialScrollSession) == null ? void 0 : _b.kind) !== "offset") {
3002
+ startBootstrapInitialScrollOnMount(ctx, {
3003
+ initialScrollAtEnd,
3004
+ target: state.initialScroll
3005
+ });
3006
+ return;
3007
+ }
3008
+ const hasPendingDataDependentInitialScroll = !!initialScroll && dataLength === 0 && !(resolvedInitialContentOffset === 0 && !initialScrollAtEnd);
3009
+ if (!resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
3010
+ if (initialScroll && !initialScrollAtEnd) {
3011
+ finishInitialScroll(ctx, {
3012
+ resolvedOffset: resolvedInitialContentOffset
3013
+ });
3014
+ } else {
3015
+ setInitialRenderState(ctx, { didInitialScroll: true });
1939
3016
  }
1940
- idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
1941
- };
1942
- const onScrollEnd = () => finish("scrollend");
1943
- target.addEventListener("scroll", onScroll2);
1944
- if (supportsScrollEnd) {
1945
- target.addEventListener("scrollend", onScrollEnd);
1946
- } else {
1947
- idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1948
3017
  }
1949
3018
  }
1950
-
1951
- // src/core/scrollTo.ts
1952
- var WATCHDOG_OFFSET_EPSILON = 1;
1953
- function scrollTo(ctx, params) {
1954
- var _a3, _b;
3019
+ function handleInitialScrollDataChange(ctx, options) {
3020
+ var _a3, _b, _c;
3021
+ const { dataLength, didDataChange, initialScrollAtEnd, stylePaddingBottom, useBootstrapInitialScroll } = options;
1955
3022
  const state = ctx.state;
1956
- const { noScrollingTo, forceScroll, ...scrollTarget } = params;
1957
- const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1958
- const {
1959
- props: { horizontal }
1960
- } = state;
1961
- if (state.animFrameCheckFinishedScroll) {
1962
- cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
1963
- }
1964
- if (state.timeoutCheckFinishedScrollFallback) {
1965
- clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
3023
+ const previousDataLength = (_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.previousDataLength) != null ? _b : 0;
3024
+ if (state.initialScrollSession) {
3025
+ state.initialScrollSession.previousDataLength = dataLength;
1966
3026
  }
1967
- let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1968
- offset = clampScrollOffset(ctx, offset, scrollTarget);
1969
- state.scrollHistory.length = 0;
1970
- if (!noScrollingTo) {
1971
- state.scrollingTo = {
1972
- ...scrollTarget,
1973
- targetOffset: offset
1974
- };
3027
+ setInitialScrollSession(state);
3028
+ if (useBootstrapInitialScroll) {
3029
+ handleBootstrapInitialScrollDataChange(ctx, {
3030
+ dataLength,
3031
+ didDataChange,
3032
+ initialScrollAtEnd,
3033
+ previousDataLength,
3034
+ stylePaddingBottom
3035
+ });
3036
+ return;
1975
3037
  }
1976
- state.scrollPending = offset;
1977
- const shouldWatchInitialNativeScroll = !state.didFinishInitialScroll && (isInitialScroll || !!state.initialNativeScrollWatchdog) && offset > WATCHDOG_OFFSET_EPSILON;
1978
- const shouldClearInitialNativeScrollWatchdog = !state.didFinishInitialScroll && !!state.initialNativeScrollWatchdog && offset <= WATCHDOG_OFFSET_EPSILON;
1979
- if (shouldWatchInitialNativeScroll) {
1980
- state.hasScrolled = false;
1981
- state.initialNativeScrollWatchdog = {
1982
- startScroll: (_b = (_a3 = state.initialNativeScrollWatchdog) == null ? void 0 : _a3.startScroll) != null ? _b : state.scroll,
1983
- targetOffset: offset
1984
- };
1985
- } else if (shouldClearInitialNativeScrollWatchdog) {
1986
- state.initialNativeScrollWatchdog = void 0;
3038
+ const shouldReplayFinishedOffsetInitialScroll = previousDataLength === 0 && dataLength > 0 && !!state.initialScroll && ((_c = ctx.state.initialScrollSession) == null ? void 0 : _c.kind) === "offset" && !!state.didFinishInitialScroll;
3039
+ if (previousDataLength !== 0 || dataLength === 0 || !state.initialScroll || !state.queuedInitialLayout || state.didFinishInitialScroll && !shouldReplayFinishedOffsetInitialScroll) {
3040
+ return;
1987
3041
  }
1988
- if (forceScroll || !isInitialScroll || Platform.OS === "android") {
1989
- doScrollTo(ctx, { animated, horizontal, offset });
1990
- } else {
1991
- state.scroll = offset;
3042
+ if (shouldReplayFinishedOffsetInitialScroll) {
3043
+ state.didFinishInitialScroll = false;
1992
3044
  }
3045
+ advanceCurrentInitialScrollSession(ctx);
1993
3046
  }
1994
3047
 
1995
- // src/core/doMaintainScrollAtEnd.ts
1996
- function doMaintainScrollAtEnd(ctx) {
3048
+ // src/utils/requestAdjust.ts
3049
+ function requestAdjust(ctx, positionDiff, dataChanged) {
1997
3050
  const state = ctx.state;
1998
- const {
1999
- didContainersLayout,
2000
- isAtEnd,
2001
- pendingNativeMVCPAdjust,
2002
- refScroller,
2003
- props: { maintainScrollAtEnd }
2004
- } = state;
2005
- const shouldMaintainScrollAtEnd = !!(isAtEnd && maintainScrollAtEnd && didContainersLayout);
2006
- if (pendingNativeMVCPAdjust) {
2007
- state.pendingMaintainScrollAtEnd = shouldMaintainScrollAtEnd;
2008
- return false;
2009
- }
2010
- state.pendingMaintainScrollAtEnd = false;
2011
- if (shouldMaintainScrollAtEnd) {
2012
- const contentSize = getContentSize(ctx);
2013
- if (contentSize < state.scrollLength) {
2014
- state.scroll = 0;
2015
- }
2016
- requestAnimationFrame(() => {
2017
- var _a3;
2018
- if (state.isAtEnd) {
2019
- state.maintainingScrollAtEnd = true;
2020
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2021
- animated: maintainScrollAtEnd.animated
2022
- });
2023
- setTimeout(
2024
- () => {
2025
- state.maintainingScrollAtEnd = false;
2026
- },
2027
- maintainScrollAtEnd.animated ? 500 : 0
2028
- );
3051
+ if (Math.abs(positionDiff) > 0.1) {
3052
+ const doit = () => {
3053
+ {
3054
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
3055
+ if (state.adjustingFromInitialMount) {
3056
+ state.adjustingFromInitialMount--;
3057
+ }
2029
3058
  }
2030
- });
2031
- return true;
3059
+ };
3060
+ state.scroll += positionDiff;
3061
+ state.scrollForNextCalculateItemsInView = void 0;
3062
+ const readyToRender = peek$(ctx, "readyToRender");
3063
+ if (readyToRender) {
3064
+ doit();
3065
+ } else {
3066
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
3067
+ requestAnimationFrame(doit);
3068
+ }
2032
3069
  }
2033
- return false;
2034
3070
  }
2035
3071
 
2036
3072
  // src/core/mvcp.ts
@@ -2312,94 +3348,6 @@ function prepareMVCP(ctx, dataChanged) {
2312
3348
  }
2313
3349
  }
2314
3350
 
2315
- // src/core/updateScroll.ts
2316
- function updateScroll(ctx, newScroll, forceUpdate) {
2317
- var _a3;
2318
- const state = ctx.state;
2319
- const { ignoreScrollFromMVCP, lastScrollAdjustForHistory, scrollAdjustHandler, scrollHistory, scrollingTo } = state;
2320
- const prevScroll = state.scroll;
2321
- state.hasScrolled = true;
2322
- state.lastBatchingAction = Date.now();
2323
- const currentTime = Date.now();
2324
- const adjust = scrollAdjustHandler.getAdjust();
2325
- const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
2326
- if (adjustChanged) {
2327
- scrollHistory.length = 0;
2328
- }
2329
- state.lastScrollAdjustForHistory = adjust;
2330
- if (scrollingTo === void 0 && !(scrollHistory.length === 0 && newScroll === state.scroll)) {
2331
- if (!adjustChanged) {
2332
- scrollHistory.push({ scroll: newScroll, time: currentTime });
2333
- }
2334
- }
2335
- if (scrollHistory.length > 5) {
2336
- scrollHistory.shift();
2337
- }
2338
- if (ignoreScrollFromMVCP && !scrollingTo) {
2339
- const { lt, gt } = ignoreScrollFromMVCP;
2340
- if (lt && newScroll < lt || gt && newScroll > gt) {
2341
- state.ignoreScrollFromMVCPIgnored = true;
2342
- return;
2343
- }
2344
- }
2345
- state.scrollPrev = prevScroll;
2346
- state.scrollPrevTime = state.scrollTime;
2347
- state.scroll = newScroll;
2348
- state.scrollTime = currentTime;
2349
- const scrollDelta = Math.abs(newScroll - prevScroll);
2350
- const didResolvePendingNativeMVCPAdjust = resolvePendingNativeMVCPAdjust(ctx, newScroll);
2351
- const scrollLength = state.scrollLength;
2352
- const lastCalculated = state.scrollLastCalculate;
2353
- const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
2354
- const shouldUpdate = useAggressiveItemRecalculation || didResolvePendingNativeMVCPAdjust || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
2355
- if (shouldUpdate) {
2356
- state.scrollLastCalculate = state.scroll;
2357
- state.ignoreScrollFromMVCPIgnored = false;
2358
- state.lastScrollDelta = scrollDelta;
2359
- const runCalculateItems = () => {
2360
- var _a4;
2361
- (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0 });
2362
- checkThresholds(ctx);
2363
- };
2364
- if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
2365
- flushSync(runCalculateItems);
2366
- } else {
2367
- runCalculateItems();
2368
- }
2369
- const shouldMaintainScrollAtEndAfterPendingSettle = !!state.pendingMaintainScrollAtEnd || !!((_a3 = state.props.maintainScrollAtEnd) == null ? void 0 : _a3.onDataChange);
2370
- if (didResolvePendingNativeMVCPAdjust && shouldMaintainScrollAtEndAfterPendingSettle) {
2371
- state.pendingMaintainScrollAtEnd = false;
2372
- doMaintainScrollAtEnd(ctx);
2373
- }
2374
- state.dataChangeNeedsScrollUpdate = false;
2375
- state.lastScrollDelta = 0;
2376
- }
2377
- }
2378
-
2379
- // src/utils/requestAdjust.ts
2380
- function requestAdjust(ctx, positionDiff, dataChanged) {
2381
- const state = ctx.state;
2382
- if (Math.abs(positionDiff) > 0.1) {
2383
- const doit = () => {
2384
- {
2385
- state.scrollAdjustHandler.requestAdjust(positionDiff);
2386
- if (state.adjustingFromInitialMount) {
2387
- state.adjustingFromInitialMount--;
2388
- }
2389
- }
2390
- };
2391
- state.scroll += positionDiff;
2392
- state.scrollForNextCalculateItemsInView = void 0;
2393
- const readyToRender = peek$(ctx, "readyToRender");
2394
- if (readyToRender) {
2395
- doit();
2396
- } else {
2397
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2398
- requestAnimationFrame(doit);
2399
- }
2400
- }
2401
- }
2402
-
2403
3351
  // src/core/prepareColumnStartState.ts
2404
3352
  function prepareColumnStartState(ctx, startIndex, useAverageSize) {
2405
3353
  var _a3;
@@ -2913,23 +3861,6 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
2913
3861
  var unstableBatchedUpdates = ReactDOM.unstable_batchedUpdates;
2914
3862
  var batchedUpdates = typeof unstableBatchedUpdates === "function" ? unstableBatchedUpdates : (fn) => fn();
2915
3863
 
2916
- // src/utils/checkAllSizesKnown.ts
2917
- function isNullOrUndefined2(value) {
2918
- return value === null || value === void 0;
2919
- }
2920
- function checkAllSizesKnown(state) {
2921
- const { startBuffered, endBuffered, sizesKnown } = state;
2922
- if (!isNullOrUndefined2(endBuffered) && !isNullOrUndefined2(startBuffered) && startBuffered >= 0 && endBuffered >= 0) {
2923
- let areAllKnown = true;
2924
- for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
2925
- const key = getId(state, i);
2926
- areAllKnown && (areAllKnown = sizesKnown.has(key));
2927
- }
2928
- return areAllKnown;
2929
- }
2930
- return false;
2931
- }
2932
-
2933
3864
  // src/utils/findAvailableContainers.ts
2934
3865
  function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
2935
3866
  const numContainers = peek$(ctx, "numContainers");
@@ -3052,97 +3983,11 @@ function comparatorByDistance(a, b) {
3052
3983
  return b.distance - a.distance;
3053
3984
  }
3054
3985
 
3055
- // src/core/scrollToIndex.ts
3056
- function scrollToIndex(ctx, {
3057
- index,
3058
- viewOffset = 0,
3059
- animated = true,
3060
- forceScroll,
3061
- isInitialScroll,
3062
- viewPosition
3063
- }) {
3064
- const state = ctx.state;
3065
- const { data } = state.props;
3066
- if (index >= data.length) {
3067
- index = data.length - 1;
3068
- } else if (index < 0) {
3069
- index = 0;
3070
- }
3071
- const firstIndexOffset = calculateOffsetForIndex(ctx, index);
3072
- const isLast = index === data.length - 1;
3073
- if (isLast && viewPosition === void 0) {
3074
- viewPosition = 1;
3075
- }
3076
- state.scrollForNextCalculateItemsInView = void 0;
3077
- const targetId = getId(state, index);
3078
- const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
3079
- scrollTo(ctx, {
3080
- animated,
3081
- forceScroll,
3082
- index,
3083
- isInitialScroll,
3084
- itemSize,
3085
- offset: firstIndexOffset,
3086
- viewOffset,
3087
- viewPosition: viewPosition != null ? viewPosition : 0
3088
- });
3089
- }
3090
-
3091
- // src/utils/performInitialScroll.ts
3092
- function performInitialScroll(ctx, params) {
3093
- var _a3;
3094
- const { forceScroll, initialScrollUsesOffset, resolvedOffset, target } = params;
3095
- if (initialScrollUsesOffset || resolvedOffset !== void 0) {
3096
- scrollTo(ctx, {
3097
- animated: false,
3098
- forceScroll,
3099
- index: initialScrollUsesOffset ? void 0 : target.index,
3100
- isInitialScroll: true,
3101
- offset: (_a3 = resolvedOffset != null ? resolvedOffset : target.contentOffset) != null ? _a3 : 0,
3102
- precomputedWithViewOffset: resolvedOffset !== void 0
3103
- });
3104
- return;
3105
- }
3106
- if (target.index === void 0) {
3107
- return;
3108
- }
3109
- scrollToIndex(ctx, {
3110
- ...target,
3111
- animated: false,
3112
- forceScroll,
3113
- isInitialScroll: true
3114
- });
3115
- }
3116
-
3117
3986
  // src/utils/setDidLayout.ts
3118
3987
  function setDidLayout(ctx) {
3119
3988
  const state = ctx.state;
3120
- const { initialScroll } = state;
3121
3989
  state.queuedInitialLayout = true;
3122
3990
  checkAtBottom(ctx);
3123
- if (initialScroll) {
3124
- const runScroll = () => {
3125
- var _a3, _b;
3126
- const target = state.initialScroll;
3127
- if (!target) {
3128
- return;
3129
- }
3130
- const activeInitialTargetOffset = ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) ? (_b = state.scrollingTo.targetOffset) != null ? _b : state.scrollingTo.offset : void 0;
3131
- const desiredInitialTargetOffset = state.initialScrollUsesOffset ? target.contentOffset : activeInitialTargetOffset;
3132
- const isAlreadyAtDesiredInitialTarget = desiredInitialTargetOffset !== void 0 && Math.abs(state.scroll - desiredInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - desiredInitialTargetOffset) <= 1;
3133
- if (!isAlreadyAtDesiredInitialTarget) {
3134
- performInitialScroll(ctx, {
3135
- forceScroll: true,
3136
- initialScrollUsesOffset: state.initialScrollUsesOffset,
3137
- // Offset-based initial scrolls do not need item lookup, so they can run even before data exists.
3138
- // Re-run on the next frame to pick up measured viewport size without waiting for index resolution.
3139
- target
3140
- });
3141
- }
3142
- };
3143
- runScroll();
3144
- requestAnimationFrame(runScroll);
3145
- }
3146
3991
  setInitialRenderState(ctx, { didLayout: true });
3147
3992
  }
3148
3993
 
@@ -3217,7 +4062,7 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
3217
4062
  function calculateItemsInView(ctx, params = {}) {
3218
4063
  const state = ctx.state;
3219
4064
  batchedUpdates(() => {
3220
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
4065
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
3221
4066
  const {
3222
4067
  columns,
3223
4068
  columnSpans,
@@ -3225,7 +4070,6 @@ function calculateItemsInView(ctx, params = {}) {
3225
4070
  enableScrollForNextCalculateItemsInView,
3226
4071
  idCache,
3227
4072
  indexByKey,
3228
- initialScroll,
3229
4073
  minIndexSizeChanged,
3230
4074
  positions,
3231
4075
  props: {
@@ -3249,6 +4093,8 @@ function calculateItemsInView(ctx, params = {}) {
3249
4093
  const alwaysRenderArr = alwaysRenderIndicesArr || [];
3250
4094
  const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
3251
4095
  const { dataChanged, doMVCP, forceFullItemPositions } = params;
4096
+ const bootstrapInitialScrollState = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
4097
+ const suppressInitialScrollSideEffects = !!bootstrapInitialScrollState;
3252
4098
  const prevNumContainers = peek$(ctx, "numContainers");
3253
4099
  if (!data || scrollLength === 0 || !prevNumContainers) {
3254
4100
  return;
@@ -3259,16 +4105,12 @@ function calculateItemsInView(ctx, params = {}) {
3259
4105
  const speed = getScrollVelocity(state);
3260
4106
  const scrollExtra = 0;
3261
4107
  const { queuedInitialLayout } = state;
3262
- let { scroll: scrollState } = state;
3263
- if (!queuedInitialLayout && initialScroll) {
3264
- const updatedOffset = state.initialScrollUsesOffset ? (_a3 = initialScroll.contentOffset) != null ? _a3 : 0 : calculateOffsetWithOffsetPosition(
3265
- ctx,
3266
- calculateOffsetForIndex(ctx, initialScroll.index),
3267
- initialScroll
3268
- );
3269
- scrollState = updatedOffset;
3270
- }
3271
- const scrollAdjustPending = (_b = peek$(ctx, "scrollAdjustPending")) != null ? _b : 0;
4108
+ const scrollState = suppressInitialScrollSideEffects ? (_b = bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.scroll) != null ? _b : state.scroll : !queuedInitialLayout && state.initialScroll ? (
4109
+ // Before the initial layout settles, keep viewport math anchored to the
4110
+ // current initial-scroll target instead of transient native adjustments.
4111
+ resolveInitialScrollOffset(ctx, state.initialScroll)
4112
+ ) : state.scroll;
4113
+ const scrollAdjustPending = (_c = peek$(ctx, "scrollAdjustPending")) != null ? _c : 0;
3272
4114
  const scrollAdjustPad = scrollAdjustPending - topPad;
3273
4115
  let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
3274
4116
  if (scroll + scrollLength > totalSize) {
@@ -3292,7 +4134,7 @@ function calculateItemsInView(ctx, params = {}) {
3292
4134
  const scrollTopBuffered = scroll - scrollBufferTop;
3293
4135
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
3294
4136
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
3295
- if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
4137
+ if (!suppressInitialScrollSideEffects && !dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
3296
4138
  const { top, bottom } = scrollForNextCalculateItemsInView;
3297
4139
  if (top === null && bottom === null) {
3298
4140
  state.scrollForNextCalculateItemsInView = void 0;
@@ -3302,7 +4144,7 @@ function calculateItemsInView(ctx, params = {}) {
3302
4144
  }
3303
4145
  }
3304
4146
  }
3305
- const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
4147
+ const checkMVCP = doMVCP && !suppressInitialScrollSideEffects ? prepareMVCP(ctx, dataChanged) : void 0;
3306
4148
  if (dataChanged) {
3307
4149
  indexByKey.clear();
3308
4150
  idCache.length = 0;
@@ -3310,7 +4152,7 @@ function calculateItemsInView(ctx, params = {}) {
3310
4152
  columns.length = 0;
3311
4153
  columnSpans.length = 0;
3312
4154
  }
3313
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4155
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_d = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _d : 0;
3314
4156
  updateItemPositions(ctx, dataChanged, {
3315
4157
  doMVCP,
3316
4158
  forceFullUpdate: !!forceFullItemPositions,
@@ -3327,11 +4169,11 @@ function calculateItemsInView(ctx, params = {}) {
3327
4169
  let startBufferedId = null;
3328
4170
  let endNoBuffer = null;
3329
4171
  let endBuffered = null;
3330
- let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4172
+ let loopStart = (_e = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _e : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
3331
4173
  for (let i = loopStart; i >= 0; i--) {
3332
- const id = (_d = idCache[i]) != null ? _d : getId(state, i);
4174
+ const id = (_f = idCache[i]) != null ? _f : getId(state, i);
3333
4175
  const top = positions[i];
3334
- const size = (_e = sizes.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i]);
4176
+ const size = (_g = sizes.get(id)) != null ? _g : getItemSize(ctx, id, i, data[i]);
3335
4177
  const bottom = top + size;
3336
4178
  if (bottom > scroll - scrollBufferTop) {
3337
4179
  loopStart = i;
@@ -3362,8 +4204,8 @@ function calculateItemsInView(ctx, params = {}) {
3362
4204
  let firstFullyOnScreenIndex;
3363
4205
  const dataLength = data.length;
3364
4206
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
3365
- const id = (_f = idCache[i]) != null ? _f : getId(state, i);
3366
- const size = (_g = sizes.get(id)) != null ? _g : getItemSize(ctx, id, i, data[i]);
4207
+ const id = (_h = idCache[i]) != null ? _h : getId(state, i);
4208
+ const size = (_i = sizes.get(id)) != null ? _i : getItemSize(ctx, id, i, data[i]);
3367
4209
  const top = positions[i];
3368
4210
  if (!foundEnd) {
3369
4211
  if (startNoBuffer === null && top + size > scroll) {
@@ -3402,7 +4244,7 @@ function calculateItemsInView(ctx, params = {}) {
3402
4244
  const firstVisibleAnchorIndex = firstFullyOnScreenIndex != null ? firstFullyOnScreenIndex : startNoBuffer;
3403
4245
  if (firstVisibleAnchorIndex !== null && firstVisibleAnchorIndex !== void 0 && endNoBuffer !== null) {
3404
4246
  for (let i = firstVisibleAnchorIndex; i <= endNoBuffer; i++) {
3405
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
4247
+ const id = (_j = idCache[i]) != null ? _j : getId(state, i);
3406
4248
  idsInView.push(id);
3407
4249
  }
3408
4250
  }
@@ -3435,7 +4277,7 @@ function calculateItemsInView(ctx, params = {}) {
3435
4277
  const needNewContainers = [];
3436
4278
  const needNewContainersSet = /* @__PURE__ */ new Set();
3437
4279
  for (let i = startBuffered; i <= endBuffered; i++) {
3438
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
4280
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
3439
4281
  if (!containerItemKeys.has(id)) {
3440
4282
  needNewContainersSet.add(i);
3441
4283
  needNewContainers.push(i);
@@ -3444,7 +4286,7 @@ function calculateItemsInView(ctx, params = {}) {
3444
4286
  if (alwaysRenderArr.length > 0) {
3445
4287
  for (const index of alwaysRenderArr) {
3446
4288
  if (index < 0 || index >= dataLength) continue;
3447
- const id = (_j = idCache[index]) != null ? _j : getId(state, index);
4289
+ const id = (_l = idCache[index]) != null ? _l : getId(state, index);
3448
4290
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
3449
4291
  needNewContainersSet.add(index);
3450
4292
  needNewContainers.push(index);
@@ -3482,7 +4324,7 @@ function calculateItemsInView(ctx, params = {}) {
3482
4324
  for (let idx = 0; idx < needNewContainers.length; idx++) {
3483
4325
  const i = needNewContainers[idx];
3484
4326
  const containerIndex = availableContainers[idx];
3485
- const id = (_k = idCache[i]) != null ? _k : getId(state, i);
4327
+ const id = (_m = idCache[i]) != null ? _m : getId(state, i);
3486
4328
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
3487
4329
  if (oldKey && oldKey !== id) {
3488
4330
  containerItemKeys.delete(oldKey);
@@ -3523,7 +4365,7 @@ function calculateItemsInView(ctx, params = {}) {
3523
4365
  if (alwaysRenderArr.length > 0) {
3524
4366
  for (const index of alwaysRenderArr) {
3525
4367
  if (index < 0 || index >= dataLength) continue;
3526
- const id = (_l = idCache[index]) != null ? _l : getId(state, index);
4368
+ const id = (_n = idCache[index]) != null ? _n : getId(state, index);
3527
4369
  const containerIndex = containerItemKeys.get(id);
3528
4370
  if (containerIndex !== void 0) {
3529
4371
  state.stickyContainerPool.add(containerIndex);
@@ -3594,13 +4436,23 @@ function calculateItemsInView(ctx, params = {}) {
3594
4436
  if (didChangePositions) {
3595
4437
  set$(ctx, "lastPositionUpdate", Date.now());
3596
4438
  }
3597
- if (!queuedInitialLayout && endBuffered !== null) {
3598
- if (checkAllSizesKnown(state)) {
3599
- setDidLayout(ctx);
3600
- }
4439
+ if (suppressInitialScrollSideEffects) {
4440
+ evaluateBootstrapInitialScroll(ctx);
4441
+ return;
3601
4442
  }
3602
- if (viewabilityConfigCallbackPairs) {
3603
- updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollLength, startNoBuffer, endNoBuffer);
4443
+ if (!queuedInitialLayout && endBuffered !== null && checkAllSizesKnown(state)) {
4444
+ setDidLayout(ctx);
4445
+ handleInitialScrollLayoutReady(ctx);
4446
+ }
4447
+ if (viewabilityConfigCallbackPairs && startNoBuffer !== null && endNoBuffer !== null) {
4448
+ updateViewableItems(
4449
+ ctx.state,
4450
+ ctx,
4451
+ viewabilityConfigCallbackPairs,
4452
+ scrollLength,
4453
+ startNoBuffer,
4454
+ endNoBuffer
4455
+ );
3604
4456
  }
3605
4457
  if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
3606
4458
  const item = data[nextActiveStickyIndex];
@@ -3631,79 +4483,45 @@ function checkActualChange(state, dataProp, previousData) {
3631
4483
  return false;
3632
4484
  }
3633
4485
 
3634
- // src/core/checkFinishedScroll.ts
3635
- var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
3636
- var INITIAL_SCROLL_MAX_FALLBACK_CHECKS = 20;
3637
- var INITIAL_SCROLL_ZERO_TARGET_EPSILON = 1;
3638
- function checkFinishedScroll(ctx) {
3639
- ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
3640
- }
3641
- function checkFinishedScrollFrame(ctx) {
3642
- var _a3;
3643
- const scrollingTo = ctx.state.scrollingTo;
3644
- if (scrollingTo) {
3645
- const { state } = ctx;
3646
- state.animFrameCheckFinishedScroll = void 0;
3647
- const scroll = state.scrollPending;
3648
- const adjust = state.scrollAdjustHandler.getAdjust();
3649
- const clampedTargetOffset = (_a3 = scrollingTo.targetOffset) != null ? _a3 : clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0), scrollingTo);
3650
- const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
3651
- const diff1 = Math.abs(scroll - clampedTargetOffset);
3652
- const diff2 = Math.abs(diff1 - adjust);
3653
- const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
3654
- const isAtTarget = diff1 < 1 || !scrollingTo.animated && diff2 < 1;
3655
- if (isNotOverscrolled && isAtTarget) {
3656
- finishScrollTo(ctx);
4486
+ // src/core/doMaintainScrollAtEnd.ts
4487
+ function doMaintainScrollAtEnd(ctx) {
4488
+ const state = ctx.state;
4489
+ const {
4490
+ didContainersLayout,
4491
+ isAtEnd,
4492
+ pendingNativeMVCPAdjust,
4493
+ refScroller,
4494
+ props: { maintainScrollAtEnd }
4495
+ } = state;
4496
+ const shouldMaintainScrollAtEnd = !!(isAtEnd && maintainScrollAtEnd && didContainersLayout);
4497
+ if (pendingNativeMVCPAdjust) {
4498
+ state.pendingMaintainScrollAtEnd = shouldMaintainScrollAtEnd;
4499
+ return false;
4500
+ }
4501
+ state.pendingMaintainScrollAtEnd = false;
4502
+ if (shouldMaintainScrollAtEnd) {
4503
+ const contentSize = getContentSize(ctx);
4504
+ if (contentSize < state.scrollLength) {
4505
+ state.scroll = 0;
3657
4506
  }
4507
+ requestAnimationFrame(() => {
4508
+ var _a3;
4509
+ if (state.isAtEnd) {
4510
+ state.maintainingScrollAtEnd = true;
4511
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
4512
+ animated: maintainScrollAtEnd.animated
4513
+ });
4514
+ setTimeout(
4515
+ () => {
4516
+ state.maintainingScrollAtEnd = false;
4517
+ },
4518
+ maintainScrollAtEnd.animated ? 500 : 0
4519
+ );
4520
+ }
4521
+ });
4522
+ return true;
3658
4523
  }
3659
- }
3660
- function checkFinishedScrollFallback(ctx) {
3661
- const state = ctx.state;
3662
- const scrollingTo = state.scrollingTo;
3663
- const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
3664
- const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget || !state.didContainersLayout;
3665
- state.timeoutCheckFinishedScrollFallback = setTimeout(
3666
- () => {
3667
- let numChecks = 0;
3668
- const checkHasScrolled = () => {
3669
- var _a3, _b;
3670
- state.timeoutCheckFinishedScrollFallback = void 0;
3671
- const isStillScrollingTo = state.scrollingTo;
3672
- if (isStillScrollingTo) {
3673
- numChecks++;
3674
- const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
3675
- const maxChecks = isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
3676
- const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
3677
- if (shouldFinishZeroTarget || state.hasScrolled || numChecks > maxChecks) {
3678
- finishScrollTo(ctx);
3679
- } else if (isNativeInitialPending && numChecks <= maxChecks) {
3680
- const targetOffset = (_b = (_a3 = state.initialNativeScrollWatchdog) == null ? void 0 : _a3.targetOffset) != null ? _b : state.scrollPending;
3681
- const scroller = state.refScroller.current;
3682
- if (scroller) {
3683
- scroller.scrollTo({
3684
- animated: false,
3685
- x: state.props.horizontal ? targetOffset : 0,
3686
- y: state.props.horizontal ? 0 : targetOffset
3687
- });
3688
- }
3689
- state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
3690
- } else {
3691
- state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
3692
- }
3693
- }
3694
- };
3695
- checkHasScrolled();
3696
- },
3697
- slowTimeout ? 500 : 100
3698
- );
3699
- }
3700
- function isNativeInitialNonZeroTarget(state) {
3701
- return !state.didFinishInitialScroll && !!state.initialNativeScrollWatchdog && state.initialNativeScrollWatchdog.targetOffset > INITIAL_SCROLL_MIN_TARGET_OFFSET;
3702
- }
3703
- function shouldFinishInitialZeroTargetScroll(ctx) {
3704
- var _a3;
3705
- const { state } = ctx;
3706
- 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;
4524
+ return false;
3707
4525
  }
3708
4526
 
3709
4527
  // src/utils/updateAveragesOnDataChange.ts
@@ -3893,20 +4711,102 @@ function handleLayout(ctx, layoutParam, setCanRender) {
3893
4711
  setCanRender(true);
3894
4712
  }
3895
4713
 
4714
+ // src/core/updateScroll.ts
4715
+ function updateScroll(ctx, newScroll, forceUpdate) {
4716
+ var _a3;
4717
+ const state = ctx.state;
4718
+ const { ignoreScrollFromMVCP, lastScrollAdjustForHistory, scrollAdjustHandler, scrollHistory, scrollingTo } = state;
4719
+ const prevScroll = state.scroll;
4720
+ state.hasScrolled = true;
4721
+ state.lastBatchingAction = Date.now();
4722
+ const currentTime = Date.now();
4723
+ const adjust = scrollAdjustHandler.getAdjust();
4724
+ const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
4725
+ if (adjustChanged) {
4726
+ scrollHistory.length = 0;
4727
+ }
4728
+ state.lastScrollAdjustForHistory = adjust;
4729
+ if (scrollingTo === void 0 && !(scrollHistory.length === 0 && newScroll === state.scroll)) {
4730
+ if (!adjustChanged) {
4731
+ scrollHistory.push({ scroll: newScroll, time: currentTime });
4732
+ }
4733
+ }
4734
+ if (scrollHistory.length > 5) {
4735
+ scrollHistory.shift();
4736
+ }
4737
+ if (ignoreScrollFromMVCP && !scrollingTo) {
4738
+ const { lt, gt } = ignoreScrollFromMVCP;
4739
+ if (lt && newScroll < lt || gt && newScroll > gt) {
4740
+ state.ignoreScrollFromMVCPIgnored = true;
4741
+ return;
4742
+ }
4743
+ }
4744
+ state.scrollPrev = prevScroll;
4745
+ state.scrollPrevTime = state.scrollTime;
4746
+ state.scroll = newScroll;
4747
+ state.scrollTime = currentTime;
4748
+ const scrollDelta = Math.abs(newScroll - prevScroll);
4749
+ const didResolvePendingNativeMVCPAdjust = resolvePendingNativeMVCPAdjust(ctx, newScroll);
4750
+ const scrollLength = state.scrollLength;
4751
+ const lastCalculated = state.scrollLastCalculate;
4752
+ const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
4753
+ const shouldUpdate = useAggressiveItemRecalculation || didResolvePendingNativeMVCPAdjust || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
4754
+ if (shouldUpdate) {
4755
+ state.scrollLastCalculate = state.scroll;
4756
+ state.ignoreScrollFromMVCPIgnored = false;
4757
+ state.lastScrollDelta = scrollDelta;
4758
+ const runCalculateItems = () => {
4759
+ var _a4;
4760
+ (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0 });
4761
+ checkThresholds(ctx);
4762
+ };
4763
+ if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
4764
+ flushSync(runCalculateItems);
4765
+ } else {
4766
+ runCalculateItems();
4767
+ }
4768
+ const shouldMaintainScrollAtEndAfterPendingSettle = !!state.pendingMaintainScrollAtEnd || !!((_a3 = state.props.maintainScrollAtEnd) == null ? void 0 : _a3.onDataChange);
4769
+ if (didResolvePendingNativeMVCPAdjust && shouldMaintainScrollAtEndAfterPendingSettle) {
4770
+ state.pendingMaintainScrollAtEnd = false;
4771
+ doMaintainScrollAtEnd(ctx);
4772
+ }
4773
+ state.dataChangeNeedsScrollUpdate = false;
4774
+ state.lastScrollDelta = 0;
4775
+ }
4776
+ }
4777
+
3896
4778
  // src/core/onScroll.ts
3897
- var INITIAL_SCROLL_PROGRESS_EPSILON = 1;
3898
- function didObserveInitialScrollProgress(newScroll, watchdog) {
3899
- const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
3900
- const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
3901
- return nextDistance <= INITIAL_SCROLL_PROGRESS_EPSILON || nextDistance + INITIAL_SCROLL_PROGRESS_EPSILON < previousDistance;
4779
+ function trackInitialScrollNativeProgress(state, newScroll) {
4780
+ const initialNativeScrollWatchdog = initialScrollWatchdog.get(state);
4781
+ const didInitialScrollProgress = !!initialNativeScrollWatchdog && initialScrollWatchdog.didObserveProgress(newScroll, initialNativeScrollWatchdog);
4782
+ if (didInitialScrollProgress) {
4783
+ initialScrollWatchdog.clear(state);
4784
+ return;
4785
+ }
4786
+ if (initialNativeScrollWatchdog) {
4787
+ state.hasScrolled = false;
4788
+ initialScrollWatchdog.set(state, {
4789
+ startScroll: initialNativeScrollWatchdog.startScroll,
4790
+ targetOffset: initialNativeScrollWatchdog.targetOffset
4791
+ });
4792
+ }
4793
+ }
4794
+ function shouldDeferPublicOnScroll(state) {
4795
+ var _a3;
4796
+ return !!state.initialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" && !state.didFinishInitialScroll;
4797
+ }
4798
+ function cloneScrollEvent(event) {
4799
+ return {
4800
+ ...event,
4801
+ nativeEvent: {
4802
+ ...event.nativeEvent
4803
+ }
4804
+ };
3902
4805
  }
3903
4806
  function onScroll(ctx, event) {
3904
4807
  var _a3, _b, _c, _d;
3905
4808
  const state = ctx.state;
3906
- const {
3907
- scrollProcessingEnabled,
3908
- props: { onScroll: onScrollProp }
3909
- } = state;
4809
+ const { scrollProcessingEnabled } = state;
3910
4810
  if (scrollProcessingEnabled === false) {
3911
4811
  return;
3912
4812
  }
@@ -3937,20 +4837,18 @@ function onScroll(ctx, event) {
3937
4837
  }
3938
4838
  }
3939
4839
  state.scrollPending = newScroll;
3940
- const initialNativeScrollWatchdog = state.initialNativeScrollWatchdog;
3941
- const didInitialScrollProgress = !!initialNativeScrollWatchdog && didObserveInitialScrollProgress(newScroll, initialNativeScrollWatchdog);
3942
- if (didInitialScrollProgress) {
3943
- state.initialNativeScrollWatchdog = void 0;
3944
- }
3945
4840
  updateScroll(ctx, newScroll, insetChanged);
3946
- if (initialNativeScrollWatchdog && !didInitialScrollProgress) {
3947
- state.hasScrolled = false;
3948
- state.initialNativeScrollWatchdog = initialNativeScrollWatchdog;
3949
- }
4841
+ trackInitialScrollNativeProgress(state, newScroll);
3950
4842
  if (state.scrollingTo) {
3951
4843
  checkFinishedScroll(ctx);
3952
4844
  }
3953
- onScrollProp == null ? void 0 : onScrollProp(event);
4845
+ if (state.props.onScroll) {
4846
+ if (shouldDeferPublicOnScroll(state)) {
4847
+ state.deferredPublicOnScrollEvent = cloneScrollEvent(event);
4848
+ } else {
4849
+ state.props.onScroll(event);
4850
+ }
4851
+ }
3954
4852
  }
3955
4853
 
3956
4854
  // src/core/ScrollAdjustHandler.ts
@@ -4591,7 +5489,7 @@ var LegendList = typedMemo(
4591
5489
  })
4592
5490
  );
4593
5491
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
4594
- var _a3, _b, _c, _d, _e, _f, _g, _h;
5492
+ var _a3, _b, _c, _d, _e, _f, _g;
4595
5493
  const {
4596
5494
  alignItemsAtEnd = false,
4597
5495
  alwaysRender,
@@ -4615,6 +5513,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4615
5513
  itemsAreEqual,
4616
5514
  keyExtractor: keyExtractorProp,
4617
5515
  ListEmptyComponent,
5516
+ ListFooterComponent,
5517
+ ListFooterComponentStyle,
4618
5518
  ListHeaderComponent,
4619
5519
  maintainScrollAtEnd = false,
4620
5520
  maintainScrollAtEndThreshold = 0.1,
@@ -4651,7 +5551,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4651
5551
  useWindowScroll = false,
4652
5552
  viewabilityConfig,
4653
5553
  viewabilityConfigCallbackPairs,
4654
- waitForInitialLayout = true,
4655
5554
  ...rest
4656
5555
  } = props;
4657
5556
  const animatedPropsInternal = props.animatedPropsInternal;
@@ -4684,8 +5583,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4684
5583
  const hasInitialScrollIndex = initialScrollIndexProp !== void 0 && initialScrollIndexProp !== null;
4685
5584
  const hasInitialScrollOffset = initialScrollOffsetProp !== void 0 && initialScrollOffsetProp !== null;
4686
5585
  const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && hasInitialScrollOffset;
4687
- const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState, viewPosition: 1 } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
5586
+ const usesBootstrapInitialScroll = initialScrollAtEnd || hasInitialScrollIndex;
5587
+ const initialScrollProp = initialScrollAtEnd ? {
5588
+ index: Math.max(0, dataProp.length - 1),
5589
+ preserveForBottomPadding: true,
5590
+ viewOffset: -stylePaddingBottomState,
5591
+ viewPosition: 1
5592
+ } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
4688
5593
  index: (_a3 = initialScrollIndexProp.index) != null ? _a3 : 0,
5594
+ preserveForBottomPadding: initialScrollIndexProp.viewOffset === void 0 && initialScrollIndexProp.viewPosition === 1 ? true : void 0,
4689
5595
  viewOffset: (_b = initialScrollIndexProp.viewOffset) != null ? _b : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingBottomState : 0,
4690
5596
  viewPosition: (_c = initialScrollIndexProp.viewPosition) != null ? _c : 0
4691
5597
  } : {
@@ -4754,22 +5660,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4754
5660
  idCache: [],
4755
5661
  idsInView: [],
4756
5662
  indexByKey: /* @__PURE__ */ new Map(),
4757
- initialAnchor: !initialScrollUsesOffsetOnly && (initialScrollProp == null ? void 0 : initialScrollProp.index) !== void 0 && (initialScrollProp == null ? void 0 : initialScrollProp.viewPosition) !== void 0 ? {
4758
- attempts: 0,
4759
- index: initialScrollProp.index,
4760
- settledTicks: 0,
4761
- viewOffset: (_f = initialScrollProp.viewOffset) != null ? _f : 0,
4762
- viewPosition: initialScrollProp.viewPosition
4763
- } : void 0,
4764
- initialNativeScrollWatchdog: void 0,
4765
5663
  initialScroll: initialScrollProp,
4766
- initialScrollLastDidFinish: false,
4767
- initialScrollLastTarget: initialScrollProp,
4768
- initialScrollLastTargetUsesOffset: initialScrollUsesOffsetOnly,
4769
- initialScrollPreviousDataLength: dataProp.length,
4770
- initialScrollRetryLastLength: void 0,
4771
- initialScrollRetryWindowUntil: 0,
4772
- initialScrollUsesOffset: initialScrollUsesOffsetOnly,
5664
+ initialScrollSession: initialScrollProp ? {
5665
+ kind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
5666
+ previousDataLength: dataProp.length
5667
+ } : void 0,
4773
5668
  isAtEnd: false,
4774
5669
  isAtStart: false,
4775
5670
  isEndReached: null,
@@ -4812,6 +5707,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4812
5707
  };
4813
5708
  const internalState = ctx.state;
4814
5709
  internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
5710
+ internalState.reprocessCurrentScroll = () => updateScroll(ctx, internalState.scroll, true);
4815
5711
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
4816
5712
  set$(ctx, "extraData", extraData);
4817
5713
  }
@@ -4898,96 +5794,23 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4898
5794
  true
4899
5795
  );
4900
5796
  }
4901
- const resolveInitialScrollOffset = useCallback((initialScroll) => {
4902
- var _a4;
4903
- if (state.initialScrollUsesOffset) {
4904
- return clampScrollOffset(ctx, (_a4 = initialScroll.contentOffset) != null ? _a4 : 0);
4905
- }
4906
- const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
4907
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
4908
- return clampScrollOffset(ctx, resolvedOffset, initialScroll);
4909
- }, []);
4910
- const finishInitialScrollWithoutScroll = useCallback(() => {
4911
- refState.current.initialAnchor = void 0;
4912
- refState.current.initialScroll = void 0;
4913
- state.initialAnchor = void 0;
4914
- state.initialScroll = void 0;
4915
- state.initialScrollUsesOffset = false;
4916
- state.initialScrollLastTarget = void 0;
4917
- state.initialScrollLastTargetUsesOffset = false;
4918
- setInitialRenderState(ctx, { didInitialScroll: true });
4919
- }, []);
4920
- const setActiveInitialScrollTarget = useCallback(
4921
- (target, options) => {
4922
- const usesOffset = !!(options == null ? void 0 : options.usesOffset);
4923
- state.initialScrollUsesOffset = usesOffset;
4924
- state.initialScrollLastTarget = target;
4925
- state.initialScrollLastTargetUsesOffset = usesOffset;
4926
- refState.current.initialScroll = target;
4927
- state.initialScroll = target;
4928
- if ((options == null ? void 0 : options.resetDidFinish) && state.didFinishInitialScroll) {
4929
- state.didFinishInitialScroll = false;
4930
- }
4931
- if (!(options == null ? void 0 : options.syncAnchor)) {
4932
- return;
4933
- }
4934
- },
4935
- []
4936
- );
4937
- const shouldFinishInitialScrollAtOrigin = useCallback(
4938
- (initialScroll, offset) => {
4939
- var _a4, _b2, _c2;
4940
- if (offset !== 0 || initialScrollAtEnd) {
4941
- return false;
4942
- }
4943
- if (state.initialScrollUsesOffset) {
4944
- return Math.abs((_a4 = initialScroll.contentOffset) != null ? _a4 : 0) <= 1;
4945
- }
4946
- return initialScroll.index === 0 && ((_b2 = initialScroll.viewPosition) != null ? _b2 : 0) === 0 && Math.abs((_c2 = initialScroll.viewOffset) != null ? _c2 : 0) <= 1;
4947
- },
4948
- [initialScrollAtEnd]
4949
- );
4950
- const shouldFinishEmptyInitialScrollAtEnd = useCallback(
4951
- (initialScroll, offset) => {
4952
- return dataProp.length === 0 && initialScrollAtEnd && offset === 0 && initialScroll.viewPosition === 1;
4953
- },
4954
- [dataProp.length, initialScrollAtEnd]
4955
- );
4956
- const shouldRearmFinishedEmptyInitialScrollAtEnd = useCallback(
4957
- (initialScroll) => {
4958
- var _a4;
4959
- return !!(state.didFinishInitialScroll && dataProp.length > 0 && initialScroll && !state.initialScrollUsesOffset && initialScroll.index === 0 && initialScroll.viewPosition === 1 && ((_a4 = initialScroll.contentOffset) != null ? _a4 : 0) === 0);
4960
- },
4961
- [dataProp.length]
4962
- );
4963
5797
  const initialContentOffset = useMemo(() => {
4964
- let value;
4965
- const { initialScroll, initialAnchor } = refState.current;
4966
- if (initialScroll) {
4967
- if (!state.initialScrollUsesOffset && false) ;
4968
- if (initialScroll.contentOffset !== void 0) {
4969
- value = initialScroll.contentOffset;
4970
- } else {
4971
- const clampedOffset = resolveInitialScrollOffset(initialScroll);
4972
- const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
4973
- setActiveInitialScrollTarget(updatedInitialScroll, {
4974
- usesOffset: state.initialScrollUsesOffset
4975
- });
4976
- value = clampedOffset;
4977
- }
4978
- } else {
4979
- refState.current.initialAnchor = void 0;
4980
- value = 0;
4981
- }
4982
- const hasPendingDataDependentInitialScroll = !!initialScroll && dataProp.length === 0 && !shouldFinishInitialScrollAtOrigin(initialScroll, value) && !shouldFinishEmptyInitialScrollAtEnd(initialScroll, value);
4983
- if (!value && !hasPendingDataDependentInitialScroll) {
4984
- if (initialScroll && shouldFinishInitialScrollAtOrigin(initialScroll, value)) {
4985
- finishInitialScrollWithoutScroll();
4986
- } else {
4987
- setInitialRenderState(ctx, { didInitialScroll: true });
4988
- }
5798
+ var _a4, _b2;
5799
+ const initialScroll = state.initialScroll;
5800
+ if (!initialScroll) {
5801
+ return void 0;
4989
5802
  }
4990
- return value;
5803
+ const resolvedOffset = (_a4 = initialScroll.contentOffset) != null ? _a4 : resolveInitialScrollOffset(ctx, initialScroll);
5804
+ return usesBootstrapInitialScroll && ((_b2 = state.initialScrollSession) == null ? void 0 : _b2.kind) === "bootstrap" && Platform.OS === "web" ? void 0 : resolvedOffset;
5805
+ }, [usesBootstrapInitialScroll]);
5806
+ useLayoutEffect(() => {
5807
+ initializeInitialScrollOnMount(ctx, {
5808
+ dataLength: dataProp.length,
5809
+ hasFooterComponent: !!ListFooterComponent,
5810
+ initialContentOffset,
5811
+ initialScrollAtEnd,
5812
+ useBootstrapInitialScroll: usesBootstrapInitialScroll
5813
+ });
4991
5814
  }, []);
4992
5815
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
4993
5816
  refState.current.lastBatchingAction = Date.now();
@@ -5002,188 +5825,39 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5002
5825
  set$(ctx, "totalSize", 0);
5003
5826
  }
5004
5827
  }
5005
- const doInitialScroll = useCallback((options) => {
5006
- var _a4, _b2;
5007
- const allowPostFinishRetry = !!(options == null ? void 0 : options.allowPostFinishRetry);
5008
- const { didFinishInitialScroll, queuedInitialLayout, scrollingTo } = state;
5009
- const initialScroll = (_a4 = state.initialScroll) != null ? _a4 : allowPostFinishRetry ? state.initialScrollLastTarget : void 0;
5010
- const isInitialScrollInProgress = !!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll);
5011
- const needsContainerLayoutForInitialScroll = !state.initialScrollUsesOffset;
5012
- const shouldWaitForInitialLayout = waitForInitialLayout && needsContainerLayoutForInitialScroll && !queuedInitialLayout && !allowPostFinishRetry && !isInitialScrollInProgress;
5013
- if (!initialScroll || shouldWaitForInitialLayout || didFinishInitialScroll && !allowPostFinishRetry || scrollingTo && !isInitialScrollInProgress) {
5014
- return;
5015
- }
5016
- if (allowPostFinishRetry && state.initialScrollLastTargetUsesOffset) {
5017
- return;
5018
- }
5019
- const didMoveAwayFromInitialTarget = allowPostFinishRetry && initialScroll.contentOffset !== void 0 && Math.abs(state.scroll - initialScroll.contentOffset) > 1;
5020
- if (didMoveAwayFromInitialTarget) {
5021
- state.initialScrollRetryWindowUntil = 0;
5022
- return;
5023
- }
5024
- const offset = resolveInitialScrollOffset(initialScroll);
5025
- const activeInitialTargetOffset = isInitialScrollInProgress ? (_b2 = scrollingTo.targetOffset) != null ? _b2 : scrollingTo.offset : void 0;
5026
- const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - offset) > 1;
5027
- const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - offset) > 1;
5028
- if (!didOffsetChange && (allowPostFinishRetry || isInitialScrollInProgress && !didActiveInitialTargetChange)) {
5029
- return;
5030
- }
5031
- if (didOffsetChange) {
5032
- const updatedInitialScroll = { ...initialScroll, contentOffset: offset };
5033
- if (!state.initialScrollUsesOffset) {
5034
- state.initialScrollLastTarget = updatedInitialScroll;
5035
- state.initialScrollLastTargetUsesOffset = false;
5036
- if (state.initialScroll) {
5037
- refState.current.initialScroll = updatedInitialScroll;
5038
- state.initialScroll = updatedInitialScroll;
5039
- }
5040
- }
5041
- }
5042
- const hasMeasuredScrollLayout = !!state.lastLayout && state.scrollLength > 0;
5043
- const shouldForceNativeInitialScroll = state.initialScrollUsesOffset && hasMeasuredScrollLayout || allowPostFinishRetry || !!queuedInitialLayout || isInitialScrollInProgress && didOffsetChange;
5044
- performInitialScroll(ctx, {
5045
- forceScroll: shouldForceNativeInitialScroll,
5046
- initialScrollUsesOffset: state.initialScrollUsesOffset,
5047
- resolvedOffset: offset,
5048
- target: initialScroll
5049
- });
5050
- }, []);
5051
- useLayoutEffect(() => {
5052
- var _a4;
5053
- const previousDataLength = state.initialScrollPreviousDataLength;
5054
- state.initialScrollPreviousDataLength = dataProp.length;
5055
- if (previousDataLength !== 0 || dataProp.length === 0 || !state.initialScroll || !state.queuedInitialLayout) {
5056
- return;
5057
- }
5058
- if (initialScrollAtEnd) {
5059
- const lastIndex = Math.max(0, dataProp.length - 1);
5060
- const initialScroll = state.initialScroll;
5061
- const shouldRearm = shouldRearmFinishedEmptyInitialScrollAtEnd(initialScroll);
5062
- if (state.didFinishInitialScroll && !shouldRearm) {
5063
- return;
5064
- }
5065
- if (initialScroll && !state.initialScrollUsesOffset && initialScroll.index === lastIndex && initialScroll.viewPosition === 1 && !shouldRearm) {
5066
- return;
5067
- }
5068
- const updatedInitialScroll = {
5069
- contentOffset: void 0,
5070
- index: lastIndex,
5071
- viewOffset: (_a4 = initialScroll == null ? void 0 : initialScroll.viewOffset) != null ? _a4 : -stylePaddingBottomState,
5072
- viewPosition: 1
5073
- };
5074
- setActiveInitialScrollTarget(updatedInitialScroll, {
5075
- resetDidFinish: shouldRearm,
5076
- syncAnchor: true
5077
- });
5078
- doInitialScroll();
5079
- return;
5080
- }
5081
- if (state.didFinishInitialScroll) {
5082
- return;
5083
- }
5084
- doInitialScroll();
5085
- }, [
5086
- dataProp.length,
5087
- doInitialScroll,
5088
- initialScrollAtEnd,
5089
- shouldRearmFinishedEmptyInitialScrollAtEnd,
5090
- stylePaddingBottomState
5091
- ]);
5092
5828
  useLayoutEffect(() => {
5093
- var _a4;
5094
- if (!initialScrollAtEnd) {
5095
- return;
5096
- }
5097
- const lastIndex = Math.max(0, dataProp.length - 1);
5098
- const initialScroll = state.initialScroll;
5099
- const shouldRearm = shouldRearmFinishedEmptyInitialScrollAtEnd(initialScroll);
5100
- if (state.didFinishInitialScroll && !shouldRearm) {
5101
- return;
5102
- }
5103
- if (shouldRearm) {
5104
- state.didFinishInitialScroll = false;
5105
- }
5106
- if (initialScroll && !state.initialScrollUsesOffset && initialScroll.index === lastIndex && initialScroll.viewPosition === 1 && !shouldRearm) {
5107
- return;
5108
- }
5109
- const updatedInitialScroll = {
5110
- contentOffset: void 0,
5111
- index: lastIndex,
5112
- viewOffset: (_a4 = initialScroll == null ? void 0 : initialScroll.viewOffset) != null ? _a4 : -stylePaddingBottomState,
5113
- viewPosition: 1
5114
- };
5115
- setActiveInitialScrollTarget(updatedInitialScroll, {
5116
- resetDidFinish: shouldRearm,
5117
- syncAnchor: true
5829
+ handleInitialScrollDataChange(ctx, {
5830
+ dataLength: dataProp.length,
5831
+ didDataChange: didDataChangeLocal,
5832
+ initialScrollAtEnd,
5833
+ stylePaddingBottom: stylePaddingBottomState,
5834
+ useBootstrapInitialScroll: usesBootstrapInitialScroll
5118
5835
  });
5119
- doInitialScroll();
5120
- }, [
5121
- dataProp.length,
5122
- doInitialScroll,
5123
- initialScrollAtEnd,
5124
- shouldRearmFinishedEmptyInitialScrollAtEnd,
5125
- stylePaddingBottomState
5126
- ]);
5836
+ }, [dataProp.length, didDataChangeLocal, initialScrollAtEnd, stylePaddingBottomState, usesBootstrapInitialScroll]);
5127
5837
  const onLayoutFooter = useCallback(
5128
5838
  (layout) => {
5129
- var _a4;
5130
- if (!initialScrollAtEnd) {
5131
- return;
5132
- }
5133
- const { initialScroll } = state;
5134
- if (!initialScroll) {
5839
+ if (!usesBootstrapInitialScroll) {
5135
5840
  return;
5136
5841
  }
5137
- const lastIndex = Math.max(0, dataProp.length - 1);
5138
- if (initialScroll.index !== lastIndex || initialScroll.viewPosition !== 1) {
5842
+ handleBootstrapInitialScrollFooterLayout(ctx, {
5843
+ dataLength: dataProp.length,
5844
+ footerSize: layout[horizontal ? "width" : "height"],
5845
+ initialScrollAtEnd,
5846
+ stylePaddingBottom: stylePaddingBottomState
5847
+ });
5848
+ },
5849
+ [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingBottomState, usesBootstrapInitialScroll]
5850
+ );
5851
+ const onLayoutChange = useCallback(
5852
+ (layout) => {
5853
+ handleLayout(ctx, layout, setCanRender);
5854
+ if (usesBootstrapInitialScroll) {
5139
5855
  return;
5140
5856
  }
5141
- const footerSize = layout[horizontal ? "width" : "height"];
5142
- const viewOffset = -stylePaddingBottomState - footerSize;
5143
- if (initialScroll.viewOffset !== viewOffset) {
5144
- const previousTargetOffset = (_a4 = initialScroll.contentOffset) != null ? _a4 : resolveInitialScrollOffset(initialScroll);
5145
- const didMoveAwayFromFinishedInitialTarget = state.didFinishInitialScroll && Math.abs(state.scroll - previousTargetOffset) > 1;
5146
- if (didMoveAwayFromFinishedInitialTarget) {
5147
- return;
5148
- }
5149
- const updatedInitialScroll = { ...initialScroll, viewOffset };
5150
- setActiveInitialScrollTarget(updatedInitialScroll, {
5151
- resetDidFinish: true
5152
- });
5153
- doInitialScroll();
5154
- }
5857
+ advanceCurrentInitialScrollSession(ctx);
5155
5858
  },
5156
- [
5157
- dataProp.length,
5158
- doInitialScroll,
5159
- horizontal,
5160
- initialScrollAtEnd,
5161
- resolveInitialScrollOffset,
5162
- stylePaddingBottomState
5163
- ]
5859
+ [usesBootstrapInitialScroll]
5164
5860
  );
5165
- const onLayoutChange = useCallback((layout) => {
5166
- var _a4;
5167
- handleLayout(ctx, layout, setCanRender);
5168
- const SCROLL_LENGTH_RETRY_WINDOW_MS = 600;
5169
- const now = Date.now();
5170
- const didFinishInitialScroll = !!state.didFinishInitialScroll;
5171
- if (didFinishInitialScroll && !state.initialScrollLastDidFinish) {
5172
- state.initialScrollRetryWindowUntil = now + SCROLL_LENGTH_RETRY_WINDOW_MS;
5173
- }
5174
- state.initialScrollLastDidFinish = didFinishInitialScroll;
5175
- const previousScrollLength = state.initialScrollRetryLastLength;
5176
- const currentScrollLength = state.scrollLength;
5177
- const didScrollLengthChange = previousScrollLength === void 0 || Math.abs(currentScrollLength - previousScrollLength) > 1;
5178
- if (didScrollLengthChange) {
5179
- state.initialScrollRetryLastLength = currentScrollLength;
5180
- }
5181
- if (didFinishInitialScroll && didScrollLengthChange && now <= state.initialScrollRetryWindowUntil && !state.initialScrollLastTargetUsesOffset && ((_a4 = state.initialScrollLastTarget) == null ? void 0 : _a4.index) !== void 0) {
5182
- doInitialScroll({ allowPostFinishRetry: true });
5183
- return;
5184
- }
5185
- doInitialScroll();
5186
- }, []);
5187
5861
  const { onLayout } = useOnLayoutSync({
5188
5862
  onLayoutChange,
5189
5863
  onLayoutProp,
@@ -5257,7 +5931,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5257
5931
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
5258
5932
  useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
5259
5933
  {
5260
- useEffect(doInitialScroll, []);
5934
+ useEffect(() => {
5935
+ if (usesBootstrapInitialScroll) {
5936
+ return;
5937
+ }
5938
+ advanceCurrentInitialScrollSession(ctx);
5939
+ }, [usesBootstrapInitialScroll]);
5261
5940
  }
5262
5941
  const fns = useMemo(
5263
5942
  () => ({
@@ -5287,6 +5966,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5287
5966
  horizontal,
5288
5967
  initialContentOffset,
5289
5968
  ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
5969
+ ListFooterComponent,
5970
+ ListFooterComponentStyle,
5290
5971
  ListHeaderComponent,
5291
5972
  onLayout,
5292
5973
  onLayoutFooter,
@@ -5294,7 +5975,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5294
5975
  onScroll: onScrollHandler,
5295
5976
  recycleItems,
5296
5977
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControlElement, {
5297
- progressViewOffset: ((_g = refreshControlElement.props.progressViewOffset) != null ? _g : 0) + stylePaddingTopState
5978
+ progressViewOffset: ((_f = refreshControlElement.props.progressViewOffset) != null ? _f : 0) + stylePaddingTopState
5298
5979
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React3.createElement(
5299
5980
  RefreshControl,
5300
5981
  {
@@ -5305,14 +5986,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5305
5986
  ),
5306
5987
  refScrollView: combinedRef,
5307
5988
  renderScrollComponent,
5308
- scrollAdjustHandler: (_h = refState.current) == null ? void 0 : _h.scrollAdjustHandler,
5989
+ scrollAdjustHandler: (_g = refState.current) == null ? void 0 : _g.scrollAdjustHandler,
5309
5990
  scrollEventThrottle: 0,
5310
5991
  snapToIndices,
5311
5992
  stickyHeaderIndices,
5312
5993
  style,
5313
5994
  updateItemSize: fns.updateItemSize,
5314
- useWindowScroll: useWindowScrollResolved,
5315
- waitForInitialLayout
5995
+ useWindowScroll: useWindowScrollResolved
5316
5996
  }
5317
5997
  ), IS_DEV && ENABLE_DEBUG_VIEW);
5318
5998
  });