@legendapp/list 3.0.6 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/react.js CHANGED
@@ -162,6 +162,7 @@ function StateProvider({ children }) {
162
162
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
163
163
  mapViewabilityValues: /* @__PURE__ */ new Map(),
164
164
  positionListeners: /* @__PURE__ */ new Map(),
165
+ scrollAxisGap: 0,
165
166
  state: void 0,
166
167
  values: /* @__PURE__ */ new Map([
167
168
  ["alignItemsAtEndPadding", 0],
@@ -174,6 +175,7 @@ function StateProvider({ children }) {
174
175
  ["isNearEnd", false],
175
176
  ["isNearStart", false],
176
177
  ["isWithinMaintainScrollAtEndThreshold", false],
178
+ ["adaptiveRender", "light"],
177
179
  ["totalSize", 0],
178
180
  ["scrollAdjustPending", 0]
179
181
  ]),
@@ -554,6 +556,24 @@ var ContextContainer = React3.createContext(null);
554
556
  function useContextContainer() {
555
557
  return React3.useContext(ContextContainer);
556
558
  }
559
+ function useAdaptiveRender() {
560
+ const [mode] = useArr$(["adaptiveRender"]);
561
+ return mode;
562
+ }
563
+ function useAdaptiveRenderChange(callback) {
564
+ const ctx = useStateContext();
565
+ const callbackRef = React3.useRef(callback);
566
+ callbackRef.current = callback;
567
+ React3.useLayoutEffect(() => {
568
+ let mode = peek$(ctx, "adaptiveRender");
569
+ return listen$(ctx, "adaptiveRender", (nextMode) => {
570
+ if (mode !== nextMode) {
571
+ mode = nextMode;
572
+ callbackRef.current(nextMode);
573
+ }
574
+ });
575
+ }, [ctx]);
576
+ }
557
577
  function useViewability(callback, configId) {
558
578
  const ctx = useStateContext();
559
579
  const containerContext = useContextContainer();
@@ -823,6 +843,7 @@ function isInMVCPActiveMode(state) {
823
843
  // src/components/Container.tsx
824
844
  function getContainerPositionStyle({
825
845
  columnWrapperStyle,
846
+ contentContainerAlignItems,
826
847
  horizontal,
827
848
  hasItemSeparator,
828
849
  isHorizontalRTLList,
@@ -848,13 +869,14 @@ function getContainerPositionStyle({
848
869
  }
849
870
  }
850
871
  return horizontal ? {
872
+ bottom: contentContainerAlignItems === "flex-end" && numColumns === 1 ? 0 : void 0,
851
873
  boxSizing: paddingStyles ? "border-box" : void 0,
852
874
  direction: isHorizontalRTLList && Platform.OS === "web" ? "ltr" : void 0,
853
875
  flexDirection: hasItemSeparator ? "row" : void 0,
854
876
  height: otherAxisSize,
855
877
  left: 0,
856
878
  position: "absolute",
857
- top: otherAxisPos,
879
+ top: contentContainerAlignItems === "flex-end" && numColumns === 1 ? void 0 : otherAxisPos,
858
880
  ...paddingStyles || {}
859
881
  } : {
860
882
  boxSizing: paddingStyles ? "border-box" : void 0,
@@ -908,6 +930,7 @@ var Container = typedMemo(function Container2({
908
930
  const style = React3.useMemo(
909
931
  () => getContainerPositionStyle({
910
932
  columnWrapperStyle,
933
+ contentContainerAlignItems: ctx.state.props.contentContainerAlignItems,
911
934
  hasItemSeparator: !!ItemSeparatorComponent,
912
935
  horizontal,
913
936
  isHorizontalRTLList,
@@ -921,6 +944,7 @@ var Container = typedMemo(function Container2({
921
944
  otherAxisPos,
922
945
  otherAxisSize,
923
946
  columnWrapperStyle,
947
+ ctx.state.props.contentContainerAlignItems,
924
948
  numColumns,
925
949
  ItemSeparatorComponent
926
950
  ]
@@ -1636,7 +1660,12 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1636
1660
  WebkitOverflowScrolling: "touch"
1637
1661
  // iOS momentum scrolling
1638
1662
  },
1639
- ...StyleSheet.flatten(style)
1663
+ ...StyleSheet.flatten(style),
1664
+ ...maintainVisibleContentPosition ? {
1665
+ // Chrome's native scroll anchoring can apply after LegendList's MVCP adjustment,
1666
+ // causing the same header/item-size delta to be compensated twice.
1667
+ overflowAnchor: "none"
1668
+ } : {}
1640
1669
  };
1641
1670
  const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd2(ctx);
1642
1671
  const anchoredEndInset = ((_c = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.anchoredEndSpace) == null ? void 0 : _c.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
@@ -1647,7 +1676,10 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1647
1676
  flexDirection: horizontal ? "row" : void 0,
1648
1677
  minHeight: horizontal ? void 0 : "100%",
1649
1678
  minWidth: horizontal ? "100%" : void 0,
1650
- ...StyleSheet.flatten(contentContainerStyle)
1679
+ ...StyleSheet.flatten(contentContainerStyle),
1680
+ ...maintainVisibleContentPosition ? {
1681
+ overflowAnchor: "none"
1682
+ } : {}
1651
1683
  };
1652
1684
  const className = contentContainerClassName ? `${LEGEND_LIST_CONTENT_CONTAINER_CLASS} ${contentContainerClassName}` : LEGEND_LIST_CONTENT_CONTAINER_CLASS;
1653
1685
  const {
@@ -1750,6 +1782,7 @@ function scrollAdjustBy(el, left, top) {
1750
1782
  function ScrollAdjust() {
1751
1783
  const ctx = useStateContext();
1752
1784
  const lastScrollOffsetRef = React3__namespace.useRef(0);
1785
+ const lastScrollAdjustUserOffsetRef = React3__namespace.useRef(0);
1753
1786
  const resetPaddingRafRef = React3__namespace.useRef(void 0);
1754
1787
  const resetPaddingBaselineRef = React3__namespace.useRef(void 0);
1755
1788
  const contentNodeRef = React3__namespace.useRef(null);
@@ -1758,20 +1791,24 @@ function ScrollAdjust() {
1758
1791
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1759
1792
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1760
1793
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1761
- const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1762
- if (scrollDelta !== 0) {
1794
+ const signalScrollDelta = scrollOffset - lastScrollOffsetRef.current;
1795
+ if (signalScrollDelta !== 0) {
1763
1796
  const target = getScrollAdjustTarget(ctx, contentNodeRef.current);
1764
1797
  if (target) {
1765
1798
  const horizontal = !!ctx.state.props.horizontal;
1766
1799
  const axis = getScrollAdjustAxis(horizontal);
1767
1800
  const { contentNode, scrollElement: el } = target;
1801
+ const currentScroll = horizontal ? el.scrollLeft : el.scrollTop;
1802
+ const userOffsetDelta = (scrollAdjustUserOffset || 0) - lastScrollAdjustUserOffsetRef.current;
1803
+ const intendedScroll = userOffsetDelta !== 0 ? currentScroll + userOffsetDelta : ctx.state.scroll;
1804
+ const scrollDelta = intendedScroll - currentScroll;
1805
+ const shouldScroll = Math.abs(scrollDelta) > 0.01;
1768
1806
  const scrollBy = () => scrollAdjustBy(el, axis.x * scrollDelta, axis.y * scrollDelta);
1769
1807
  contentNodeRef.current = contentNode;
1770
- if (contentNode) {
1771
- const prevScroll = horizontal ? el.scrollLeft : el.scrollTop;
1808
+ if (shouldScroll && contentNode) {
1772
1809
  const totalSize = contentNode[axis.contentSizeKey];
1773
1810
  const viewportSize = el[axis.viewportSizeKey];
1774
- const nextScroll = prevScroll + scrollDelta;
1811
+ const nextScroll = currentScroll + scrollDelta;
1775
1812
  const needsTemporaryPadding = scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize;
1776
1813
  if (needsTemporaryPadding) {
1777
1814
  const previousPaddingEnd = (_a3 = resetPaddingBaselineRef.current) != null ? _a3 : contentNode.style[axis.paddingEndProp];
@@ -1791,11 +1828,12 @@ function ScrollAdjust() {
1791
1828
  } else {
1792
1829
  scrollBy();
1793
1830
  }
1794
- } else {
1831
+ } else if (shouldScroll) {
1795
1832
  scrollBy();
1796
1833
  }
1797
1834
  }
1798
1835
  lastScrollOffsetRef.current = scrollOffset;
1836
+ lastScrollAdjustUserOffsetRef.current = scrollAdjustUserOffset || 0;
1799
1837
  }
1800
1838
  }, [ctx]);
1801
1839
  useValueListener$("scrollAdjust", callback);
@@ -1817,7 +1855,7 @@ function WebAnchoredEndSpace({ horizontal }) {
1817
1855
  return /* @__PURE__ */ React3__namespace.createElement("div", { style }, null);
1818
1856
  }
1819
1857
 
1820
- // src/core/updateContentMetrics.ts
1858
+ // src/core/updateContentMetricsState.ts
1821
1859
  function getRawContentLength(ctx) {
1822
1860
  var _a3, _b, _c;
1823
1861
  const { state, values } = ctx;
@@ -1828,233 +1866,41 @@ function getAlignItemsAtEndPadding(ctx) {
1828
1866
  const shouldPad = !!state.props.alignItemsAtEndPaddingEnabled && !state.props.horizontal && state.props.data.length > 0 && state.scrollLength > 0;
1829
1867
  return shouldPad ? Math.max(0, state.scrollLength - getRawContentLength(ctx) - getContentInsetEnd(ctx)) : 0;
1830
1868
  }
1831
- function updateContentMetrics(ctx) {
1869
+ function updateContentMetricsState(ctx) {
1870
+ const previousPadding = peek$(ctx, "alignItemsAtEndPadding") || 0;
1832
1871
  const nextPadding = getAlignItemsAtEndPadding(ctx);
1833
- if (peek$(ctx, "alignItemsAtEndPadding") !== nextPadding) {
1872
+ if (previousPadding !== nextPadding) {
1834
1873
  set$(ctx, "alignItemsAtEndPadding", nextPadding);
1835
1874
  }
1836
1875
  }
1837
- function setContentLengthSignal(ctx, signalName, size) {
1838
- if (peek$(ctx, signalName) !== size) {
1839
- set$(ctx, signalName, size);
1840
- updateContentMetrics(ctx);
1841
- }
1842
- }
1843
- function setHeaderSize(ctx, size) {
1844
- setContentLengthSignal(ctx, "headerSize", size);
1845
- }
1846
- function setFooterSize(ctx, size) {
1847
- setContentLengthSignal(ctx, "footerSize", size);
1848
- }
1849
- function areInsetsEqual(left, right) {
1850
- var _a3, _b, _c, _d, _e, _f, _g, _h;
1851
- return ((_a3 = left == null ? void 0 : left.top) != null ? _a3 : 0) === ((_b = right == null ? void 0 : right.top) != null ? _b : 0) && ((_c = left == null ? void 0 : left.bottom) != null ? _c : 0) === ((_d = right == null ? void 0 : right.bottom) != null ? _d : 0) && ((_e = left == null ? void 0 : left.left) != null ? _e : 0) === ((_f = right == null ? void 0 : right.left) != null ? _f : 0) && ((_g = left == null ? void 0 : left.right) != null ? _g : 0) === ((_h = right == null ? void 0 : right.right) != null ? _h : 0);
1852
- }
1853
- function setContentInsetOverride(ctx, inset) {
1854
- const { state } = ctx;
1855
- const previousInset = state.contentInsetOverride;
1856
- const nextInset = inset != null ? inset : void 0;
1857
- const didChange = !areInsetsEqual(previousInset, nextInset);
1858
- state.contentInsetOverride = nextInset;
1859
- if (didChange) {
1860
- updateContentMetrics(ctx);
1861
- }
1862
- return didChange;
1863
- }
1864
- function useStableRenderComponent(renderComponent, mapProps) {
1865
- const renderComponentRef = useLatestRef(renderComponent);
1866
- const mapPropsRef = useLatestRef(mapProps);
1867
- return React3__namespace.useMemo(
1868
- () => React3__namespace.forwardRef(
1869
- (props, ref) => {
1870
- var _a3, _b;
1871
- return (_b = (_a3 = renderComponentRef.current) == null ? void 0 : _a3.call(renderComponentRef, mapPropsRef.current(props, ref))) != null ? _b : null;
1872
- }
1873
- ),
1874
- [mapPropsRef, renderComponentRef]
1875
- );
1876
- }
1877
- var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1878
- const localRef = React3.useRef(null);
1879
- const ref = refView != null ? refView : localRef;
1880
- useOnLayoutSync({ onLayoutChange, ref });
1881
- return /* @__PURE__ */ React3__namespace.createElement("div", { ...rest, ref }, children);
1882
- };
1883
1876
 
1884
- // src/components/ListComponent.tsx
1885
- var ListComponent = typedMemo(function ListComponent2({
1886
- canRender,
1887
- style,
1888
- contentContainerStyle,
1889
- horizontal,
1890
- initialContentOffset,
1891
- recycleItems,
1892
- ItemSeparatorComponent,
1893
- alignItemsAtEnd: _alignItemsAtEnd,
1894
- onScroll: onScroll2,
1895
- onLayout,
1896
- ListHeaderComponent,
1897
- ListHeaderComponentStyle,
1898
- ListFooterComponent,
1899
- ListFooterComponentStyle,
1900
- ListEmptyComponent,
1901
- getRenderedItem: getRenderedItem2,
1902
- updateItemSize: updateItemSize2,
1903
- refScrollView,
1904
- renderScrollComponent,
1905
- onLayoutFooter,
1906
- scrollAdjustHandler,
1907
- snapToIndices,
1908
- stickyHeaderConfig,
1909
- stickyHeaderIndices,
1910
- useWindowScroll = false,
1911
- ...rest
1912
- }) {
1913
- const ctx = useStateContext();
1914
- const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1915
- const [alignItemsAtEndPadding = 0, otherAxisSize = 0] = useArr$(["alignItemsAtEndPadding", "otherAxisSize"]);
1916
- const autoOtherAxisStyle = getAutoOtherAxisStyle({
1917
- horizontal,
1918
- needsOtherAxisSize: ctx.state.needsOtherAxisSize,
1919
- otherAxisSize
1920
- });
1921
- const CustomScrollComponent = useStableRenderComponent(
1922
- renderScrollComponent,
1923
- (props, ref) => ({ ...props, ref })
1924
- );
1925
- const ScrollComponent = renderScrollComponent ? CustomScrollComponent : ListComponentScrollView;
1926
- const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1927
- React3.useLayoutEffect(() => {
1928
- if (!ListHeaderComponent) {
1929
- setHeaderSize(ctx, 0);
1930
- }
1931
- if (!ListFooterComponent) {
1932
- setFooterSize(ctx, 0);
1877
+ // src/core/addTotalSize.ts
1878
+ function addTotalSize(ctx, key, add, notifyTotalSize = true) {
1879
+ const state = ctx.state;
1880
+ const prevTotalSize = state.totalSize;
1881
+ let totalSize = state.totalSize;
1882
+ if (key === null) {
1883
+ totalSize = add;
1884
+ if (state.timeoutSetPaddingTop) {
1885
+ clearTimeout(state.timeoutSetPaddingTop);
1886
+ state.timeoutSetPaddingTop = void 0;
1933
1887
  }
1934
- }, [ListHeaderComponent, ListFooterComponent, ctx]);
1935
- const onLayoutHeader = React3.useCallback(
1936
- (rect) => {
1937
- const size = rect[horizontal ? "width" : "height"];
1938
- setHeaderSize(ctx, size);
1939
- },
1940
- [ctx, horizontal]
1941
- );
1942
- const onLayoutFooterInternal = React3.useCallback(
1943
- (rect, fromLayoutEffect) => {
1944
- const size = rect[horizontal ? "width" : "height"];
1945
- setFooterSize(ctx, size);
1946
- onLayoutFooter == null ? void 0 : onLayoutFooter(rect, fromLayoutEffect);
1947
- },
1948
- [ctx, horizontal, onLayoutFooter]
1949
- );
1950
- return /* @__PURE__ */ React3__namespace.createElement(
1951
- SnapOrScroll,
1888
+ } else {
1889
+ totalSize += add;
1890
+ }
1891
+ if (prevTotalSize !== totalSize) {
1952
1892
  {
1953
- ...rest,
1954
- ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1955
- contentContainerStyle: [
1956
- horizontal ? {
1957
- height: "100%"
1958
- } : {},
1959
- contentContainerStyle
1960
- ],
1961
- contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1962
- horizontal,
1963
- maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
1964
- onLayout,
1965
- onScroll: onScroll2,
1966
- ref: refScrollView,
1967
- ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1968
- style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
1969
- },
1970
- /* @__PURE__ */ React3__namespace.createElement(ScrollAdjust, null),
1971
- ListHeaderComponent && /* @__PURE__ */ React3__namespace.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
1972
- ListEmptyComponent && getComponent(ListEmptyComponent),
1973
- alignItemsAtEndPadding > 0 && /* @__PURE__ */ React3__namespace.createElement(
1974
- View,
1975
- {
1976
- style: horizontal ? { flexShrink: 0, width: alignItemsAtEndPadding } : { flexShrink: 0, height: alignItemsAtEndPadding }
1977
- },
1978
- null
1979
- ),
1980
- canRender && !ListEmptyComponent && /* @__PURE__ */ React3__namespace.createElement(
1981
- Containers,
1982
- {
1983
- getRenderedItem: getRenderedItem2,
1984
- horizontal,
1985
- ItemSeparatorComponent,
1986
- recycleItems,
1987
- stickyHeaderConfig,
1988
- updateItemSize: updateItemSize2
1893
+ state.pendingTotalSize = void 0;
1894
+ state.totalSize = totalSize;
1895
+ if (notifyTotalSize) {
1896
+ set$(ctx, "totalSize", totalSize);
1989
1897
  }
1990
- ),
1991
- ListFooterComponent && /* @__PURE__ */ React3__namespace.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
1992
- /* @__PURE__ */ React3__namespace.createElement(WebAnchoredEndSpace, { horizontal }),
1993
- IS_DEV && ENABLE_DEVMODE
1994
- );
1995
- });
1996
- var WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH = 100;
1997
- var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
1998
- var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
1999
- function useDevChecksImpl(props) {
2000
- const ctx = useStateContext();
2001
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
2002
- React3.useEffect(() => {
2003
- if (useWindowScroll && renderScrollComponent) {
2004
- warnDevOnce(
2005
- "useWindowScrollRenderScrollComponent",
2006
- "useWindowScroll is not supported when renderScrollComponent is provided."
2007
- );
2008
- }
2009
- }, [renderScrollComponent, useWindowScroll]);
2010
- React3.useEffect(() => {
2011
- if (!keyExtractor && !ctx.state.isFirst && ctx.state.didDataChange && !childrenMode) {
2012
- warnDevOnce(
2013
- "keyExtractor",
2014
- "Changing data without a keyExtractor can cause slow performance and resetting scroll. If your list data can change you should use a keyExtractor with a unique id for best performance and behavior."
2015
- );
2016
- }
2017
- }, [childrenMode, ctx, keyExtractor]);
2018
- React3.useEffect(() => {
2019
- const state = ctx.state;
2020
- const dataLength = state.props.data.length;
2021
- const useWindowScrollResolved = state.props.useWindowScroll;
2022
- if (useWindowScrollResolved || dataLength < WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH) {
2023
- return;
1898
+ updateContentMetricsState(ctx);
2024
1899
  }
2025
- const warnIfUnboundedOuterSize = () => {
2026
- const readyToRender = peek$(ctx, "readyToRender");
2027
- const numContainers = peek$(ctx, "numContainers") || 0;
2028
- const totalSize = peek$(ctx, "totalSize") || 0;
2029
- const scrollLength = ctx.state.scrollLength || 0;
2030
- if (!readyToRender || totalSize <= 0 || scrollLength <= 0) {
2031
- return;
2032
- }
2033
- const rendersAlmostEverything = numContainers >= Math.ceil(dataLength * WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO);
2034
- const viewportMatchesContent = scrollLength >= totalSize * WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO;
2035
- if (rendersAlmostEverything && viewportMatchesContent) {
2036
- warnDevOnce(
2037
- "webUnboundedOuterSize",
2038
- "LegendList appears to have an unbounded outer height on web, so virtualization is effectively disabled. Set a bounded height or flex: 1 on the list container, or use useWindowScroll."
2039
- );
2040
- }
2041
- };
2042
- warnIfUnboundedOuterSize();
2043
- const unsubscribe = [
2044
- listen$(ctx, "numContainers", warnIfUnboundedOuterSize),
2045
- listen$(ctx, "readyToRender", warnIfUnboundedOuterSize),
2046
- listen$(ctx, "totalSize", warnIfUnboundedOuterSize)
2047
- ];
2048
- return () => {
2049
- for (const unsub of unsubscribe) {
2050
- unsub();
2051
- }
2052
- };
2053
- }, [ctx]);
2054
- }
2055
- function useDevChecksNoop(_props) {
1900
+ } else if (notifyTotalSize && ctx.values.get("totalSize") !== totalSize) {
1901
+ set$(ctx, "totalSize", totalSize);
1902
+ }
2056
1903
  }
2057
- var useDevChecks = IS_DEV ? useDevChecksImpl : useDevChecksNoop;
2058
1904
 
2059
1905
  // src/core/deferredPublicOnScroll.ts
2060
1906
  function withResolvedContentOffset(state, event, resolvedOffset) {
@@ -2367,6 +2213,66 @@ function recalculateSettledScroll(ctx) {
2367
2213
  checkThresholds(ctx);
2368
2214
  }
2369
2215
 
2216
+ // src/core/adaptiveRender.ts
2217
+ var DEFAULT_ENTER_VELOCITY = 4;
2218
+ var DEFAULT_EXIT_VELOCITY = 1;
2219
+ var DEFAULT_EXIT_DELAY = 1e3;
2220
+ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
2221
+ const state = ctx.state;
2222
+ const previousTimeout = state.timeoutAdaptiveRender;
2223
+ if (previousTimeout !== void 0) {
2224
+ clearTimeout(previousTimeout);
2225
+ state.timeouts.delete(previousTimeout);
2226
+ state.timeoutAdaptiveRender = void 0;
2227
+ }
2228
+ if (exitDelay <= 0) {
2229
+ setAdaptiveRender(ctx, "normal");
2230
+ } else {
2231
+ const timeout = setTimeout(() => {
2232
+ state.timeouts.delete(timeout);
2233
+ state.timeoutAdaptiveRender = void 0;
2234
+ setAdaptiveRender(ctx, "normal");
2235
+ }, exitDelay);
2236
+ state.timeoutAdaptiveRender = timeout;
2237
+ state.timeouts.add(timeout);
2238
+ }
2239
+ }
2240
+ function setAdaptiveRender(ctx, mode) {
2241
+ var _a3, _b;
2242
+ const previousMode = peek$(ctx, "adaptiveRender");
2243
+ if (previousMode !== mode) {
2244
+ set$(ctx, "adaptiveRender", mode);
2245
+ (_b = (_a3 = ctx.state.props.adaptiveRender) == null ? void 0 : _a3.onChange) == null ? void 0 : _b.call(_a3, mode);
2246
+ }
2247
+ }
2248
+ function updateAdaptiveRender(ctx, scrollVelocity) {
2249
+ var _a3, _b, _c;
2250
+ const state = ctx.state;
2251
+ const adaptiveRender = state.props.adaptiveRender;
2252
+ const enterVelocity = (_a3 = adaptiveRender == null ? void 0 : adaptiveRender.enterVelocity) != null ? _a3 : DEFAULT_ENTER_VELOCITY;
2253
+ const exitVelocity = (_b = adaptiveRender == null ? void 0 : adaptiveRender.exitVelocity) != null ? _b : DEFAULT_EXIT_VELOCITY;
2254
+ const exitDelay = (_c = adaptiveRender == null ? void 0 : adaptiveRender.exitDelay) != null ? _c : DEFAULT_EXIT_DELAY;
2255
+ const currentMode = peek$(ctx, "adaptiveRender");
2256
+ const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
2257
+ const nextMode = Math.abs(scrollVelocity) > threshold ? "light" : "normal";
2258
+ const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
2259
+ if (nextMode !== previousMode) {
2260
+ if (nextMode === "light") {
2261
+ setAdaptiveRender(ctx, "light");
2262
+ scheduleAdaptiveRenderExit(ctx, exitDelay);
2263
+ } else if (currentMode === "light") {
2264
+ scheduleAdaptiveRenderExit(ctx, exitDelay);
2265
+ }
2266
+ }
2267
+ }
2268
+
2269
+ // src/utils/getEffectiveDrawDistance.ts
2270
+ var INITIAL_DRAW_DISTANCE = 100;
2271
+ function getEffectiveDrawDistance(ctx) {
2272
+ const drawDistance = ctx.state.props.drawDistance;
2273
+ return peek$(ctx, "readyToRender") ? drawDistance : Math.min(drawDistance, INITIAL_DRAW_DISTANCE);
2274
+ }
2275
+
2370
2276
  // src/utils/setInitialRenderState.ts
2371
2277
  function setInitialRenderState(ctx, {
2372
2278
  didLayout,
@@ -2386,8 +2292,15 @@ function setInitialRenderState(ctx, {
2386
2292
  const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
2387
2293
  if (isReadyToRender && !peek$(ctx, "readyToRender")) {
2388
2294
  set$(ctx, "readyToRender", true);
2389
- if (onLoad) {
2390
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2295
+ setAdaptiveRender(ctx, "normal");
2296
+ if (state.props.drawDistance > INITIAL_DRAW_DISTANCE) {
2297
+ requestAnimationFrame(() => {
2298
+ var _a3;
2299
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
2300
+ });
2301
+ }
2302
+ if (onLoad) {
2303
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2391
2304
  }
2392
2305
  }
2393
2306
  }
@@ -2460,200 +2373,6 @@ function finishInitialScroll(ctx, options) {
2460
2373
  complete();
2461
2374
  }
2462
2375
 
2463
- // src/core/calculateOffsetForIndex.ts
2464
- function calculateOffsetForIndex(ctx, index) {
2465
- const state = ctx.state;
2466
- return index !== void 0 ? state.positions[index] || 0 : 0;
2467
- }
2468
-
2469
- // src/core/getTopOffsetAdjustment.ts
2470
- function getTopOffsetAdjustment(ctx) {
2471
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
2472
- }
2473
-
2474
- // src/utils/getId.ts
2475
- function getId(state, index) {
2476
- const { data, keyExtractor } = state.props;
2477
- if (!data) {
2478
- return "";
2479
- }
2480
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
2481
- const id = ret;
2482
- state.idCache[index] = id;
2483
- return id;
2484
- }
2485
-
2486
- // src/core/addTotalSize.ts
2487
- function addTotalSize(ctx, key, add, notifyTotalSize = true) {
2488
- const state = ctx.state;
2489
- const prevTotalSize = state.totalSize;
2490
- let totalSize = state.totalSize;
2491
- if (key === null) {
2492
- totalSize = add;
2493
- if (state.timeoutSetPaddingTop) {
2494
- clearTimeout(state.timeoutSetPaddingTop);
2495
- state.timeoutSetPaddingTop = void 0;
2496
- }
2497
- } else {
2498
- totalSize += add;
2499
- }
2500
- if (prevTotalSize !== totalSize) {
2501
- {
2502
- state.pendingTotalSize = void 0;
2503
- state.totalSize = totalSize;
2504
- if (notifyTotalSize) {
2505
- set$(ctx, "totalSize", totalSize);
2506
- }
2507
- updateContentMetrics(ctx);
2508
- }
2509
- } else if (notifyTotalSize && ctx.values.get("totalSize") !== totalSize) {
2510
- set$(ctx, "totalSize", totalSize);
2511
- }
2512
- }
2513
-
2514
- // src/core/setSize.ts
2515
- function setSize(ctx, itemKey, size, notifyTotalSize = true) {
2516
- const state = ctx.state;
2517
- const { sizes } = state;
2518
- const previousSize = sizes.get(itemKey);
2519
- const diff = previousSize !== void 0 ? size - previousSize : size;
2520
- if (diff !== 0) {
2521
- addTotalSize(ctx, itemKey, diff, notifyTotalSize);
2522
- }
2523
- sizes.set(itemKey, size);
2524
- }
2525
-
2526
- // src/utils/getItemSize.ts
2527
- function getKnownOrFixedSize(ctx, key, index, data, resolved) {
2528
- var _a3, _b;
2529
- const state = ctx.state;
2530
- const { getFixedItemSize, getItemType } = state.props;
2531
- let size = key ? state.sizesKnown.get(key) : void 0;
2532
- if (size === void 0 && key && getFixedItemSize) {
2533
- const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
2534
- size = (resolved == null ? void 0 : resolved.didResolveFixedItemSize) ? resolved.fixedItemSize : getFixedItemSize(data, index, itemType);
2535
- if (size !== void 0) {
2536
- state.sizesKnown.set(key, size);
2537
- }
2538
- }
2539
- return size;
2540
- }
2541
- function getKnownOrFixedItemSize(ctx, index) {
2542
- const key = getId(ctx.state, index);
2543
- return getKnownOrFixedSize(ctx, key, index, ctx.state.props.data[index]);
2544
- }
2545
- function areKnownOrFixedItemSizesAvailable(ctx, startIndex, endIndex) {
2546
- for (let index = startIndex; index <= endIndex; index++) {
2547
- if (getKnownOrFixedItemSize(ctx, index) === void 0) {
2548
- return false;
2549
- }
2550
- }
2551
- return true;
2552
- }
2553
- function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, notifyTotalSize, resolved) {
2554
- var _a3, _b, _c, _d;
2555
- const state = ctx.state;
2556
- const {
2557
- sizes,
2558
- averageSizes,
2559
- props: { estimatedItemSize, getItemType },
2560
- scrollingTo
2561
- } = state;
2562
- const sizeKnown = state.sizesKnown.get(key);
2563
- if (sizeKnown !== void 0) {
2564
- return sizeKnown;
2565
- }
2566
- let size;
2567
- const renderedSize = sizes.get(key);
2568
- if (preferCachedSize) {
2569
- if (renderedSize !== void 0) {
2570
- return renderedSize;
2571
- }
2572
- }
2573
- size = getKnownOrFixedSize(ctx, key, index, data, resolved);
2574
- if (size !== void 0) {
2575
- setSize(ctx, key, size, notifyTotalSize);
2576
- return size;
2577
- }
2578
- const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
2579
- if (useAverageSize && !scrollingTo) {
2580
- const averageSizeForType = (_c = averageSizes[itemType]) == null ? void 0 : _c.avg;
2581
- if (averageSizeForType !== void 0) {
2582
- size = roundSize(averageSizeForType);
2583
- }
2584
- }
2585
- if (size === void 0 && renderedSize !== void 0) {
2586
- return renderedSize;
2587
- }
2588
- if (size === void 0 && useAverageSize && scrollingTo) {
2589
- const averageSizeForType = (_d = scrollingTo.averageSizeSnapshot) == null ? void 0 : _d[itemType];
2590
- if (averageSizeForType !== void 0) {
2591
- size = roundSize(averageSizeForType);
2592
- }
2593
- }
2594
- if (size === void 0) {
2595
- size = estimatedItemSize;
2596
- }
2597
- setSize(ctx, key, size, notifyTotalSize);
2598
- return size;
2599
- }
2600
- function getItemSizeAtIndex(ctx, index) {
2601
- if (index === void 0 || index < 0) {
2602
- return void 0;
2603
- }
2604
- const targetId = getId(ctx.state, index);
2605
- return getItemSize(ctx, targetId, index, ctx.state.props.data[index]);
2606
- }
2607
-
2608
- // src/core/calculateOffsetWithOffsetPosition.ts
2609
- function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
2610
- var _a3;
2611
- const state = ctx.state;
2612
- const { index, viewOffset, viewPosition } = params;
2613
- let offset = offsetParam;
2614
- if (viewOffset) {
2615
- offset -= viewOffset;
2616
- }
2617
- if (index !== void 0) {
2618
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
2619
- if (topOffsetAdjustment) {
2620
- offset += topOffsetAdjustment;
2621
- }
2622
- }
2623
- if (viewPosition !== void 0 && index !== void 0) {
2624
- const dataLength = state.props.data.length;
2625
- if (dataLength === 0) {
2626
- return offset;
2627
- }
2628
- const isOutOfBounds = index < 0 || index >= dataLength;
2629
- const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
2630
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
2631
- const trailingInset = getContentInsetEnd(ctx);
2632
- offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
2633
- if (!isOutOfBounds && index === state.props.data.length - 1) {
2634
- const footerSize = peek$(ctx, "footerSize") || 0;
2635
- offset += footerSize;
2636
- }
2637
- }
2638
- return offset;
2639
- }
2640
-
2641
- // src/core/clampScrollOffset.ts
2642
- function clampScrollOffset(ctx, offset, scrollTarget) {
2643
- const state = ctx.state;
2644
- const contentSize = getContentSize(ctx);
2645
- let clampedOffset = offset;
2646
- if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android")) {
2647
- const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
2648
- const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
2649
- const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
2650
- const maxOffset = baseMaxOffset + extraEndOffset;
2651
- clampedOffset = Math.min(offset, maxOffset);
2652
- }
2653
- clampedOffset = Math.max(0, clampedOffset);
2654
- return clampedOffset;
2655
- }
2656
-
2657
2376
  // src/core/finishScrollTo.ts
2658
2377
  function finishScrollTo(ctx) {
2659
2378
  var _a3, _b;
@@ -2730,50 +2449,491 @@ function listenForScrollEnd(ctx, params) {
2730
2449
  finishScrollTo(ctx);
2731
2450
  return;
2732
2451
  }
2733
- const supportsScrollEnd = "onscrollend" in target;
2734
- let idleTimeout;
2735
- let settled = false;
2736
- const targetToken = ctx.state.scrollingTo;
2737
- const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
2738
- const cleanup = () => {
2739
- target.removeEventListener("scroll", onScroll2);
2740
- if (supportsScrollEnd) {
2741
- target.removeEventListener("scrollend", onScrollEnd);
2452
+ const supportsScrollEnd = "onscrollend" in target;
2453
+ let idleTimeout;
2454
+ let settled = false;
2455
+ const targetToken = ctx.state.scrollingTo;
2456
+ const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
2457
+ const cleanup = () => {
2458
+ target.removeEventListener("scroll", onScroll2);
2459
+ if (supportsScrollEnd) {
2460
+ target.removeEventListener("scrollend", onScrollEnd);
2461
+ }
2462
+ if (idleTimeout) {
2463
+ clearTimeout(idleTimeout);
2464
+ }
2465
+ clearTimeout(maxTimeout);
2466
+ };
2467
+ const finish = (reason) => {
2468
+ if (settled) return;
2469
+ if (targetToken !== ctx.state.scrollingTo) {
2470
+ settled = true;
2471
+ cleanup();
2472
+ return;
2473
+ }
2474
+ const currentOffset = readOffset();
2475
+ const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
2476
+ if (reason === "scrollend" && !isNearTarget) {
2477
+ return;
2478
+ }
2479
+ settled = true;
2480
+ cleanup();
2481
+ finishScrollTo(ctx);
2482
+ };
2483
+ const onScroll2 = () => {
2484
+ if (idleTimeout) {
2485
+ clearTimeout(idleTimeout);
2486
+ }
2487
+ idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
2488
+ };
2489
+ const onScrollEnd = () => finish("scrollend");
2490
+ target.addEventListener("scroll", onScroll2);
2491
+ if (supportsScrollEnd) {
2492
+ target.addEventListener("scrollend", onScrollEnd);
2493
+ } else {
2494
+ idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
2495
+ }
2496
+ }
2497
+
2498
+ // src/utils/requestAdjust.ts
2499
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2500
+ const state = ctx.state;
2501
+ if (Math.abs(positionDiff) > 0.1) {
2502
+ const doit = () => {
2503
+ {
2504
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
2505
+ if (state.adjustingFromInitialMount) {
2506
+ state.adjustingFromInitialMount--;
2507
+ }
2508
+ }
2509
+ };
2510
+ state.scroll += positionDiff;
2511
+ state.scrollForNextCalculateItemsInView = void 0;
2512
+ const readyToRender = peek$(ctx, "readyToRender");
2513
+ if (readyToRender) {
2514
+ doit();
2515
+ } else {
2516
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2517
+ requestAnimationFrame(doit);
2518
+ }
2519
+ }
2520
+ }
2521
+
2522
+ // src/core/updateContentMetrics.ts
2523
+ var SCROLL_ADJUST_EPSILON = 0.1;
2524
+ function setContentLengthSignal(ctx, signalName, size) {
2525
+ if (peek$(ctx, signalName) !== size) {
2526
+ set$(ctx, signalName, size);
2527
+ updateContentMetricsState(ctx);
2528
+ }
2529
+ }
2530
+ function shouldAdjustForHeaderSizeChange(ctx, previousHeaderSize, nextHeaderSize) {
2531
+ const { didContainersLayout, didFinishInitialScroll, props, scroll, scrollingTo } = ctx.state;
2532
+ const sizeDiff = nextHeaderSize - previousHeaderSize;
2533
+ const leadingPadding = props.horizontal ? props.stylePaddingLeft : props.stylePaddingTop;
2534
+ const previousHeaderEnd = (leadingPadding || 0) + previousHeaderSize;
2535
+ return props.maintainVisibleContentPosition.size && didContainersLayout && didFinishInitialScroll && !scrollingTo && scroll >= previousHeaderEnd - SCROLL_ADJUST_EPSILON && Math.abs(sizeDiff) > SCROLL_ADJUST_EPSILON;
2536
+ }
2537
+ function setHeaderSize(ctx, size) {
2538
+ const { state } = ctx;
2539
+ const previousHeaderSize = peek$(ctx, "headerSize") || 0;
2540
+ const didChange = previousHeaderSize !== size;
2541
+ const hasMeasuredOrEstimatedHeaderBaseline = state.didMeasureHeader || previousHeaderSize > SCROLL_ADJUST_EPSILON;
2542
+ if (didChange) {
2543
+ set$(ctx, "headerSize", size);
2544
+ updateContentMetricsState(ctx);
2545
+ if (hasMeasuredOrEstimatedHeaderBaseline && shouldAdjustForHeaderSizeChange(ctx, previousHeaderSize, size)) {
2546
+ requestAdjust(ctx, size - previousHeaderSize);
2547
+ }
2548
+ }
2549
+ state.didMeasureHeader = true;
2550
+ }
2551
+ function setFooterSize(ctx, size) {
2552
+ setContentLengthSignal(ctx, "footerSize", size);
2553
+ }
2554
+ function areInsetsEqual(left, right) {
2555
+ var _a3, _b, _c, _d, _e, _f, _g, _h;
2556
+ return ((_a3 = left == null ? void 0 : left.top) != null ? _a3 : 0) === ((_b = right == null ? void 0 : right.top) != null ? _b : 0) && ((_c = left == null ? void 0 : left.bottom) != null ? _c : 0) === ((_d = right == null ? void 0 : right.bottom) != null ? _d : 0) && ((_e = left == null ? void 0 : left.left) != null ? _e : 0) === ((_f = right == null ? void 0 : right.left) != null ? _f : 0) && ((_g = left == null ? void 0 : left.right) != null ? _g : 0) === ((_h = right == null ? void 0 : right.right) != null ? _h : 0);
2557
+ }
2558
+ function setContentInsetOverride(ctx, inset) {
2559
+ const { state } = ctx;
2560
+ const previousInset = state.contentInsetOverride;
2561
+ const nextInset = inset != null ? inset : void 0;
2562
+ const didChange = !areInsetsEqual(previousInset, nextInset);
2563
+ state.contentInsetOverride = nextInset;
2564
+ if (didChange) {
2565
+ updateContentMetricsState(ctx);
2566
+ }
2567
+ return didChange;
2568
+ }
2569
+ function useStableRenderComponent(renderComponent, mapProps) {
2570
+ const renderComponentRef = useLatestRef(renderComponent);
2571
+ const mapPropsRef = useLatestRef(mapProps);
2572
+ return React3__namespace.useMemo(
2573
+ () => React3__namespace.forwardRef(
2574
+ (props, ref) => {
2575
+ var _a3, _b;
2576
+ return (_b = (_a3 = renderComponentRef.current) == null ? void 0 : _a3.call(renderComponentRef, mapPropsRef.current(props, ref))) != null ? _b : null;
2577
+ }
2578
+ ),
2579
+ [mapPropsRef, renderComponentRef]
2580
+ );
2581
+ }
2582
+ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
2583
+ const localRef = React3.useRef(null);
2584
+ const ref = refView != null ? refView : localRef;
2585
+ useOnLayoutSync({ onLayoutChange, ref });
2586
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ...rest, ref }, children);
2587
+ };
2588
+
2589
+ // src/components/ListComponent.tsx
2590
+ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizontal }) {
2591
+ const [alignItemsAtEndPadding = 0] = useArr$(["alignItemsAtEndPadding"]);
2592
+ if (alignItemsAtEndPadding <= 0) {
2593
+ return null;
2594
+ }
2595
+ return /* @__PURE__ */ React3__namespace.createElement(
2596
+ View,
2597
+ {
2598
+ style: horizontal ? { flexShrink: 0, width: alignItemsAtEndPadding } : { flexShrink: 0, height: alignItemsAtEndPadding }
2599
+ },
2600
+ null
2601
+ );
2602
+ });
2603
+ var ListComponent = typedMemo(function ListComponent2({
2604
+ canRender,
2605
+ style,
2606
+ contentContainerStyle,
2607
+ horizontal,
2608
+ initialContentOffset,
2609
+ recycleItems,
2610
+ ItemSeparatorComponent,
2611
+ alignItemsAtEnd: _alignItemsAtEnd,
2612
+ onScroll: onScroll2,
2613
+ onLayout,
2614
+ ListHeaderComponent,
2615
+ ListHeaderComponentStyle,
2616
+ ListFooterComponent,
2617
+ ListFooterComponentStyle,
2618
+ ListEmptyComponent,
2619
+ getRenderedItem: getRenderedItem2,
2620
+ updateItemSize: updateItemSize2,
2621
+ refScrollView,
2622
+ renderScrollComponent,
2623
+ onLayoutFooter,
2624
+ scrollAdjustHandler,
2625
+ snapToIndices,
2626
+ stickyHeaderConfig,
2627
+ stickyHeaderIndices,
2628
+ useWindowScroll = false,
2629
+ ...rest
2630
+ }) {
2631
+ const ctx = useStateContext();
2632
+ const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
2633
+ const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
2634
+ const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
2635
+ const autoOtherAxisStyle = getAutoOtherAxisStyle({
2636
+ horizontal,
2637
+ needsOtherAxisSize: ctx.state.needsOtherAxisSize,
2638
+ otherAxisSize
2639
+ });
2640
+ const CustomScrollComponent = useStableRenderComponent(
2641
+ renderScrollComponent,
2642
+ (props, ref) => ({ ...props, ref })
2643
+ );
2644
+ const ScrollComponent = renderScrollComponent ? CustomScrollComponent : ListComponentScrollView;
2645
+ const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
2646
+ React3.useLayoutEffect(() => {
2647
+ if (!ListHeaderComponent) {
2648
+ setHeaderSize(ctx, 0);
2649
+ }
2650
+ if (!ListFooterComponent) {
2651
+ setFooterSize(ctx, 0);
2652
+ }
2653
+ }, [ListHeaderComponent, ListFooterComponent, ctx]);
2654
+ const onLayoutHeader = React3.useCallback(
2655
+ (rect) => {
2656
+ const size = rect[horizontal ? "width" : "height"];
2657
+ setHeaderSize(ctx, size);
2658
+ },
2659
+ [ctx, horizontal]
2660
+ );
2661
+ const onLayoutFooterInternal = React3.useCallback(
2662
+ (rect, fromLayoutEffect) => {
2663
+ const size = rect[horizontal ? "width" : "height"];
2664
+ setFooterSize(ctx, size);
2665
+ onLayoutFooter == null ? void 0 : onLayoutFooter(rect, fromLayoutEffect);
2666
+ },
2667
+ [ctx, horizontal, onLayoutFooter]
2668
+ );
2669
+ return /* @__PURE__ */ React3__namespace.createElement(
2670
+ SnapOrScroll,
2671
+ {
2672
+ ...rest,
2673
+ ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
2674
+ contentContainerStyle: [
2675
+ horizontal ? {
2676
+ height: "100%"
2677
+ } : {},
2678
+ contentContainerStyle
2679
+ ],
2680
+ contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
2681
+ horizontal,
2682
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
2683
+ onLayout,
2684
+ onScroll: onScroll2,
2685
+ ref: refScrollView,
2686
+ ScrollComponent: snapToIndices ? ScrollComponent : void 0,
2687
+ style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
2688
+ },
2689
+ /* @__PURE__ */ React3__namespace.createElement(ScrollAdjust, null),
2690
+ ListHeaderComponent && /* @__PURE__ */ React3__namespace.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
2691
+ ListEmptyComponent && getComponent(ListEmptyComponent),
2692
+ shouldRenderAlignItemsAtEndSpacer && /* @__PURE__ */ React3__namespace.createElement(AlignItemsAtEndSpacer, { horizontal }),
2693
+ canRender && !ListEmptyComponent && /* @__PURE__ */ React3__namespace.createElement(
2694
+ Containers,
2695
+ {
2696
+ getRenderedItem: getRenderedItem2,
2697
+ horizontal,
2698
+ ItemSeparatorComponent,
2699
+ recycleItems,
2700
+ stickyHeaderConfig,
2701
+ updateItemSize: updateItemSize2
2702
+ }
2703
+ ),
2704
+ ListFooterComponent && /* @__PURE__ */ React3__namespace.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
2705
+ /* @__PURE__ */ React3__namespace.createElement(WebAnchoredEndSpace, { horizontal }),
2706
+ IS_DEV && ENABLE_DEVMODE
2707
+ );
2708
+ });
2709
+ var WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH = 100;
2710
+ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
2711
+ var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
2712
+ function useDevChecksImpl(props) {
2713
+ const ctx = useStateContext();
2714
+ const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
2715
+ React3.useEffect(() => {
2716
+ if (useWindowScroll && renderScrollComponent) {
2717
+ warnDevOnce(
2718
+ "useWindowScrollRenderScrollComponent",
2719
+ "useWindowScroll is not supported when renderScrollComponent is provided."
2720
+ );
2721
+ }
2722
+ }, [renderScrollComponent, useWindowScroll]);
2723
+ React3.useEffect(() => {
2724
+ if (!keyExtractor && !ctx.state.isFirst && ctx.state.didDataChange && !childrenMode) {
2725
+ warnDevOnce(
2726
+ "keyExtractor",
2727
+ "Changing data without a keyExtractor can cause slow performance and resetting scroll. If your list data can change you should use a keyExtractor with a unique id for best performance and behavior."
2728
+ );
2729
+ }
2730
+ }, [childrenMode, ctx, keyExtractor]);
2731
+ React3.useEffect(() => {
2732
+ const state = ctx.state;
2733
+ const dataLength = state.props.data.length;
2734
+ const useWindowScrollResolved = state.props.useWindowScroll;
2735
+ if (useWindowScrollResolved || dataLength < WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH) {
2736
+ return;
2737
+ }
2738
+ const warnIfUnboundedOuterSize = () => {
2739
+ const readyToRender = peek$(ctx, "readyToRender");
2740
+ const numContainers = peek$(ctx, "numContainers") || 0;
2741
+ const totalSize = peek$(ctx, "totalSize") || 0;
2742
+ const scrollLength = ctx.state.scrollLength || 0;
2743
+ if (!readyToRender || totalSize <= 0 || scrollLength <= 0) {
2744
+ return;
2745
+ }
2746
+ const rendersAlmostEverything = numContainers >= Math.ceil(dataLength * WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO);
2747
+ const viewportMatchesContent = scrollLength >= totalSize * WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO;
2748
+ if (rendersAlmostEverything && viewportMatchesContent) {
2749
+ warnDevOnce(
2750
+ "webUnboundedOuterSize",
2751
+ "LegendList appears to have an unbounded outer height on web, so virtualization is effectively disabled. Set a bounded height or flex: 1 on the list container, or use useWindowScroll."
2752
+ );
2753
+ }
2754
+ };
2755
+ warnIfUnboundedOuterSize();
2756
+ const unsubscribe = [
2757
+ listen$(ctx, "numContainers", warnIfUnboundedOuterSize),
2758
+ listen$(ctx, "readyToRender", warnIfUnboundedOuterSize),
2759
+ listen$(ctx, "totalSize", warnIfUnboundedOuterSize)
2760
+ ];
2761
+ return () => {
2762
+ for (const unsub of unsubscribe) {
2763
+ unsub();
2764
+ }
2765
+ };
2766
+ }, [ctx]);
2767
+ }
2768
+ function useDevChecksNoop(_props) {
2769
+ }
2770
+ var useDevChecks = IS_DEV ? useDevChecksImpl : useDevChecksNoop;
2771
+
2772
+ // src/core/calculateOffsetForIndex.ts
2773
+ function calculateOffsetForIndex(ctx, index) {
2774
+ const state = ctx.state;
2775
+ return index !== void 0 ? state.positions[index] || 0 : 0;
2776
+ }
2777
+
2778
+ // src/core/getTopOffsetAdjustment.ts
2779
+ function getTopOffsetAdjustment(ctx) {
2780
+ return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
2781
+ }
2782
+
2783
+ // src/utils/getId.ts
2784
+ function getId(state, index) {
2785
+ const { data, keyExtractor } = state.props;
2786
+ if (!data) {
2787
+ return "";
2788
+ }
2789
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
2790
+ const id = ret;
2791
+ state.idCache[index] = id;
2792
+ return id;
2793
+ }
2794
+
2795
+ // src/core/setSize.ts
2796
+ function setSize(ctx, itemKey, size, notifyTotalSize = true) {
2797
+ const state = ctx.state;
2798
+ const { sizes } = state;
2799
+ const previousSize = sizes.get(itemKey);
2800
+ const diff = previousSize !== void 0 ? size - previousSize : size;
2801
+ if (diff !== 0) {
2802
+ addTotalSize(ctx, itemKey, diff, notifyTotalSize);
2803
+ }
2804
+ sizes.set(itemKey, size);
2805
+ }
2806
+
2807
+ // src/utils/getItemSize.ts
2808
+ function getKnownOrFixedSize(ctx, key, index, data, resolved) {
2809
+ var _a3, _b;
2810
+ const state = ctx.state;
2811
+ const { getFixedItemSize, getItemType } = state.props;
2812
+ let size = key ? state.sizesKnown.get(key) : void 0;
2813
+ if (size === void 0 && key && getFixedItemSize) {
2814
+ const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
2815
+ const fixedSize = (resolved == null ? void 0 : resolved.didResolveFixedItemSize) ? resolved.fixedItemSize : getFixedItemSize(data, index, itemType);
2816
+ if (fixedSize !== void 0) {
2817
+ size = fixedSize + ctx.scrollAxisGap;
2818
+ state.sizesKnown.set(key, size);
2819
+ }
2820
+ }
2821
+ return size;
2822
+ }
2823
+ function getKnownOrFixedItemSize(ctx, index) {
2824
+ const key = getId(ctx.state, index);
2825
+ return getKnownOrFixedSize(ctx, key, index, ctx.state.props.data[index]);
2826
+ }
2827
+ function areKnownOrFixedItemSizesAvailable(ctx, startIndex, endIndex) {
2828
+ for (let index = startIndex; index <= endIndex; index++) {
2829
+ if (getKnownOrFixedItemSize(ctx, index) === void 0) {
2830
+ return false;
2831
+ }
2832
+ }
2833
+ return true;
2834
+ }
2835
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, notifyTotalSize, resolved) {
2836
+ var _a3, _b, _c, _d;
2837
+ const state = ctx.state;
2838
+ const {
2839
+ sizes,
2840
+ averageSizes,
2841
+ props: { estimatedItemSize, getItemType },
2842
+ scrollingTo
2843
+ } = state;
2844
+ const sizeKnown = state.sizesKnown.get(key);
2845
+ if (sizeKnown !== void 0) {
2846
+ return sizeKnown;
2847
+ }
2848
+ let size;
2849
+ const renderedSize = sizes.get(key);
2850
+ if (preferCachedSize) {
2851
+ if (renderedSize !== void 0) {
2852
+ return renderedSize;
2853
+ }
2854
+ }
2855
+ size = getKnownOrFixedSize(ctx, key, index, data, resolved);
2856
+ if (size !== void 0) {
2857
+ setSize(ctx, key, size, notifyTotalSize);
2858
+ return size;
2859
+ }
2860
+ const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
2861
+ if (useAverageSize && !scrollingTo) {
2862
+ const averageSizeForType = (_c = averageSizes[itemType]) == null ? void 0 : _c.avg;
2863
+ if (averageSizeForType !== void 0) {
2864
+ size = roundSize(averageSizeForType);
2742
2865
  }
2743
- if (idleTimeout) {
2744
- clearTimeout(idleTimeout);
2866
+ }
2867
+ if (size === void 0 && renderedSize !== void 0) {
2868
+ return renderedSize;
2869
+ }
2870
+ if (size === void 0 && useAverageSize && scrollingTo) {
2871
+ const averageSizeForType = (_d = scrollingTo.averageSizeSnapshot) == null ? void 0 : _d[itemType];
2872
+ if (averageSizeForType !== void 0) {
2873
+ size = roundSize(averageSizeForType);
2745
2874
  }
2746
- clearTimeout(maxTimeout);
2747
- };
2748
- const finish = (reason) => {
2749
- if (settled) return;
2750
- if (targetToken !== ctx.state.scrollingTo) {
2751
- settled = true;
2752
- cleanup();
2753
- return;
2875
+ }
2876
+ if (size === void 0) {
2877
+ size = estimatedItemSize + ctx.scrollAxisGap;
2878
+ }
2879
+ setSize(ctx, key, size, notifyTotalSize);
2880
+ return size;
2881
+ }
2882
+ function getItemSizeAtIndex(ctx, index) {
2883
+ if (index === void 0 || index < 0) {
2884
+ return void 0;
2885
+ }
2886
+ const targetId = getId(ctx.state, index);
2887
+ return getItemSize(ctx, targetId, index, ctx.state.props.data[index]);
2888
+ }
2889
+
2890
+ // src/core/calculateOffsetWithOffsetPosition.ts
2891
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
2892
+ var _a3;
2893
+ const state = ctx.state;
2894
+ const { index, viewOffset, viewPosition } = params;
2895
+ let offset = offsetParam;
2896
+ if (viewOffset) {
2897
+ offset -= viewOffset;
2898
+ }
2899
+ if (index !== void 0) {
2900
+ const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
2901
+ if (topOffsetAdjustment) {
2902
+ offset += topOffsetAdjustment;
2754
2903
  }
2755
- const currentOffset = readOffset();
2756
- const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
2757
- if (reason === "scrollend" && !isNearTarget) {
2758
- return;
2904
+ }
2905
+ if (viewPosition !== void 0 && index !== void 0) {
2906
+ const dataLength = state.props.data.length;
2907
+ if (dataLength === 0) {
2908
+ return offset;
2759
2909
  }
2760
- settled = true;
2761
- cleanup();
2762
- finishScrollTo(ctx);
2763
- };
2764
- const onScroll2 = () => {
2765
- if (idleTimeout) {
2766
- clearTimeout(idleTimeout);
2910
+ const isOutOfBounds = index < 0 || index >= dataLength;
2911
+ const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
2912
+ const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
2913
+ const trailingInset = getContentInsetEnd(ctx);
2914
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
2915
+ if (!isOutOfBounds && index === state.props.data.length - 1) {
2916
+ const footerSize = peek$(ctx, "footerSize") || 0;
2917
+ offset += footerSize;
2767
2918
  }
2768
- idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
2769
- };
2770
- const onScrollEnd = () => finish("scrollend");
2771
- target.addEventListener("scroll", onScroll2);
2772
- if (supportsScrollEnd) {
2773
- target.addEventListener("scrollend", onScrollEnd);
2774
- } else {
2775
- idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
2776
2919
  }
2920
+ return offset;
2921
+ }
2922
+
2923
+ // src/core/clampScrollOffset.ts
2924
+ function clampScrollOffset(ctx, offset, scrollTarget) {
2925
+ const state = ctx.state;
2926
+ const contentSize = getContentSize(ctx);
2927
+ let clampedOffset = offset;
2928
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android")) {
2929
+ const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
2930
+ const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
2931
+ const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
2932
+ const maxOffset = baseMaxOffset + extraEndOffset;
2933
+ clampedOffset = Math.min(offset, maxOffset);
2934
+ }
2935
+ clampedOffset = Math.max(0, clampedOffset);
2936
+ return clampedOffset;
2777
2937
  }
2778
2938
 
2779
2939
  // src/core/doMaintainScrollAtEnd.ts
@@ -2798,9 +2958,12 @@ function doMaintainScrollAtEnd(ctx) {
2798
2958
  state.scroll = 0;
2799
2959
  }
2800
2960
  if (!state.maintainingScrollAtEnd) {
2801
- state.maintainingScrollAtEnd = true;
2961
+ const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
2962
+ const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
2963
+ state.maintainingScrollAtEnd = pendingState;
2802
2964
  requestAnimationFrame(() => {
2803
2965
  if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
2966
+ state.maintainingScrollAtEnd = activeState;
2804
2967
  const scroller = refScroller.current;
2805
2968
  if (state.props.horizontal && isHorizontalRTL(state)) {
2806
2969
  const currentContentSize = getContentSize(ctx);
@@ -2818,12 +2981,14 @@ function doMaintainScrollAtEnd(ctx) {
2818
2981
  }
2819
2982
  setTimeout(
2820
2983
  () => {
2821
- state.maintainingScrollAtEnd = false;
2984
+ if (state.maintainingScrollAtEnd === activeState) {
2985
+ state.maintainingScrollAtEnd = void 0;
2986
+ }
2822
2987
  },
2823
2988
  maintainScrollAtEnd.animated ? 500 : 0
2824
2989
  );
2825
- } else {
2826
- state.maintainingScrollAtEnd = false;
2990
+ } else if (state.maintainingScrollAtEnd === pendingState) {
2991
+ state.maintainingScrollAtEnd = void 0;
2827
2992
  }
2828
2993
  });
2829
2994
  }
@@ -2832,30 +2997,6 @@ function doMaintainScrollAtEnd(ctx) {
2832
2997
  return false;
2833
2998
  }
2834
2999
 
2835
- // src/utils/requestAdjust.ts
2836
- function requestAdjust(ctx, positionDiff, dataChanged) {
2837
- const state = ctx.state;
2838
- if (Math.abs(positionDiff) > 0.1) {
2839
- const doit = () => {
2840
- {
2841
- state.scrollAdjustHandler.requestAdjust(positionDiff);
2842
- if (state.adjustingFromInitialMount) {
2843
- state.adjustingFromInitialMount--;
2844
- }
2845
- }
2846
- };
2847
- state.scroll += positionDiff;
2848
- state.scrollForNextCalculateItemsInView = void 0;
2849
- const readyToRender = peek$(ctx, "readyToRender");
2850
- if (readyToRender) {
2851
- doit();
2852
- } else {
2853
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2854
- requestAnimationFrame(doit);
2855
- }
2856
- }
2857
- }
2858
-
2859
3000
  // src/core/mvcp.ts
2860
3001
  var MVCP_POSITION_EPSILON = 0.1;
2861
3002
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -3001,6 +3142,10 @@ function prepareMVCP(ctx, dataChanged) {
3001
3142
  const now = Date.now();
3002
3143
  const enableMVCPAnchorLock = (!!dataChanged || !!state.mvcpAnchorLock);
3003
3144
  const scrollingTo = state.scrollingTo;
3145
+ if (dataChanged && state.pendingScrollToEnd && scrollingTo === void 0) {
3146
+ state.mvcpAnchorLock = void 0;
3147
+ return void 0;
3148
+ }
3004
3149
  const anchorLock = resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) ;
3005
3150
  let prevPosition;
3006
3151
  let targetId;
@@ -3129,7 +3274,7 @@ function prepareMVCP(ctx, dataChanged) {
3129
3274
  return;
3130
3275
  }
3131
3276
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
3132
- const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
3277
+ const shouldSkipAdjustForMaintainedEnd = (state.maintainingScrollAtEnd === "pending-animated" || state.maintainingScrollAtEnd === "animated") && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
3133
3278
  if (!shouldSkipAdjustForMaintainedEnd) {
3134
3279
  requestAdjust(ctx, positionDiff);
3135
3280
  }
@@ -3138,6 +3283,45 @@ function prepareMVCP(ctx, dataChanged) {
3138
3283
  }
3139
3284
  }
3140
3285
 
3286
+ // src/utils/getScrollVelocity.ts
3287
+ var getScrollVelocity = (state) => {
3288
+ const { scrollHistory } = state;
3289
+ const newestIndex = scrollHistory.length - 1;
3290
+ if (newestIndex < 1) {
3291
+ return 0;
3292
+ }
3293
+ const newest = scrollHistory[newestIndex];
3294
+ const now = Date.now();
3295
+ let direction = 0;
3296
+ for (let i = newestIndex; i > 0; i--) {
3297
+ const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
3298
+ if (delta !== 0) {
3299
+ direction = Math.sign(delta);
3300
+ break;
3301
+ }
3302
+ }
3303
+ if (direction === 0) {
3304
+ return 0;
3305
+ }
3306
+ let oldest = newest;
3307
+ for (let i = newestIndex - 1; i >= 0; i--) {
3308
+ const current = scrollHistory[i];
3309
+ const next = scrollHistory[i + 1];
3310
+ const delta = next.scroll - current.scroll;
3311
+ const deltaSign = Math.sign(delta);
3312
+ if (deltaSign !== 0 && deltaSign !== direction) {
3313
+ break;
3314
+ }
3315
+ if (now - current.time > 1e3) {
3316
+ break;
3317
+ }
3318
+ oldest = current;
3319
+ }
3320
+ const scrollDiff = newest.scroll - oldest.scroll;
3321
+ const timeDiff = newest.time - oldest.time;
3322
+ return timeDiff > 0 ? scrollDiff / timeDiff : 0;
3323
+ };
3324
+
3141
3325
  // src/core/updateScroll.ts
3142
3326
  function updateScroll(ctx, newScroll, forceUpdate, options) {
3143
3327
  var _a3;
@@ -3163,6 +3347,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
3163
3347
  if (scrollHistory.length > 5) {
3164
3348
  scrollHistory.shift();
3165
3349
  }
3350
+ const scrollVelocity = getScrollVelocity(state);
3351
+ updateAdaptiveRender(ctx, scrollVelocity);
3166
3352
  if (ignoreScrollFromMVCP && !scrollingTo) {
3167
3353
  const { lt, gt } = ignoreScrollFromMVCP;
3168
3354
  if (lt && newScroll < lt || gt && newScroll > gt) {
@@ -3186,7 +3372,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
3186
3372
  state.lastScrollDelta = scrollDelta;
3187
3373
  const runCalculateItems = () => {
3188
3374
  var _a4;
3189
- (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0 });
3375
+ (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0, scrollVelocity });
3190
3376
  checkThresholds(ctx);
3191
3377
  };
3192
3378
  if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength && !state.pendingNativeMVCPAdjust) {
@@ -4266,9 +4452,32 @@ function initializeInitialScrollOnMount(ctx, options) {
4266
4452
  }
4267
4453
  function handleInitialScrollDataChange(ctx, options) {
4268
4454
  var _a3, _b, _c;
4269
- const { dataLength, didDataChange, initialScrollAtEnd, stylePaddingBottom, useBootstrapInitialScroll } = options;
4455
+ const {
4456
+ dataLength,
4457
+ didDataChange,
4458
+ initialScrollAtEnd,
4459
+ latestInitialScroll,
4460
+ latestInitialScrollSessionKind,
4461
+ stylePaddingBottom,
4462
+ useBootstrapInitialScroll
4463
+ } = options;
4270
4464
  const state = ctx.state;
4271
4465
  const previousDataLength = (_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.previousDataLength) != null ? _b : 0;
4466
+ const isFirstNonEmptyData = !state.hasHadNonEmptyData && dataLength > 0;
4467
+ if (dataLength > 0) {
4468
+ state.hasHadNonEmptyData = true;
4469
+ }
4470
+ if (isFirstNonEmptyData) {
4471
+ if (latestInitialScroll) {
4472
+ setInitialScrollTarget(state, latestInitialScroll);
4473
+ setInitialScrollSession(state, {
4474
+ kind: latestInitialScrollSessionKind,
4475
+ previousDataLength
4476
+ });
4477
+ } else {
4478
+ clearPreservedInitialScrollTarget(state);
4479
+ }
4480
+ }
4272
4481
  if (state.initialScrollSession) {
4273
4482
  state.initialScrollSession.previousDataLength = dataLength;
4274
4483
  }
@@ -4492,45 +4701,6 @@ function updateTotalSize(ctx) {
4492
4701
  }
4493
4702
  }
4494
4703
 
4495
- // src/utils/getScrollVelocity.ts
4496
- var getScrollVelocity = (state) => {
4497
- const { scrollHistory } = state;
4498
- const newestIndex = scrollHistory.length - 1;
4499
- if (newestIndex < 1) {
4500
- return 0;
4501
- }
4502
- const newest = scrollHistory[newestIndex];
4503
- const now = Date.now();
4504
- let direction = 0;
4505
- for (let i = newestIndex; i > 0; i--) {
4506
- const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
4507
- if (delta !== 0) {
4508
- direction = Math.sign(delta);
4509
- break;
4510
- }
4511
- }
4512
- if (direction === 0) {
4513
- return 0;
4514
- }
4515
- let oldest = newest;
4516
- for (let i = newestIndex - 1; i >= 0; i--) {
4517
- const current = scrollHistory[i];
4518
- const next = scrollHistory[i + 1];
4519
- const delta = next.scroll - current.scroll;
4520
- const deltaSign = Math.sign(delta);
4521
- if (deltaSign !== 0 && deltaSign !== direction) {
4522
- break;
4523
- }
4524
- if (now - current.time > 1e3) {
4525
- break;
4526
- }
4527
- oldest = current;
4528
- }
4529
- const scrollDiff = newest.scroll - oldest.scroll;
4530
- const timeDiff = newest.time - oldest.time;
4531
- return timeDiff > 0 ? scrollDiff / timeDiff : 0;
4532
- };
4533
-
4534
4704
  // src/utils/updateSnapToOffsets.ts
4535
4705
  function updateSnapToOffsets(ctx) {
4536
4706
  const state = ctx.state;
@@ -5266,7 +5436,7 @@ function updateViewabilityForCachedRange(ctx, viewabilityConfigCallbackPairs, sc
5266
5436
  function calculateItemsInView(ctx, params = {}) {
5267
5437
  const state = ctx.state;
5268
5438
  batchedUpdates(() => {
5269
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
5439
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
5270
5440
  const {
5271
5441
  columns,
5272
5442
  containerItemKeys,
@@ -5275,14 +5445,7 @@ function calculateItemsInView(ctx, params = {}) {
5275
5445
  indexByKey,
5276
5446
  minIndexSizeChanged,
5277
5447
  positions,
5278
- props: {
5279
- alwaysRenderIndicesArr,
5280
- alwaysRenderIndicesSet,
5281
- drawDistance,
5282
- getItemType,
5283
- keyExtractor,
5284
- onStickyHeaderChange
5285
- },
5448
+ props: { alwaysRenderIndicesArr, alwaysRenderIndicesSet, getItemType, keyExtractor, onStickyHeaderChange },
5286
5449
  scrollForNextCalculateItemsInView,
5287
5450
  scrollLength,
5288
5451
  sizes,
@@ -5294,6 +5457,7 @@ function calculateItemsInView(ctx, params = {}) {
5294
5457
  const stickyHeaderIndicesSet = state.props.stickyHeaderIndicesSet || /* @__PURE__ */ new Set();
5295
5458
  const alwaysRenderArr = alwaysRenderIndicesArr || [];
5296
5459
  const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
5460
+ const drawDistance = getEffectiveDrawDistance(ctx);
5297
5461
  const { dataChanged, doMVCP, forceFullItemPositions } = params;
5298
5462
  const bootstrapInitialScrollState = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
5299
5463
  const suppressInitialScrollSideEffects = !!bootstrapInitialScrollState;
@@ -5304,10 +5468,10 @@ function calculateItemsInView(ctx, params = {}) {
5304
5468
  let totalSize = getContentSize(ctx);
5305
5469
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "alignItemsAtEndPadding") + peek$(ctx, "headerSize");
5306
5470
  const numColumns = peek$(ctx, "numColumns");
5307
- const speed = getScrollVelocity(state);
5471
+ const speed = (_b = params.scrollVelocity) != null ? _b : getScrollVelocity(state);
5308
5472
  const scrollExtra = 0;
5309
5473
  const { initialScroll, queuedInitialLayout } = state;
5310
- const scrollState = suppressInitialScrollSideEffects ? (_b = bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.scroll) != null ? _b : state.scroll : !queuedInitialLayout && hasActiveInitialScroll(state) && initialScroll ? (
5474
+ const scrollState = suppressInitialScrollSideEffects ? (_c = bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.scroll) != null ? _c : state.scroll : !queuedInitialLayout && hasActiveInitialScroll(state) && initialScroll ? (
5311
5475
  // Before the initial layout settles, keep viewport math anchored to the
5312
5476
  // current initial-scroll target instead of transient native adjustments.
5313
5477
  resolveInitialScrollOffset(ctx, initialScroll)
@@ -5331,19 +5495,25 @@ function calculateItemsInView(ctx, params = {}) {
5331
5495
  };
5332
5496
  updateScroll2(scrollState);
5333
5497
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
5334
- const currentStickyIdx = stickyHeaderIndicesArr.length > 0 ? findCurrentStickyIndex(stickyHeaderIndicesArr, scroll, state) : -1;
5335
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyHeaderIndicesArr[currentStickyIdx] : -1;
5336
- const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
5337
- if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
5338
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
5339
- }
5340
- const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyHeaderIndicesArr.length > 0 && stickyIndexDidChange;
5341
- const finishCalculateItemsInView = shouldNotifyStickyHeaderChange ? () => {
5342
- const item = data[nextActiveStickyIndex];
5343
- if (item !== void 0) {
5344
- onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
5498
+ const resolveStickyState = () => {
5499
+ const currentStickyIdx = stickyHeaderIndicesArr.length > 0 ? findCurrentStickyIndex(stickyHeaderIndicesArr, scroll, state) : -1;
5500
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyHeaderIndicesArr[currentStickyIdx] : -1;
5501
+ const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
5502
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
5503
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
5345
5504
  }
5346
- } : void 0;
5505
+ const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyHeaderIndicesArr.length > 0 && stickyIndexDidChange;
5506
+ return {
5507
+ currentStickyIdx,
5508
+ finishCalculateItemsInView: shouldNotifyStickyHeaderChange ? () => {
5509
+ const item = data[nextActiveStickyIndex];
5510
+ if (item !== void 0) {
5511
+ onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
5512
+ }
5513
+ } : void 0
5514
+ };
5515
+ };
5516
+ let stickyState = dataChanged ? void 0 : resolveStickyState();
5347
5517
  let scrollBufferTop = drawDistance;
5348
5518
  let scrollBufferBottom = drawDistance;
5349
5519
  if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
@@ -5376,7 +5546,7 @@ function calculateItemsInView(ctx, params = {}) {
5376
5546
  scrollBottom
5377
5547
  );
5378
5548
  }
5379
- finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
5549
+ (_d = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _d.call(stickyState);
5380
5550
  return;
5381
5551
  }
5382
5552
  }
@@ -5385,7 +5555,7 @@ function calculateItemsInView(ctx, params = {}) {
5385
5555
  if (dataChanged) {
5386
5556
  resetLayoutCachesForDataChange(state);
5387
5557
  }
5388
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
5558
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_e = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _e : 0;
5389
5559
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
5390
5560
  updateItemPositions(ctx, dataChanged, {
5391
5561
  doMVCP,
@@ -5411,21 +5581,24 @@ function calculateItemsInView(ctx, params = {}) {
5411
5581
  }
5412
5582
  }
5413
5583
  const scrollBeforeMVCP = state.scroll;
5414
- const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
5584
+ const scrollAdjustPendingBeforeMVCP = (_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0;
5415
5585
  checkMVCP == null ? void 0 : checkMVCP();
5416
- const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0) !== scrollAdjustPendingBeforeMVCP);
5586
+ const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_g = peek$(ctx, "scrollAdjustPending")) != null ? _g : 0) !== scrollAdjustPendingBeforeMVCP);
5417
5587
  if (didMVCPAdjustScroll && initialScroll) {
5418
5588
  updateScroll2(state.scroll);
5419
5589
  updateScrollRange();
5420
5590
  }
5591
+ if (dataChanged) {
5592
+ stickyState = resolveStickyState();
5593
+ }
5421
5594
  let startBuffered = null;
5422
5595
  let startBufferedId = null;
5423
5596
  let endBuffered = null;
5424
- let loopStart = (_f = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _f : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
5597
+ let loopStart = (_h = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _h : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
5425
5598
  for (let i = loopStart; i >= 0; i--) {
5426
- const id = (_g = idCache[i]) != null ? _g : getId(state, i);
5599
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
5427
5600
  const top = positions[i];
5428
- const size = (_h = sizes.get(id)) != null ? _h : getItemSize(ctx, id, i, data[i]);
5601
+ const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
5429
5602
  const bottom = top + size;
5430
5603
  if (bottom > scrollTopBuffered) {
5431
5604
  loopStart = i;
@@ -5460,8 +5633,8 @@ function calculateItemsInView(ctx, params = {}) {
5460
5633
  };
5461
5634
  const dataLength = data.length;
5462
5635
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
5463
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
5464
- const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
5636
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
5637
+ const size = (_l = sizes.get(id)) != null ? _l : getItemSize(ctx, id, i, data[i]);
5465
5638
  const top = positions[i];
5466
5639
  if (!foundEnd) {
5467
5640
  trackVisibleRange(visibleRange, i, top, size, scroll, scrollBottom);
@@ -5517,7 +5690,7 @@ function calculateItemsInView(ctx, params = {}) {
5517
5690
  const needNewContainers = [];
5518
5691
  const needNewContainersSet = /* @__PURE__ */ new Set();
5519
5692
  for (let i = startBuffered; i <= endBuffered; i++) {
5520
- const id = (_k = idCache[i]) != null ? _k : getId(state, i);
5693
+ const id = (_m = idCache[i]) != null ? _m : getId(state, i);
5521
5694
  if (!containerItemKeys.has(id)) {
5522
5695
  needNewContainersSet.add(i);
5523
5696
  needNewContainers.push(i);
@@ -5526,7 +5699,7 @@ function calculateItemsInView(ctx, params = {}) {
5526
5699
  if (alwaysRenderArr.length > 0) {
5527
5700
  for (const index of alwaysRenderArr) {
5528
5701
  if (index < 0 || index >= dataLength) continue;
5529
- const id = (_l = idCache[index]) != null ? _l : getId(state, index);
5702
+ const id = (_n = idCache[index]) != null ? _n : getId(state, index);
5530
5703
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
5531
5704
  needNewContainersSet.add(index);
5532
5705
  needNewContainers.push(index);
@@ -5537,7 +5710,7 @@ function calculateItemsInView(ctx, params = {}) {
5537
5710
  handleStickyActivation(
5538
5711
  ctx,
5539
5712
  stickyHeaderIndicesArr,
5540
- currentStickyIdx,
5713
+ (_o = stickyState == null ? void 0 : stickyState.currentStickyIdx) != null ? _o : -1,
5541
5714
  needNewContainers,
5542
5715
  needNewContainersSet,
5543
5716
  startBuffered,
@@ -5563,7 +5736,7 @@ function calculateItemsInView(ctx, params = {}) {
5563
5736
  for (const allocation of availableContainerAllocations) {
5564
5737
  const i = allocation.itemIndex;
5565
5738
  const containerIndex = allocation.containerIndex;
5566
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
5739
+ const id = (_p = idCache[i]) != null ? _p : getId(state, i);
5567
5740
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
5568
5741
  if (oldKey && oldKey !== id) {
5569
5742
  containerItemKeys.delete(oldKey);
@@ -5574,7 +5747,7 @@ function calculateItemsInView(ctx, params = {}) {
5574
5747
  state.containerItemTypes.set(containerIndex, allocation.itemType);
5575
5748
  }
5576
5749
  containerItemKeys.set(id, containerIndex);
5577
- (_n = state.userScrollAnchorReset) == null ? void 0 : _n.keys.add(id);
5750
+ (_q = state.userScrollAnchorReset) == null ? void 0 : _q.keys.add(id);
5578
5751
  const containerSticky = `containerSticky${containerIndex}`;
5579
5752
  const isSticky = stickyHeaderIndicesSet.has(i);
5580
5753
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -5605,14 +5778,12 @@ function calculateItemsInView(ctx, params = {}) {
5605
5778
  if (state.userScrollAnchorReset) {
5606
5779
  if (state.userScrollAnchorReset.keys.size === 0) {
5607
5780
  state.userScrollAnchorReset = void 0;
5608
- } else {
5609
- state.userScrollAnchorReset.batchSize = state.userScrollAnchorReset.keys.size;
5610
5781
  }
5611
5782
  }
5612
5783
  if (alwaysRenderArr.length > 0) {
5613
5784
  for (const index of alwaysRenderArr) {
5614
5785
  if (index < 0 || index >= dataLength) continue;
5615
- const id = (_o = idCache[index]) != null ? _o : getId(state, index);
5786
+ const id = (_r = idCache[index]) != null ? _r : getId(state, index);
5616
5787
  const containerIndex = containerItemKeys.get(id);
5617
5788
  if (containerIndex !== void 0) {
5618
5789
  state.stickyContainerPool.add(containerIndex);
@@ -5626,7 +5797,7 @@ function calculateItemsInView(ctx, params = {}) {
5626
5797
  stickyHeaderIndicesArr,
5627
5798
  scroll,
5628
5799
  drawDistance,
5629
- currentStickyIdx,
5800
+ (_s = stickyState == null ? void 0 : stickyState.currentStickyIdx) != null ? _s : -1,
5630
5801
  pendingRemoval,
5631
5802
  alwaysRenderSet
5632
5803
  );
@@ -5687,7 +5858,7 @@ function calculateItemsInView(ctx, params = {}) {
5687
5858
  );
5688
5859
  }
5689
5860
  }
5690
- finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
5861
+ (_t = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _t.call(stickyState);
5691
5862
  });
5692
5863
  }
5693
5864
 
@@ -5770,8 +5941,9 @@ function doInitialAllocateContainers(ctx) {
5770
5941
  const state = ctx.state;
5771
5942
  const {
5772
5943
  scrollLength,
5773
- props: { data, drawDistance, getFixedItemSize, getItemType, numColumns, estimatedItemSize }
5944
+ props: { data, getFixedItemSize, getItemType, numColumns, estimatedItemSize }
5774
5945
  } = state;
5946
+ const drawDistance = getEffectiveDrawDistance(ctx);
5775
5947
  const hasContainers = peek$(ctx, "numContainers");
5776
5948
  if (scrollLength > 0 && data.length > 0 && !hasContainers) {
5777
5949
  let averageItemSize;
@@ -5782,12 +5954,12 @@ function doInitialAllocateContainers(ctx) {
5782
5954
  const item = data[i];
5783
5955
  if (item !== void 0) {
5784
5956
  const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
5785
- totalSize += (_b = getFixedItemSize(item, i, itemType)) != null ? _b : estimatedItemSize;
5957
+ totalSize += ((_b = getFixedItemSize(item, i, itemType)) != null ? _b : estimatedItemSize) + ctx.scrollAxisGap;
5786
5958
  }
5787
5959
  }
5788
5960
  averageItemSize = totalSize / num;
5789
5961
  } else {
5790
- averageItemSize = estimatedItemSize;
5962
+ averageItemSize = estimatedItemSize + ctx.scrollAxisGap;
5791
5963
  }
5792
5964
  const numContainers = Math.max(
5793
5965
  1,
@@ -5846,7 +6018,7 @@ function handleLayout(ctx, layoutParam, setCanRender) {
5846
6018
  if (didChange) {
5847
6019
  state.scrollLength = scrollLength;
5848
6020
  state.otherAxisSize = otherAxisSize;
5849
- updateContentMetrics(ctx);
6021
+ updateContentMetricsState(ctx);
5850
6022
  state.lastBatchingAction = Date.now();
5851
6023
  state.scrollForNextCalculateItemsInView = void 0;
5852
6024
  if (scrollLength > 0) {
@@ -6083,28 +6255,12 @@ function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment)
6083
6255
 
6084
6256
  // src/core/updateItemSize.ts
6085
6257
  function runOrScheduleMVCPRecalculate(ctx) {
6086
- var _a3, _b;
6258
+ var _a3;
6087
6259
  const state = ctx.state;
6088
6260
  if (state.userScrollAnchorReset !== void 0) {
6089
- const replacementBatchSize = (_a3 = state.userScrollAnchorReset.batchSize) != null ? _a3 : state.userScrollAnchorReset.keys.size;
6090
- const replacementMeasurementBatchThreshold = 3;
6091
- const shouldBatchReplacementMeasurements = replacementBatchSize > replacementMeasurementBatchThreshold;
6092
- if (shouldBatchReplacementMeasurements) {
6093
- if (state.queuedMVCPRecalculate === void 0) {
6094
- state.queuedMVCPRecalculate = requestAnimationFrame(() => {
6095
- var _a4;
6096
- state.queuedMVCPRecalculate = void 0;
6097
- calculateItemsInView(ctx);
6098
- if (((_a4 = state.userScrollAnchorReset) == null ? void 0 : _a4.keys.size) === 0) {
6099
- state.userScrollAnchorReset = void 0;
6100
- }
6101
- });
6102
- }
6103
- } else {
6104
- calculateItemsInView(ctx);
6105
- if (((_b = state.userScrollAnchorReset) == null ? void 0 : _b.keys.size) === 0) {
6106
- state.userScrollAnchorReset = void 0;
6107
- }
6261
+ calculateItemsInView(ctx);
6262
+ if (((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
6263
+ state.userScrollAnchorReset = void 0;
6108
6264
  }
6109
6265
  } else {
6110
6266
  if (!state.mvcpAnchorLock) {
@@ -6564,6 +6720,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6564
6720
  scrollTo(ctx, params);
6565
6721
  return true;
6566
6722
  }),
6723
+ setItemSize: (itemKey, size) => {
6724
+ updateItemSize(ctx, itemKey, size);
6725
+ },
6567
6726
  setScrollProcessingEnabled: (enabled) => {
6568
6727
  state.scrollProcessingEnabled = enabled;
6569
6728
  },
@@ -6788,7 +6947,7 @@ var LegendList = typedMemo(
6788
6947
  })
6789
6948
  );
6790
6949
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
6791
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
6950
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
6792
6951
  const noopOnScroll = React3.useCallback((_event) => {
6793
6952
  }, []);
6794
6953
  if (props.recycleItems === void 0) {
@@ -6819,6 +6978,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6819
6978
  initialScrollAtEnd = false,
6820
6979
  initialScrollIndex: initialScrollIndexProp,
6821
6980
  initialScrollOffset: initialScrollOffsetProp,
6981
+ experimental_adaptiveRender,
6822
6982
  itemsAreEqual,
6823
6983
  keyExtractor: keyExtractorProp,
6824
6984
  ListEmptyComponent,
@@ -6915,6 +7075,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6915
7075
  const [, scheduleImperativeScrollCommit] = React3__namespace.useReducer((value) => value + 1, 0);
6916
7076
  const ctx = useStateContext();
6917
7077
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
7078
+ const scrollAxisGap = horizontal ? (_f = (_d = ctx.columnWrapperStyle) == null ? void 0 : _d.columnGap) != null ? _f : (_e = ctx.columnWrapperStyle) == null ? void 0 : _e.gap : (_i = (_g = ctx.columnWrapperStyle) == null ? void 0 : _g.rowGap) != null ? _i : (_h = ctx.columnWrapperStyle) == null ? void 0 : _h.gap;
7079
+ const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
6918
7080
  const refScroller = React3.useRef(null);
6919
7081
  const combinedRef = useCombinedRef(refScroller, refScrollView);
6920
7082
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
@@ -6928,8 +7090,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6928
7090
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
6929
7091
  alwaysRender == null ? void 0 : alwaysRender.top,
6930
7092
  alwaysRender == null ? void 0 : alwaysRender.bottom,
6931
- (_d = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _d.join(","),
6932
- (_e = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _e.join(","),
7093
+ (_j = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _j.join(","),
7094
+ (_k = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _k.join(","),
6933
7095
  dataProp,
6934
7096
  dataVersion,
6935
7097
  keyExtractor
@@ -6957,6 +7119,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6957
7119
  endNoBuffer: -1,
6958
7120
  endReachedSnapshot: void 0,
6959
7121
  firstFullyOnScreenIndex: -1,
7122
+ hasHadNonEmptyData: dataProp.length > 0,
6960
7123
  idCache: [],
6961
7124
  idsInView: [],
6962
7125
  indexByKey: /* @__PURE__ */ new Map(),
@@ -6999,6 +7162,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6999
7162
  startReachedSnapshotDataChangeEpoch: void 0,
7000
7163
  stickyContainerPool: /* @__PURE__ */ new Set(),
7001
7164
  stickyContainers: /* @__PURE__ */ new Map(),
7165
+ timeoutAdaptiveRender: void 0,
7002
7166
  timeouts: /* @__PURE__ */ new Set(),
7003
7167
  totalSize: 0,
7004
7168
  viewabilityConfigCallbackPairs: void 0
@@ -7017,11 +7181,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7017
7181
  const state = refState.current;
7018
7182
  const isFirstLocal = state.isFirst;
7019
7183
  const previousNumColumnsProp = state.props.numColumns;
7020
- state.didColumnsChange = numColumnsProp !== previousNumColumnsProp;
7184
+ const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
7185
+ ctx.scrollAxisGap = nextScrollAxisGap;
7186
+ state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
7021
7187
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
7022
7188
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
7023
7189
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
7024
- if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
7190
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_l = state.initialScroll) == null ? void 0 : _l.viewPosition) === 1 && state.props.data.length > 0) {
7025
7191
  clearPreservedInitialScrollTarget(state);
7026
7192
  }
7027
7193
  if (didDataChangeLocal) {
@@ -7033,8 +7199,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7033
7199
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
7034
7200
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? throttledOnScroll : onScrollProp;
7035
7201
  const anchoredEndSpaceResolved = anchoredEndSpace ? { ...anchoredEndSpace, includeInEndInset: true } : anchoredEndSpace;
7036
- const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_g = state.props.anchoredEndSpace) == null ? void 0 : _g.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
7202
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_m = state.props.anchoredEndSpace) == null ? void 0 : _m.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
7037
7203
  state.props = {
7204
+ adaptiveRender: experimental_adaptiveRender,
7038
7205
  alignItemsAtEnd,
7039
7206
  alignItemsAtEndPaddingEnabled: useAlignItemsAtEndPadding,
7040
7207
  alwaysRender,
@@ -7042,6 +7209,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7042
7209
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
7043
7210
  anchoredEndSpace: anchoredEndSpaceResolved,
7044
7211
  animatedProps: animatedPropsInternal,
7212
+ contentContainerAlignItems: contentContainerStyle.alignItems,
7045
7213
  contentInset,
7046
7214
  contentInsetEndAdjustment: contentInsetEndAdjustmentResolved,
7047
7215
  data: dataProp,
@@ -7094,7 +7262,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7094
7262
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
7095
7263
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
7096
7264
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
7097
- updateContentMetrics(ctx);
7265
+ updateContentMetricsState(ctx);
7098
7266
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
7099
7267
  if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") ;
7100
7268
  };
@@ -7126,7 +7294,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7126
7294
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7127
7295
  });
7128
7296
  }, []);
7129
- if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
7297
+ if (isFirstLocal || didDataChangeLocal || state.didColumnsChange) {
7130
7298
  refState.current.lastBatchingAction = Date.now();
7131
7299
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
7132
7300
  refState.current.sizes.clear();
@@ -7143,6 +7311,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7143
7311
  dataLength: dataProp.length,
7144
7312
  didDataChange: didDataChangeLocal,
7145
7313
  initialScrollAtEnd,
7314
+ latestInitialScroll: initialScrollProp,
7315
+ latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
7146
7316
  stylePaddingBottom: stylePaddingBottomState,
7147
7317
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7148
7318
  });
@@ -7217,6 +7387,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7217
7387
  dataVersion,
7218
7388
  memoizedLastItemKeys.join(","),
7219
7389
  numColumnsProp,
7390
+ nextScrollAxisGap,
7220
7391
  stylePaddingBottomState,
7221
7392
  stylePaddingTopState,
7222
7393
  useAlignItemsAtEndPadding
@@ -7239,7 +7410,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7239
7410
  state.didColumnsChange = false;
7240
7411
  state.didDataChange = false;
7241
7412
  state.isFirst = false;
7242
- }, [dataProp, dataVersion, numColumnsProp]);
7413
+ }, [dataProp, dataVersion, numColumnsProp, nextScrollAxisGap]);
7243
7414
  React3.useLayoutEffect(() => {
7244
7415
  var _a4;
7245
7416
  set$(ctx, "extraData", extraData);
@@ -7287,6 +7458,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7287
7458
  useInit(() => {
7288
7459
  });
7289
7460
  React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
7461
+ React3.useEffect(() => {
7462
+ return () => {
7463
+ for (const timeout of state.timeouts) {
7464
+ clearTimeout(timeout);
7465
+ }
7466
+ state.timeouts.clear();
7467
+ };
7468
+ }, [state]);
7290
7469
  React3.useLayoutEffect(() => {
7291
7470
  var _a4;
7292
7471
  (_a4 = state.runPendingScrollToEnd) == null ? void 0 : _a4.call(state);
@@ -7334,7 +7513,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7334
7513
  onScroll: onScrollHandler,
7335
7514
  recycleItems,
7336
7515
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControlElement, {
7337
- progressViewOffset: ((_h = refreshControlElement.props.progressViewOffset) != null ? _h : 0) + stylePaddingTopState
7516
+ progressViewOffset: ((_n = refreshControlElement.props.progressViewOffset) != null ? _n : 0) + stylePaddingTopState
7338
7517
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React3__namespace.createElement(
7339
7518
  RefreshControl,
7340
7519
  {
@@ -7345,7 +7524,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7345
7524
  ),
7346
7525
  refScrollView: combinedRef,
7347
7526
  renderScrollComponent,
7348
- scrollAdjustHandler: (_i = refState.current) == null ? void 0 : _i.scrollAdjustHandler,
7527
+ scrollAdjustHandler: (_o = refState.current) == null ? void 0 : _o.scrollAdjustHandler,
7349
7528
  scrollEventThrottle: 0,
7350
7529
  snapToIndices,
7351
7530
  stickyHeaderIndices,
@@ -7403,6 +7582,8 @@ var internal2 = internal;
7403
7582
 
7404
7583
  exports.LegendList = LegendList3;
7405
7584
  exports.internal = internal2;
7585
+ exports.useAdaptiveRender = useAdaptiveRender;
7586
+ exports.useAdaptiveRenderChange = useAdaptiveRenderChange;
7406
7587
  exports.useIsLastItem = useIsLastItem;
7407
7588
  exports.useListScrollSize = useListScrollSize;
7408
7589
  exports.useRecyclingEffect = useRecyclingEffect;