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