@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.mjs CHANGED
@@ -141,6 +141,7 @@ function StateProvider({ children }) {
141
141
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
142
142
  mapViewabilityValues: /* @__PURE__ */ new Map(),
143
143
  positionListeners: /* @__PURE__ */ new Map(),
144
+ scrollAxisGap: 0,
144
145
  state: void 0,
145
146
  values: /* @__PURE__ */ new Map([
146
147
  ["alignItemsAtEndPadding", 0],
@@ -153,6 +154,7 @@ function StateProvider({ children }) {
153
154
  ["isNearEnd", false],
154
155
  ["isNearStart", false],
155
156
  ["isWithinMaintainScrollAtEndThreshold", false],
157
+ ["adaptiveRender", "light"],
156
158
  ["totalSize", 0],
157
159
  ["scrollAdjustPending", 0]
158
160
  ]),
@@ -533,6 +535,24 @@ var ContextContainer = createContext(null);
533
535
  function useContextContainer() {
534
536
  return useContext(ContextContainer);
535
537
  }
538
+ function useAdaptiveRender() {
539
+ const [mode] = useArr$(["adaptiveRender"]);
540
+ return mode;
541
+ }
542
+ function useAdaptiveRenderChange(callback) {
543
+ const ctx = useStateContext();
544
+ const callbackRef = useRef(callback);
545
+ callbackRef.current = callback;
546
+ useLayoutEffect(() => {
547
+ let mode = peek$(ctx, "adaptiveRender");
548
+ return listen$(ctx, "adaptiveRender", (nextMode) => {
549
+ if (mode !== nextMode) {
550
+ mode = nextMode;
551
+ callbackRef.current(nextMode);
552
+ }
553
+ });
554
+ }, [ctx]);
555
+ }
536
556
  function useViewability(callback, configId) {
537
557
  const ctx = useStateContext();
538
558
  const containerContext = useContextContainer();
@@ -802,6 +822,7 @@ function isInMVCPActiveMode(state) {
802
822
  // src/components/Container.tsx
803
823
  function getContainerPositionStyle({
804
824
  columnWrapperStyle,
825
+ contentContainerAlignItems,
805
826
  horizontal,
806
827
  hasItemSeparator,
807
828
  isHorizontalRTLList,
@@ -827,13 +848,14 @@ function getContainerPositionStyle({
827
848
  }
828
849
  }
829
850
  return horizontal ? {
851
+ bottom: contentContainerAlignItems === "flex-end" && numColumns === 1 ? 0 : void 0,
830
852
  boxSizing: paddingStyles ? "border-box" : void 0,
831
853
  direction: isHorizontalRTLList && Platform.OS === "web" ? "ltr" : void 0,
832
854
  flexDirection: hasItemSeparator ? "row" : void 0,
833
855
  height: otherAxisSize,
834
856
  left: 0,
835
857
  position: "absolute",
836
- top: otherAxisPos,
858
+ top: contentContainerAlignItems === "flex-end" && numColumns === 1 ? void 0 : otherAxisPos,
837
859
  ...paddingStyles || {}
838
860
  } : {
839
861
  boxSizing: paddingStyles ? "border-box" : void 0,
@@ -887,6 +909,7 @@ var Container = typedMemo(function Container2({
887
909
  const style = useMemo(
888
910
  () => getContainerPositionStyle({
889
911
  columnWrapperStyle,
912
+ contentContainerAlignItems: ctx.state.props.contentContainerAlignItems,
890
913
  hasItemSeparator: !!ItemSeparatorComponent,
891
914
  horizontal,
892
915
  isHorizontalRTLList,
@@ -900,6 +923,7 @@ var Container = typedMemo(function Container2({
900
923
  otherAxisPos,
901
924
  otherAxisSize,
902
925
  columnWrapperStyle,
926
+ ctx.state.props.contentContainerAlignItems,
903
927
  numColumns,
904
928
  ItemSeparatorComponent
905
929
  ]
@@ -1615,7 +1639,12 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1615
1639
  WebkitOverflowScrolling: "touch"
1616
1640
  // iOS momentum scrolling
1617
1641
  },
1618
- ...StyleSheet.flatten(style)
1642
+ ...StyleSheet.flatten(style),
1643
+ ...maintainVisibleContentPosition ? {
1644
+ // Chrome's native scroll anchoring can apply after LegendList's MVCP adjustment,
1645
+ // causing the same header/item-size delta to be compensated twice.
1646
+ overflowAnchor: "none"
1647
+ } : {}
1619
1648
  };
1620
1649
  const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd2(ctx);
1621
1650
  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;
@@ -1626,7 +1655,10 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1626
1655
  flexDirection: horizontal ? "row" : void 0,
1627
1656
  minHeight: horizontal ? void 0 : "100%",
1628
1657
  minWidth: horizontal ? "100%" : void 0,
1629
- ...StyleSheet.flatten(contentContainerStyle)
1658
+ ...StyleSheet.flatten(contentContainerStyle),
1659
+ ...maintainVisibleContentPosition ? {
1660
+ overflowAnchor: "none"
1661
+ } : {}
1630
1662
  };
1631
1663
  const className = contentContainerClassName ? `${LEGEND_LIST_CONTENT_CONTAINER_CLASS} ${contentContainerClassName}` : LEGEND_LIST_CONTENT_CONTAINER_CLASS;
1632
1664
  const {
@@ -1729,6 +1761,7 @@ function scrollAdjustBy(el, left, top) {
1729
1761
  function ScrollAdjust() {
1730
1762
  const ctx = useStateContext();
1731
1763
  const lastScrollOffsetRef = React3.useRef(0);
1764
+ const lastScrollAdjustUserOffsetRef = React3.useRef(0);
1732
1765
  const resetPaddingRafRef = React3.useRef(void 0);
1733
1766
  const resetPaddingBaselineRef = React3.useRef(void 0);
1734
1767
  const contentNodeRef = React3.useRef(null);
@@ -1737,20 +1770,24 @@ function ScrollAdjust() {
1737
1770
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1738
1771
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1739
1772
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1740
- const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1741
- if (scrollDelta !== 0) {
1773
+ const signalScrollDelta = scrollOffset - lastScrollOffsetRef.current;
1774
+ if (signalScrollDelta !== 0) {
1742
1775
  const target = getScrollAdjustTarget(ctx, contentNodeRef.current);
1743
1776
  if (target) {
1744
1777
  const horizontal = !!ctx.state.props.horizontal;
1745
1778
  const axis = getScrollAdjustAxis(horizontal);
1746
1779
  const { contentNode, scrollElement: el } = target;
1780
+ const currentScroll = horizontal ? el.scrollLeft : el.scrollTop;
1781
+ const userOffsetDelta = (scrollAdjustUserOffset || 0) - lastScrollAdjustUserOffsetRef.current;
1782
+ const intendedScroll = userOffsetDelta !== 0 ? currentScroll + userOffsetDelta : ctx.state.scroll;
1783
+ const scrollDelta = intendedScroll - currentScroll;
1784
+ const shouldScroll = Math.abs(scrollDelta) > 0.01;
1747
1785
  const scrollBy = () => scrollAdjustBy(el, axis.x * scrollDelta, axis.y * scrollDelta);
1748
1786
  contentNodeRef.current = contentNode;
1749
- if (contentNode) {
1750
- const prevScroll = horizontal ? el.scrollLeft : el.scrollTop;
1787
+ if (shouldScroll && contentNode) {
1751
1788
  const totalSize = contentNode[axis.contentSizeKey];
1752
1789
  const viewportSize = el[axis.viewportSizeKey];
1753
- const nextScroll = prevScroll + scrollDelta;
1790
+ const nextScroll = currentScroll + scrollDelta;
1754
1791
  const needsTemporaryPadding = scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize;
1755
1792
  if (needsTemporaryPadding) {
1756
1793
  const previousPaddingEnd = (_a3 = resetPaddingBaselineRef.current) != null ? _a3 : contentNode.style[axis.paddingEndProp];
@@ -1770,11 +1807,12 @@ function ScrollAdjust() {
1770
1807
  } else {
1771
1808
  scrollBy();
1772
1809
  }
1773
- } else {
1810
+ } else if (shouldScroll) {
1774
1811
  scrollBy();
1775
1812
  }
1776
1813
  }
1777
1814
  lastScrollOffsetRef.current = scrollOffset;
1815
+ lastScrollAdjustUserOffsetRef.current = scrollAdjustUserOffset || 0;
1778
1816
  }
1779
1817
  }, [ctx]);
1780
1818
  useValueListener$("scrollAdjust", callback);
@@ -1796,7 +1834,7 @@ function WebAnchoredEndSpace({ horizontal }) {
1796
1834
  return /* @__PURE__ */ React3.createElement("div", { style }, null);
1797
1835
  }
1798
1836
 
1799
- // src/core/updateContentMetrics.ts
1837
+ // src/core/updateContentMetricsState.ts
1800
1838
  function getRawContentLength(ctx) {
1801
1839
  var _a3, _b, _c;
1802
1840
  const { state, values } = ctx;
@@ -1807,233 +1845,41 @@ function getAlignItemsAtEndPadding(ctx) {
1807
1845
  const shouldPad = !!state.props.alignItemsAtEndPaddingEnabled && !state.props.horizontal && state.props.data.length > 0 && state.scrollLength > 0;
1808
1846
  return shouldPad ? Math.max(0, state.scrollLength - getRawContentLength(ctx) - getContentInsetEnd(ctx)) : 0;
1809
1847
  }
1810
- function updateContentMetrics(ctx) {
1848
+ function updateContentMetricsState(ctx) {
1849
+ const previousPadding = peek$(ctx, "alignItemsAtEndPadding") || 0;
1811
1850
  const nextPadding = getAlignItemsAtEndPadding(ctx);
1812
- if (peek$(ctx, "alignItemsAtEndPadding") !== nextPadding) {
1851
+ if (previousPadding !== nextPadding) {
1813
1852
  set$(ctx, "alignItemsAtEndPadding", nextPadding);
1814
1853
  }
1815
1854
  }
1816
- function setContentLengthSignal(ctx, signalName, size) {
1817
- if (peek$(ctx, signalName) !== size) {
1818
- set$(ctx, signalName, size);
1819
- updateContentMetrics(ctx);
1820
- }
1821
- }
1822
- function setHeaderSize(ctx, size) {
1823
- setContentLengthSignal(ctx, "headerSize", size);
1824
- }
1825
- function setFooterSize(ctx, size) {
1826
- setContentLengthSignal(ctx, "footerSize", size);
1827
- }
1828
- function areInsetsEqual(left, right) {
1829
- var _a3, _b, _c, _d, _e, _f, _g, _h;
1830
- 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);
1831
- }
1832
- function setContentInsetOverride(ctx, inset) {
1833
- const { state } = ctx;
1834
- const previousInset = state.contentInsetOverride;
1835
- const nextInset = inset != null ? inset : void 0;
1836
- const didChange = !areInsetsEqual(previousInset, nextInset);
1837
- state.contentInsetOverride = nextInset;
1838
- if (didChange) {
1839
- updateContentMetrics(ctx);
1840
- }
1841
- return didChange;
1842
- }
1843
- function useStableRenderComponent(renderComponent, mapProps) {
1844
- const renderComponentRef = useLatestRef(renderComponent);
1845
- const mapPropsRef = useLatestRef(mapProps);
1846
- return React3.useMemo(
1847
- () => React3.forwardRef(
1848
- (props, ref) => {
1849
- var _a3, _b;
1850
- return (_b = (_a3 = renderComponentRef.current) == null ? void 0 : _a3.call(renderComponentRef, mapPropsRef.current(props, ref))) != null ? _b : null;
1851
- }
1852
- ),
1853
- [mapPropsRef, renderComponentRef]
1854
- );
1855
- }
1856
- var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1857
- const localRef = useRef(null);
1858
- const ref = refView != null ? refView : localRef;
1859
- useOnLayoutSync({ onLayoutChange, ref });
1860
- return /* @__PURE__ */ React3.createElement("div", { ...rest, ref }, children);
1861
- };
1862
1855
 
1863
- // src/components/ListComponent.tsx
1864
- var ListComponent = typedMemo(function ListComponent2({
1865
- canRender,
1866
- style,
1867
- contentContainerStyle,
1868
- horizontal,
1869
- initialContentOffset,
1870
- recycleItems,
1871
- ItemSeparatorComponent,
1872
- alignItemsAtEnd: _alignItemsAtEnd,
1873
- onScroll: onScroll2,
1874
- onLayout,
1875
- ListHeaderComponent,
1876
- ListHeaderComponentStyle,
1877
- ListFooterComponent,
1878
- ListFooterComponentStyle,
1879
- ListEmptyComponent,
1880
- getRenderedItem: getRenderedItem2,
1881
- updateItemSize: updateItemSize2,
1882
- refScrollView,
1883
- renderScrollComponent,
1884
- onLayoutFooter,
1885
- scrollAdjustHandler,
1886
- snapToIndices,
1887
- stickyHeaderConfig,
1888
- stickyHeaderIndices,
1889
- useWindowScroll = false,
1890
- ...rest
1891
- }) {
1892
- const ctx = useStateContext();
1893
- const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1894
- const [alignItemsAtEndPadding = 0, otherAxisSize = 0] = useArr$(["alignItemsAtEndPadding", "otherAxisSize"]);
1895
- const autoOtherAxisStyle = getAutoOtherAxisStyle({
1896
- horizontal,
1897
- needsOtherAxisSize: ctx.state.needsOtherAxisSize,
1898
- otherAxisSize
1899
- });
1900
- const CustomScrollComponent = useStableRenderComponent(
1901
- renderScrollComponent,
1902
- (props, ref) => ({ ...props, ref })
1903
- );
1904
- const ScrollComponent = renderScrollComponent ? CustomScrollComponent : ListComponentScrollView;
1905
- const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1906
- useLayoutEffect(() => {
1907
- if (!ListHeaderComponent) {
1908
- setHeaderSize(ctx, 0);
1909
- }
1910
- if (!ListFooterComponent) {
1911
- setFooterSize(ctx, 0);
1856
+ // src/core/addTotalSize.ts
1857
+ function addTotalSize(ctx, key, add, notifyTotalSize = true) {
1858
+ const state = ctx.state;
1859
+ const prevTotalSize = state.totalSize;
1860
+ let totalSize = state.totalSize;
1861
+ if (key === null) {
1862
+ totalSize = add;
1863
+ if (state.timeoutSetPaddingTop) {
1864
+ clearTimeout(state.timeoutSetPaddingTop);
1865
+ state.timeoutSetPaddingTop = void 0;
1912
1866
  }
1913
- }, [ListHeaderComponent, ListFooterComponent, ctx]);
1914
- const onLayoutHeader = useCallback(
1915
- (rect) => {
1916
- const size = rect[horizontal ? "width" : "height"];
1917
- setHeaderSize(ctx, size);
1918
- },
1919
- [ctx, horizontal]
1920
- );
1921
- const onLayoutFooterInternal = useCallback(
1922
- (rect, fromLayoutEffect) => {
1923
- const size = rect[horizontal ? "width" : "height"];
1924
- setFooterSize(ctx, size);
1925
- onLayoutFooter == null ? void 0 : onLayoutFooter(rect, fromLayoutEffect);
1926
- },
1927
- [ctx, horizontal, onLayoutFooter]
1928
- );
1929
- return /* @__PURE__ */ React3.createElement(
1930
- SnapOrScroll,
1867
+ } else {
1868
+ totalSize += add;
1869
+ }
1870
+ if (prevTotalSize !== totalSize) {
1931
1871
  {
1932
- ...rest,
1933
- ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1934
- contentContainerStyle: [
1935
- horizontal ? {
1936
- height: "100%"
1937
- } : {},
1938
- contentContainerStyle
1939
- ],
1940
- contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1941
- horizontal,
1942
- maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
1943
- onLayout,
1944
- onScroll: onScroll2,
1945
- ref: refScrollView,
1946
- ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1947
- style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
1948
- },
1949
- /* @__PURE__ */ React3.createElement(ScrollAdjust, null),
1950
- ListHeaderComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
1951
- ListEmptyComponent && getComponent(ListEmptyComponent),
1952
- alignItemsAtEndPadding > 0 && /* @__PURE__ */ React3.createElement(
1953
- View,
1954
- {
1955
- style: horizontal ? { flexShrink: 0, width: alignItemsAtEndPadding } : { flexShrink: 0, height: alignItemsAtEndPadding }
1956
- },
1957
- null
1958
- ),
1959
- canRender && !ListEmptyComponent && /* @__PURE__ */ React3.createElement(
1960
- Containers,
1961
- {
1962
- getRenderedItem: getRenderedItem2,
1963
- horizontal,
1964
- ItemSeparatorComponent,
1965
- recycleItems,
1966
- stickyHeaderConfig,
1967
- updateItemSize: updateItemSize2
1872
+ state.pendingTotalSize = void 0;
1873
+ state.totalSize = totalSize;
1874
+ if (notifyTotalSize) {
1875
+ set$(ctx, "totalSize", totalSize);
1968
1876
  }
1969
- ),
1970
- ListFooterComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
1971
- /* @__PURE__ */ React3.createElement(WebAnchoredEndSpace, { horizontal }),
1972
- IS_DEV && ENABLE_DEVMODE
1973
- );
1974
- });
1975
- var WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH = 100;
1976
- var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
1977
- var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
1978
- function useDevChecksImpl(props) {
1979
- const ctx = useStateContext();
1980
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
1981
- useEffect(() => {
1982
- if (useWindowScroll && renderScrollComponent) {
1983
- warnDevOnce(
1984
- "useWindowScrollRenderScrollComponent",
1985
- "useWindowScroll is not supported when renderScrollComponent is provided."
1986
- );
1987
- }
1988
- }, [renderScrollComponent, useWindowScroll]);
1989
- useEffect(() => {
1990
- if (!keyExtractor && !ctx.state.isFirst && ctx.state.didDataChange && !childrenMode) {
1991
- warnDevOnce(
1992
- "keyExtractor",
1993
- "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."
1994
- );
1995
- }
1996
- }, [childrenMode, ctx, keyExtractor]);
1997
- useEffect(() => {
1998
- const state = ctx.state;
1999
- const dataLength = state.props.data.length;
2000
- const useWindowScrollResolved = state.props.useWindowScroll;
2001
- if (useWindowScrollResolved || dataLength < WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH) {
2002
- return;
1877
+ updateContentMetricsState(ctx);
2003
1878
  }
2004
- const warnIfUnboundedOuterSize = () => {
2005
- const readyToRender = peek$(ctx, "readyToRender");
2006
- const numContainers = peek$(ctx, "numContainers") || 0;
2007
- const totalSize = peek$(ctx, "totalSize") || 0;
2008
- const scrollLength = ctx.state.scrollLength || 0;
2009
- if (!readyToRender || totalSize <= 0 || scrollLength <= 0) {
2010
- return;
2011
- }
2012
- const rendersAlmostEverything = numContainers >= Math.ceil(dataLength * WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO);
2013
- const viewportMatchesContent = scrollLength >= totalSize * WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO;
2014
- if (rendersAlmostEverything && viewportMatchesContent) {
2015
- warnDevOnce(
2016
- "webUnboundedOuterSize",
2017
- "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."
2018
- );
2019
- }
2020
- };
2021
- warnIfUnboundedOuterSize();
2022
- const unsubscribe = [
2023
- listen$(ctx, "numContainers", warnIfUnboundedOuterSize),
2024
- listen$(ctx, "readyToRender", warnIfUnboundedOuterSize),
2025
- listen$(ctx, "totalSize", warnIfUnboundedOuterSize)
2026
- ];
2027
- return () => {
2028
- for (const unsub of unsubscribe) {
2029
- unsub();
2030
- }
2031
- };
2032
- }, [ctx]);
2033
- }
2034
- function useDevChecksNoop(_props) {
1879
+ } else if (notifyTotalSize && ctx.values.get("totalSize") !== totalSize) {
1880
+ set$(ctx, "totalSize", totalSize);
1881
+ }
2035
1882
  }
2036
- var useDevChecks = IS_DEV ? useDevChecksImpl : useDevChecksNoop;
2037
1883
 
2038
1884
  // src/core/deferredPublicOnScroll.ts
2039
1885
  function withResolvedContentOffset(state, event, resolvedOffset) {
@@ -2346,6 +2192,66 @@ function recalculateSettledScroll(ctx) {
2346
2192
  checkThresholds(ctx);
2347
2193
  }
2348
2194
 
2195
+ // src/core/adaptiveRender.ts
2196
+ var DEFAULT_ENTER_VELOCITY = 4;
2197
+ var DEFAULT_EXIT_VELOCITY = 1;
2198
+ var DEFAULT_EXIT_DELAY = 1e3;
2199
+ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
2200
+ const state = ctx.state;
2201
+ const previousTimeout = state.timeoutAdaptiveRender;
2202
+ if (previousTimeout !== void 0) {
2203
+ clearTimeout(previousTimeout);
2204
+ state.timeouts.delete(previousTimeout);
2205
+ state.timeoutAdaptiveRender = void 0;
2206
+ }
2207
+ if (exitDelay <= 0) {
2208
+ setAdaptiveRender(ctx, "normal");
2209
+ } else {
2210
+ const timeout = setTimeout(() => {
2211
+ state.timeouts.delete(timeout);
2212
+ state.timeoutAdaptiveRender = void 0;
2213
+ setAdaptiveRender(ctx, "normal");
2214
+ }, exitDelay);
2215
+ state.timeoutAdaptiveRender = timeout;
2216
+ state.timeouts.add(timeout);
2217
+ }
2218
+ }
2219
+ function setAdaptiveRender(ctx, mode) {
2220
+ var _a3, _b;
2221
+ const previousMode = peek$(ctx, "adaptiveRender");
2222
+ if (previousMode !== mode) {
2223
+ set$(ctx, "adaptiveRender", mode);
2224
+ (_b = (_a3 = ctx.state.props.adaptiveRender) == null ? void 0 : _a3.onChange) == null ? void 0 : _b.call(_a3, mode);
2225
+ }
2226
+ }
2227
+ function updateAdaptiveRender(ctx, scrollVelocity) {
2228
+ var _a3, _b, _c;
2229
+ const state = ctx.state;
2230
+ const adaptiveRender = state.props.adaptiveRender;
2231
+ const enterVelocity = (_a3 = adaptiveRender == null ? void 0 : adaptiveRender.enterVelocity) != null ? _a3 : DEFAULT_ENTER_VELOCITY;
2232
+ const exitVelocity = (_b = adaptiveRender == null ? void 0 : adaptiveRender.exitVelocity) != null ? _b : DEFAULT_EXIT_VELOCITY;
2233
+ const exitDelay = (_c = adaptiveRender == null ? void 0 : adaptiveRender.exitDelay) != null ? _c : DEFAULT_EXIT_DELAY;
2234
+ const currentMode = peek$(ctx, "adaptiveRender");
2235
+ const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
2236
+ const nextMode = Math.abs(scrollVelocity) > threshold ? "light" : "normal";
2237
+ const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
2238
+ if (nextMode !== previousMode) {
2239
+ if (nextMode === "light") {
2240
+ setAdaptiveRender(ctx, "light");
2241
+ scheduleAdaptiveRenderExit(ctx, exitDelay);
2242
+ } else if (currentMode === "light") {
2243
+ scheduleAdaptiveRenderExit(ctx, exitDelay);
2244
+ }
2245
+ }
2246
+ }
2247
+
2248
+ // src/utils/getEffectiveDrawDistance.ts
2249
+ var INITIAL_DRAW_DISTANCE = 100;
2250
+ function getEffectiveDrawDistance(ctx) {
2251
+ const drawDistance = ctx.state.props.drawDistance;
2252
+ return peek$(ctx, "readyToRender") ? drawDistance : Math.min(drawDistance, INITIAL_DRAW_DISTANCE);
2253
+ }
2254
+
2349
2255
  // src/utils/setInitialRenderState.ts
2350
2256
  function setInitialRenderState(ctx, {
2351
2257
  didLayout,
@@ -2365,8 +2271,15 @@ function setInitialRenderState(ctx, {
2365
2271
  const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
2366
2272
  if (isReadyToRender && !peek$(ctx, "readyToRender")) {
2367
2273
  set$(ctx, "readyToRender", true);
2368
- if (onLoad) {
2369
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2274
+ setAdaptiveRender(ctx, "normal");
2275
+ if (state.props.drawDistance > INITIAL_DRAW_DISTANCE) {
2276
+ requestAnimationFrame(() => {
2277
+ var _a3;
2278
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
2279
+ });
2280
+ }
2281
+ if (onLoad) {
2282
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
2370
2283
  }
2371
2284
  }
2372
2285
  }
@@ -2439,200 +2352,6 @@ function finishInitialScroll(ctx, options) {
2439
2352
  complete();
2440
2353
  }
2441
2354
 
2442
- // src/core/calculateOffsetForIndex.ts
2443
- function calculateOffsetForIndex(ctx, index) {
2444
- const state = ctx.state;
2445
- return index !== void 0 ? state.positions[index] || 0 : 0;
2446
- }
2447
-
2448
- // src/core/getTopOffsetAdjustment.ts
2449
- function getTopOffsetAdjustment(ctx) {
2450
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
2451
- }
2452
-
2453
- // src/utils/getId.ts
2454
- function getId(state, index) {
2455
- const { data, keyExtractor } = state.props;
2456
- if (!data) {
2457
- return "";
2458
- }
2459
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
2460
- const id = ret;
2461
- state.idCache[index] = id;
2462
- return id;
2463
- }
2464
-
2465
- // src/core/addTotalSize.ts
2466
- function addTotalSize(ctx, key, add, notifyTotalSize = true) {
2467
- const state = ctx.state;
2468
- const prevTotalSize = state.totalSize;
2469
- let totalSize = state.totalSize;
2470
- if (key === null) {
2471
- totalSize = add;
2472
- if (state.timeoutSetPaddingTop) {
2473
- clearTimeout(state.timeoutSetPaddingTop);
2474
- state.timeoutSetPaddingTop = void 0;
2475
- }
2476
- } else {
2477
- totalSize += add;
2478
- }
2479
- if (prevTotalSize !== totalSize) {
2480
- {
2481
- state.pendingTotalSize = void 0;
2482
- state.totalSize = totalSize;
2483
- if (notifyTotalSize) {
2484
- set$(ctx, "totalSize", totalSize);
2485
- }
2486
- updateContentMetrics(ctx);
2487
- }
2488
- } else if (notifyTotalSize && ctx.values.get("totalSize") !== totalSize) {
2489
- set$(ctx, "totalSize", totalSize);
2490
- }
2491
- }
2492
-
2493
- // src/core/setSize.ts
2494
- function setSize(ctx, itemKey, size, notifyTotalSize = true) {
2495
- const state = ctx.state;
2496
- const { sizes } = state;
2497
- const previousSize = sizes.get(itemKey);
2498
- const diff = previousSize !== void 0 ? size - previousSize : size;
2499
- if (diff !== 0) {
2500
- addTotalSize(ctx, itemKey, diff, notifyTotalSize);
2501
- }
2502
- sizes.set(itemKey, size);
2503
- }
2504
-
2505
- // src/utils/getItemSize.ts
2506
- function getKnownOrFixedSize(ctx, key, index, data, resolved) {
2507
- var _a3, _b;
2508
- const state = ctx.state;
2509
- const { getFixedItemSize, getItemType } = state.props;
2510
- let size = key ? state.sizesKnown.get(key) : void 0;
2511
- if (size === void 0 && key && getFixedItemSize) {
2512
- const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
2513
- size = (resolved == null ? void 0 : resolved.didResolveFixedItemSize) ? resolved.fixedItemSize : getFixedItemSize(data, index, itemType);
2514
- if (size !== void 0) {
2515
- state.sizesKnown.set(key, size);
2516
- }
2517
- }
2518
- return size;
2519
- }
2520
- function getKnownOrFixedItemSize(ctx, index) {
2521
- const key = getId(ctx.state, index);
2522
- return getKnownOrFixedSize(ctx, key, index, ctx.state.props.data[index]);
2523
- }
2524
- function areKnownOrFixedItemSizesAvailable(ctx, startIndex, endIndex) {
2525
- for (let index = startIndex; index <= endIndex; index++) {
2526
- if (getKnownOrFixedItemSize(ctx, index) === void 0) {
2527
- return false;
2528
- }
2529
- }
2530
- return true;
2531
- }
2532
- function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, notifyTotalSize, resolved) {
2533
- var _a3, _b, _c, _d;
2534
- const state = ctx.state;
2535
- const {
2536
- sizes,
2537
- averageSizes,
2538
- props: { estimatedItemSize, getItemType },
2539
- scrollingTo
2540
- } = state;
2541
- const sizeKnown = state.sizesKnown.get(key);
2542
- if (sizeKnown !== void 0) {
2543
- return sizeKnown;
2544
- }
2545
- let size;
2546
- const renderedSize = sizes.get(key);
2547
- if (preferCachedSize) {
2548
- if (renderedSize !== void 0) {
2549
- return renderedSize;
2550
- }
2551
- }
2552
- size = getKnownOrFixedSize(ctx, key, index, data, resolved);
2553
- if (size !== void 0) {
2554
- setSize(ctx, key, size, notifyTotalSize);
2555
- return size;
2556
- }
2557
- const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
2558
- if (useAverageSize && !scrollingTo) {
2559
- const averageSizeForType = (_c = averageSizes[itemType]) == null ? void 0 : _c.avg;
2560
- if (averageSizeForType !== void 0) {
2561
- size = roundSize(averageSizeForType);
2562
- }
2563
- }
2564
- if (size === void 0 && renderedSize !== void 0) {
2565
- return renderedSize;
2566
- }
2567
- if (size === void 0 && useAverageSize && scrollingTo) {
2568
- const averageSizeForType = (_d = scrollingTo.averageSizeSnapshot) == null ? void 0 : _d[itemType];
2569
- if (averageSizeForType !== void 0) {
2570
- size = roundSize(averageSizeForType);
2571
- }
2572
- }
2573
- if (size === void 0) {
2574
- size = estimatedItemSize;
2575
- }
2576
- setSize(ctx, key, size, notifyTotalSize);
2577
- return size;
2578
- }
2579
- function getItemSizeAtIndex(ctx, index) {
2580
- if (index === void 0 || index < 0) {
2581
- return void 0;
2582
- }
2583
- const targetId = getId(ctx.state, index);
2584
- return getItemSize(ctx, targetId, index, ctx.state.props.data[index]);
2585
- }
2586
-
2587
- // src/core/calculateOffsetWithOffsetPosition.ts
2588
- function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
2589
- var _a3;
2590
- const state = ctx.state;
2591
- const { index, viewOffset, viewPosition } = params;
2592
- let offset = offsetParam;
2593
- if (viewOffset) {
2594
- offset -= viewOffset;
2595
- }
2596
- if (index !== void 0) {
2597
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
2598
- if (topOffsetAdjustment) {
2599
- offset += topOffsetAdjustment;
2600
- }
2601
- }
2602
- if (viewPosition !== void 0 && index !== void 0) {
2603
- const dataLength = state.props.data.length;
2604
- if (dataLength === 0) {
2605
- return offset;
2606
- }
2607
- const isOutOfBounds = index < 0 || index >= dataLength;
2608
- const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
2609
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
2610
- const trailingInset = getContentInsetEnd(ctx);
2611
- offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
2612
- if (!isOutOfBounds && index === state.props.data.length - 1) {
2613
- const footerSize = peek$(ctx, "footerSize") || 0;
2614
- offset += footerSize;
2615
- }
2616
- }
2617
- return offset;
2618
- }
2619
-
2620
- // src/core/clampScrollOffset.ts
2621
- function clampScrollOffset(ctx, offset, scrollTarget) {
2622
- const state = ctx.state;
2623
- const contentSize = getContentSize(ctx);
2624
- let clampedOffset = offset;
2625
- if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android")) {
2626
- const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
2627
- const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
2628
- const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
2629
- const maxOffset = baseMaxOffset + extraEndOffset;
2630
- clampedOffset = Math.min(offset, maxOffset);
2631
- }
2632
- clampedOffset = Math.max(0, clampedOffset);
2633
- return clampedOffset;
2634
- }
2635
-
2636
2355
  // src/core/finishScrollTo.ts
2637
2356
  function finishScrollTo(ctx) {
2638
2357
  var _a3, _b;
@@ -2709,50 +2428,491 @@ function listenForScrollEnd(ctx, params) {
2709
2428
  finishScrollTo(ctx);
2710
2429
  return;
2711
2430
  }
2712
- const supportsScrollEnd = "onscrollend" in target;
2713
- let idleTimeout;
2714
- let settled = false;
2715
- const targetToken = ctx.state.scrollingTo;
2716
- const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
2717
- const cleanup = () => {
2718
- target.removeEventListener("scroll", onScroll2);
2719
- if (supportsScrollEnd) {
2720
- target.removeEventListener("scrollend", onScrollEnd);
2431
+ const supportsScrollEnd = "onscrollend" in target;
2432
+ let idleTimeout;
2433
+ let settled = false;
2434
+ const targetToken = ctx.state.scrollingTo;
2435
+ const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
2436
+ const cleanup = () => {
2437
+ target.removeEventListener("scroll", onScroll2);
2438
+ if (supportsScrollEnd) {
2439
+ target.removeEventListener("scrollend", onScrollEnd);
2440
+ }
2441
+ if (idleTimeout) {
2442
+ clearTimeout(idleTimeout);
2443
+ }
2444
+ clearTimeout(maxTimeout);
2445
+ };
2446
+ const finish = (reason) => {
2447
+ if (settled) return;
2448
+ if (targetToken !== ctx.state.scrollingTo) {
2449
+ settled = true;
2450
+ cleanup();
2451
+ return;
2452
+ }
2453
+ const currentOffset = readOffset();
2454
+ const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
2455
+ if (reason === "scrollend" && !isNearTarget) {
2456
+ return;
2457
+ }
2458
+ settled = true;
2459
+ cleanup();
2460
+ finishScrollTo(ctx);
2461
+ };
2462
+ const onScroll2 = () => {
2463
+ if (idleTimeout) {
2464
+ clearTimeout(idleTimeout);
2465
+ }
2466
+ idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
2467
+ };
2468
+ const onScrollEnd = () => finish("scrollend");
2469
+ target.addEventListener("scroll", onScroll2);
2470
+ if (supportsScrollEnd) {
2471
+ target.addEventListener("scrollend", onScrollEnd);
2472
+ } else {
2473
+ idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
2474
+ }
2475
+ }
2476
+
2477
+ // src/utils/requestAdjust.ts
2478
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2479
+ const state = ctx.state;
2480
+ if (Math.abs(positionDiff) > 0.1) {
2481
+ const doit = () => {
2482
+ {
2483
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
2484
+ if (state.adjustingFromInitialMount) {
2485
+ state.adjustingFromInitialMount--;
2486
+ }
2487
+ }
2488
+ };
2489
+ state.scroll += positionDiff;
2490
+ state.scrollForNextCalculateItemsInView = void 0;
2491
+ const readyToRender = peek$(ctx, "readyToRender");
2492
+ if (readyToRender) {
2493
+ doit();
2494
+ } else {
2495
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2496
+ requestAnimationFrame(doit);
2497
+ }
2498
+ }
2499
+ }
2500
+
2501
+ // src/core/updateContentMetrics.ts
2502
+ var SCROLL_ADJUST_EPSILON = 0.1;
2503
+ function setContentLengthSignal(ctx, signalName, size) {
2504
+ if (peek$(ctx, signalName) !== size) {
2505
+ set$(ctx, signalName, size);
2506
+ updateContentMetricsState(ctx);
2507
+ }
2508
+ }
2509
+ function shouldAdjustForHeaderSizeChange(ctx, previousHeaderSize, nextHeaderSize) {
2510
+ const { didContainersLayout, didFinishInitialScroll, props, scroll, scrollingTo } = ctx.state;
2511
+ const sizeDiff = nextHeaderSize - previousHeaderSize;
2512
+ const leadingPadding = props.horizontal ? props.stylePaddingLeft : props.stylePaddingTop;
2513
+ const previousHeaderEnd = (leadingPadding || 0) + previousHeaderSize;
2514
+ return props.maintainVisibleContentPosition.size && didContainersLayout && didFinishInitialScroll && !scrollingTo && scroll >= previousHeaderEnd - SCROLL_ADJUST_EPSILON && Math.abs(sizeDiff) > SCROLL_ADJUST_EPSILON;
2515
+ }
2516
+ function setHeaderSize(ctx, size) {
2517
+ const { state } = ctx;
2518
+ const previousHeaderSize = peek$(ctx, "headerSize") || 0;
2519
+ const didChange = previousHeaderSize !== size;
2520
+ const hasMeasuredOrEstimatedHeaderBaseline = state.didMeasureHeader || previousHeaderSize > SCROLL_ADJUST_EPSILON;
2521
+ if (didChange) {
2522
+ set$(ctx, "headerSize", size);
2523
+ updateContentMetricsState(ctx);
2524
+ if (hasMeasuredOrEstimatedHeaderBaseline && shouldAdjustForHeaderSizeChange(ctx, previousHeaderSize, size)) {
2525
+ requestAdjust(ctx, size - previousHeaderSize);
2526
+ }
2527
+ }
2528
+ state.didMeasureHeader = true;
2529
+ }
2530
+ function setFooterSize(ctx, size) {
2531
+ setContentLengthSignal(ctx, "footerSize", size);
2532
+ }
2533
+ function areInsetsEqual(left, right) {
2534
+ var _a3, _b, _c, _d, _e, _f, _g, _h;
2535
+ 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);
2536
+ }
2537
+ function setContentInsetOverride(ctx, inset) {
2538
+ const { state } = ctx;
2539
+ const previousInset = state.contentInsetOverride;
2540
+ const nextInset = inset != null ? inset : void 0;
2541
+ const didChange = !areInsetsEqual(previousInset, nextInset);
2542
+ state.contentInsetOverride = nextInset;
2543
+ if (didChange) {
2544
+ updateContentMetricsState(ctx);
2545
+ }
2546
+ return didChange;
2547
+ }
2548
+ function useStableRenderComponent(renderComponent, mapProps) {
2549
+ const renderComponentRef = useLatestRef(renderComponent);
2550
+ const mapPropsRef = useLatestRef(mapProps);
2551
+ return React3.useMemo(
2552
+ () => React3.forwardRef(
2553
+ (props, ref) => {
2554
+ var _a3, _b;
2555
+ return (_b = (_a3 = renderComponentRef.current) == null ? void 0 : _a3.call(renderComponentRef, mapPropsRef.current(props, ref))) != null ? _b : null;
2556
+ }
2557
+ ),
2558
+ [mapPropsRef, renderComponentRef]
2559
+ );
2560
+ }
2561
+ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
2562
+ const localRef = useRef(null);
2563
+ const ref = refView != null ? refView : localRef;
2564
+ useOnLayoutSync({ onLayoutChange, ref });
2565
+ return /* @__PURE__ */ React3.createElement("div", { ...rest, ref }, children);
2566
+ };
2567
+
2568
+ // src/components/ListComponent.tsx
2569
+ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizontal }) {
2570
+ const [alignItemsAtEndPadding = 0] = useArr$(["alignItemsAtEndPadding"]);
2571
+ if (alignItemsAtEndPadding <= 0) {
2572
+ return null;
2573
+ }
2574
+ return /* @__PURE__ */ React3.createElement(
2575
+ View,
2576
+ {
2577
+ style: horizontal ? { flexShrink: 0, width: alignItemsAtEndPadding } : { flexShrink: 0, height: alignItemsAtEndPadding }
2578
+ },
2579
+ null
2580
+ );
2581
+ });
2582
+ var ListComponent = typedMemo(function ListComponent2({
2583
+ canRender,
2584
+ style,
2585
+ contentContainerStyle,
2586
+ horizontal,
2587
+ initialContentOffset,
2588
+ recycleItems,
2589
+ ItemSeparatorComponent,
2590
+ alignItemsAtEnd: _alignItemsAtEnd,
2591
+ onScroll: onScroll2,
2592
+ onLayout,
2593
+ ListHeaderComponent,
2594
+ ListHeaderComponentStyle,
2595
+ ListFooterComponent,
2596
+ ListFooterComponentStyle,
2597
+ ListEmptyComponent,
2598
+ getRenderedItem: getRenderedItem2,
2599
+ updateItemSize: updateItemSize2,
2600
+ refScrollView,
2601
+ renderScrollComponent,
2602
+ onLayoutFooter,
2603
+ scrollAdjustHandler,
2604
+ snapToIndices,
2605
+ stickyHeaderConfig,
2606
+ stickyHeaderIndices,
2607
+ useWindowScroll = false,
2608
+ ...rest
2609
+ }) {
2610
+ const ctx = useStateContext();
2611
+ const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
2612
+ const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
2613
+ const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
2614
+ const autoOtherAxisStyle = getAutoOtherAxisStyle({
2615
+ horizontal,
2616
+ needsOtherAxisSize: ctx.state.needsOtherAxisSize,
2617
+ otherAxisSize
2618
+ });
2619
+ const CustomScrollComponent = useStableRenderComponent(
2620
+ renderScrollComponent,
2621
+ (props, ref) => ({ ...props, ref })
2622
+ );
2623
+ const ScrollComponent = renderScrollComponent ? CustomScrollComponent : ListComponentScrollView;
2624
+ const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
2625
+ useLayoutEffect(() => {
2626
+ if (!ListHeaderComponent) {
2627
+ setHeaderSize(ctx, 0);
2628
+ }
2629
+ if (!ListFooterComponent) {
2630
+ setFooterSize(ctx, 0);
2631
+ }
2632
+ }, [ListHeaderComponent, ListFooterComponent, ctx]);
2633
+ const onLayoutHeader = useCallback(
2634
+ (rect) => {
2635
+ const size = rect[horizontal ? "width" : "height"];
2636
+ setHeaderSize(ctx, size);
2637
+ },
2638
+ [ctx, horizontal]
2639
+ );
2640
+ const onLayoutFooterInternal = useCallback(
2641
+ (rect, fromLayoutEffect) => {
2642
+ const size = rect[horizontal ? "width" : "height"];
2643
+ setFooterSize(ctx, size);
2644
+ onLayoutFooter == null ? void 0 : onLayoutFooter(rect, fromLayoutEffect);
2645
+ },
2646
+ [ctx, horizontal, onLayoutFooter]
2647
+ );
2648
+ return /* @__PURE__ */ React3.createElement(
2649
+ SnapOrScroll,
2650
+ {
2651
+ ...rest,
2652
+ ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
2653
+ contentContainerStyle: [
2654
+ horizontal ? {
2655
+ height: "100%"
2656
+ } : {},
2657
+ contentContainerStyle
2658
+ ],
2659
+ contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
2660
+ horizontal,
2661
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
2662
+ onLayout,
2663
+ onScroll: onScroll2,
2664
+ ref: refScrollView,
2665
+ ScrollComponent: snapToIndices ? ScrollComponent : void 0,
2666
+ style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
2667
+ },
2668
+ /* @__PURE__ */ React3.createElement(ScrollAdjust, null),
2669
+ ListHeaderComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
2670
+ ListEmptyComponent && getComponent(ListEmptyComponent),
2671
+ shouldRenderAlignItemsAtEndSpacer && /* @__PURE__ */ React3.createElement(AlignItemsAtEndSpacer, { horizontal }),
2672
+ canRender && !ListEmptyComponent && /* @__PURE__ */ React3.createElement(
2673
+ Containers,
2674
+ {
2675
+ getRenderedItem: getRenderedItem2,
2676
+ horizontal,
2677
+ ItemSeparatorComponent,
2678
+ recycleItems,
2679
+ stickyHeaderConfig,
2680
+ updateItemSize: updateItemSize2
2681
+ }
2682
+ ),
2683
+ ListFooterComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
2684
+ /* @__PURE__ */ React3.createElement(WebAnchoredEndSpace, { horizontal }),
2685
+ IS_DEV && ENABLE_DEVMODE
2686
+ );
2687
+ });
2688
+ var WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH = 100;
2689
+ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
2690
+ var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
2691
+ function useDevChecksImpl(props) {
2692
+ const ctx = useStateContext();
2693
+ const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
2694
+ useEffect(() => {
2695
+ if (useWindowScroll && renderScrollComponent) {
2696
+ warnDevOnce(
2697
+ "useWindowScrollRenderScrollComponent",
2698
+ "useWindowScroll is not supported when renderScrollComponent is provided."
2699
+ );
2700
+ }
2701
+ }, [renderScrollComponent, useWindowScroll]);
2702
+ useEffect(() => {
2703
+ if (!keyExtractor && !ctx.state.isFirst && ctx.state.didDataChange && !childrenMode) {
2704
+ warnDevOnce(
2705
+ "keyExtractor",
2706
+ "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."
2707
+ );
2708
+ }
2709
+ }, [childrenMode, ctx, keyExtractor]);
2710
+ useEffect(() => {
2711
+ const state = ctx.state;
2712
+ const dataLength = state.props.data.length;
2713
+ const useWindowScrollResolved = state.props.useWindowScroll;
2714
+ if (useWindowScrollResolved || dataLength < WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH) {
2715
+ return;
2716
+ }
2717
+ const warnIfUnboundedOuterSize = () => {
2718
+ const readyToRender = peek$(ctx, "readyToRender");
2719
+ const numContainers = peek$(ctx, "numContainers") || 0;
2720
+ const totalSize = peek$(ctx, "totalSize") || 0;
2721
+ const scrollLength = ctx.state.scrollLength || 0;
2722
+ if (!readyToRender || totalSize <= 0 || scrollLength <= 0) {
2723
+ return;
2724
+ }
2725
+ const rendersAlmostEverything = numContainers >= Math.ceil(dataLength * WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO);
2726
+ const viewportMatchesContent = scrollLength >= totalSize * WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO;
2727
+ if (rendersAlmostEverything && viewportMatchesContent) {
2728
+ warnDevOnce(
2729
+ "webUnboundedOuterSize",
2730
+ "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."
2731
+ );
2732
+ }
2733
+ };
2734
+ warnIfUnboundedOuterSize();
2735
+ const unsubscribe = [
2736
+ listen$(ctx, "numContainers", warnIfUnboundedOuterSize),
2737
+ listen$(ctx, "readyToRender", warnIfUnboundedOuterSize),
2738
+ listen$(ctx, "totalSize", warnIfUnboundedOuterSize)
2739
+ ];
2740
+ return () => {
2741
+ for (const unsub of unsubscribe) {
2742
+ unsub();
2743
+ }
2744
+ };
2745
+ }, [ctx]);
2746
+ }
2747
+ function useDevChecksNoop(_props) {
2748
+ }
2749
+ var useDevChecks = IS_DEV ? useDevChecksImpl : useDevChecksNoop;
2750
+
2751
+ // src/core/calculateOffsetForIndex.ts
2752
+ function calculateOffsetForIndex(ctx, index) {
2753
+ const state = ctx.state;
2754
+ return index !== void 0 ? state.positions[index] || 0 : 0;
2755
+ }
2756
+
2757
+ // src/core/getTopOffsetAdjustment.ts
2758
+ function getTopOffsetAdjustment(ctx) {
2759
+ return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
2760
+ }
2761
+
2762
+ // src/utils/getId.ts
2763
+ function getId(state, index) {
2764
+ const { data, keyExtractor } = state.props;
2765
+ if (!data) {
2766
+ return "";
2767
+ }
2768
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
2769
+ const id = ret;
2770
+ state.idCache[index] = id;
2771
+ return id;
2772
+ }
2773
+
2774
+ // src/core/setSize.ts
2775
+ function setSize(ctx, itemKey, size, notifyTotalSize = true) {
2776
+ const state = ctx.state;
2777
+ const { sizes } = state;
2778
+ const previousSize = sizes.get(itemKey);
2779
+ const diff = previousSize !== void 0 ? size - previousSize : size;
2780
+ if (diff !== 0) {
2781
+ addTotalSize(ctx, itemKey, diff, notifyTotalSize);
2782
+ }
2783
+ sizes.set(itemKey, size);
2784
+ }
2785
+
2786
+ // src/utils/getItemSize.ts
2787
+ function getKnownOrFixedSize(ctx, key, index, data, resolved) {
2788
+ var _a3, _b;
2789
+ const state = ctx.state;
2790
+ const { getFixedItemSize, getItemType } = state.props;
2791
+ let size = key ? state.sizesKnown.get(key) : void 0;
2792
+ if (size === void 0 && key && getFixedItemSize) {
2793
+ const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
2794
+ const fixedSize = (resolved == null ? void 0 : resolved.didResolveFixedItemSize) ? resolved.fixedItemSize : getFixedItemSize(data, index, itemType);
2795
+ if (fixedSize !== void 0) {
2796
+ size = fixedSize + ctx.scrollAxisGap;
2797
+ state.sizesKnown.set(key, size);
2798
+ }
2799
+ }
2800
+ return size;
2801
+ }
2802
+ function getKnownOrFixedItemSize(ctx, index) {
2803
+ const key = getId(ctx.state, index);
2804
+ return getKnownOrFixedSize(ctx, key, index, ctx.state.props.data[index]);
2805
+ }
2806
+ function areKnownOrFixedItemSizesAvailable(ctx, startIndex, endIndex) {
2807
+ for (let index = startIndex; index <= endIndex; index++) {
2808
+ if (getKnownOrFixedItemSize(ctx, index) === void 0) {
2809
+ return false;
2810
+ }
2811
+ }
2812
+ return true;
2813
+ }
2814
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, notifyTotalSize, resolved) {
2815
+ var _a3, _b, _c, _d;
2816
+ const state = ctx.state;
2817
+ const {
2818
+ sizes,
2819
+ averageSizes,
2820
+ props: { estimatedItemSize, getItemType },
2821
+ scrollingTo
2822
+ } = state;
2823
+ const sizeKnown = state.sizesKnown.get(key);
2824
+ if (sizeKnown !== void 0) {
2825
+ return sizeKnown;
2826
+ }
2827
+ let size;
2828
+ const renderedSize = sizes.get(key);
2829
+ if (preferCachedSize) {
2830
+ if (renderedSize !== void 0) {
2831
+ return renderedSize;
2832
+ }
2833
+ }
2834
+ size = getKnownOrFixedSize(ctx, key, index, data, resolved);
2835
+ if (size !== void 0) {
2836
+ setSize(ctx, key, size, notifyTotalSize);
2837
+ return size;
2838
+ }
2839
+ const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
2840
+ if (useAverageSize && !scrollingTo) {
2841
+ const averageSizeForType = (_c = averageSizes[itemType]) == null ? void 0 : _c.avg;
2842
+ if (averageSizeForType !== void 0) {
2843
+ size = roundSize(averageSizeForType);
2721
2844
  }
2722
- if (idleTimeout) {
2723
- clearTimeout(idleTimeout);
2845
+ }
2846
+ if (size === void 0 && renderedSize !== void 0) {
2847
+ return renderedSize;
2848
+ }
2849
+ if (size === void 0 && useAverageSize && scrollingTo) {
2850
+ const averageSizeForType = (_d = scrollingTo.averageSizeSnapshot) == null ? void 0 : _d[itemType];
2851
+ if (averageSizeForType !== void 0) {
2852
+ size = roundSize(averageSizeForType);
2724
2853
  }
2725
- clearTimeout(maxTimeout);
2726
- };
2727
- const finish = (reason) => {
2728
- if (settled) return;
2729
- if (targetToken !== ctx.state.scrollingTo) {
2730
- settled = true;
2731
- cleanup();
2732
- return;
2854
+ }
2855
+ if (size === void 0) {
2856
+ size = estimatedItemSize + ctx.scrollAxisGap;
2857
+ }
2858
+ setSize(ctx, key, size, notifyTotalSize);
2859
+ return size;
2860
+ }
2861
+ function getItemSizeAtIndex(ctx, index) {
2862
+ if (index === void 0 || index < 0) {
2863
+ return void 0;
2864
+ }
2865
+ const targetId = getId(ctx.state, index);
2866
+ return getItemSize(ctx, targetId, index, ctx.state.props.data[index]);
2867
+ }
2868
+
2869
+ // src/core/calculateOffsetWithOffsetPosition.ts
2870
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
2871
+ var _a3;
2872
+ const state = ctx.state;
2873
+ const { index, viewOffset, viewPosition } = params;
2874
+ let offset = offsetParam;
2875
+ if (viewOffset) {
2876
+ offset -= viewOffset;
2877
+ }
2878
+ if (index !== void 0) {
2879
+ const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
2880
+ if (topOffsetAdjustment) {
2881
+ offset += topOffsetAdjustment;
2733
2882
  }
2734
- const currentOffset = readOffset();
2735
- const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
2736
- if (reason === "scrollend" && !isNearTarget) {
2737
- return;
2883
+ }
2884
+ if (viewPosition !== void 0 && index !== void 0) {
2885
+ const dataLength = state.props.data.length;
2886
+ if (dataLength === 0) {
2887
+ return offset;
2738
2888
  }
2739
- settled = true;
2740
- cleanup();
2741
- finishScrollTo(ctx);
2742
- };
2743
- const onScroll2 = () => {
2744
- if (idleTimeout) {
2745
- clearTimeout(idleTimeout);
2889
+ const isOutOfBounds = index < 0 || index >= dataLength;
2890
+ const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
2891
+ const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
2892
+ const trailingInset = getContentInsetEnd(ctx);
2893
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
2894
+ if (!isOutOfBounds && index === state.props.data.length - 1) {
2895
+ const footerSize = peek$(ctx, "footerSize") || 0;
2896
+ offset += footerSize;
2746
2897
  }
2747
- idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
2748
- };
2749
- const onScrollEnd = () => finish("scrollend");
2750
- target.addEventListener("scroll", onScroll2);
2751
- if (supportsScrollEnd) {
2752
- target.addEventListener("scrollend", onScrollEnd);
2753
- } else {
2754
- idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
2755
2898
  }
2899
+ return offset;
2900
+ }
2901
+
2902
+ // src/core/clampScrollOffset.ts
2903
+ function clampScrollOffset(ctx, offset, scrollTarget) {
2904
+ const state = ctx.state;
2905
+ const contentSize = getContentSize(ctx);
2906
+ let clampedOffset = offset;
2907
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android")) {
2908
+ const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
2909
+ const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
2910
+ const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
2911
+ const maxOffset = baseMaxOffset + extraEndOffset;
2912
+ clampedOffset = Math.min(offset, maxOffset);
2913
+ }
2914
+ clampedOffset = Math.max(0, clampedOffset);
2915
+ return clampedOffset;
2756
2916
  }
2757
2917
 
2758
2918
  // src/core/doMaintainScrollAtEnd.ts
@@ -2777,9 +2937,12 @@ function doMaintainScrollAtEnd(ctx) {
2777
2937
  state.scroll = 0;
2778
2938
  }
2779
2939
  if (!state.maintainingScrollAtEnd) {
2780
- state.maintainingScrollAtEnd = true;
2940
+ const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
2941
+ const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
2942
+ state.maintainingScrollAtEnd = pendingState;
2781
2943
  requestAnimationFrame(() => {
2782
2944
  if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
2945
+ state.maintainingScrollAtEnd = activeState;
2783
2946
  const scroller = refScroller.current;
2784
2947
  if (state.props.horizontal && isHorizontalRTL(state)) {
2785
2948
  const currentContentSize = getContentSize(ctx);
@@ -2797,12 +2960,14 @@ function doMaintainScrollAtEnd(ctx) {
2797
2960
  }
2798
2961
  setTimeout(
2799
2962
  () => {
2800
- state.maintainingScrollAtEnd = false;
2963
+ if (state.maintainingScrollAtEnd === activeState) {
2964
+ state.maintainingScrollAtEnd = void 0;
2965
+ }
2801
2966
  },
2802
2967
  maintainScrollAtEnd.animated ? 500 : 0
2803
2968
  );
2804
- } else {
2805
- state.maintainingScrollAtEnd = false;
2969
+ } else if (state.maintainingScrollAtEnd === pendingState) {
2970
+ state.maintainingScrollAtEnd = void 0;
2806
2971
  }
2807
2972
  });
2808
2973
  }
@@ -2811,30 +2976,6 @@ function doMaintainScrollAtEnd(ctx) {
2811
2976
  return false;
2812
2977
  }
2813
2978
 
2814
- // src/utils/requestAdjust.ts
2815
- function requestAdjust(ctx, positionDiff, dataChanged) {
2816
- const state = ctx.state;
2817
- if (Math.abs(positionDiff) > 0.1) {
2818
- const doit = () => {
2819
- {
2820
- state.scrollAdjustHandler.requestAdjust(positionDiff);
2821
- if (state.adjustingFromInitialMount) {
2822
- state.adjustingFromInitialMount--;
2823
- }
2824
- }
2825
- };
2826
- state.scroll += positionDiff;
2827
- state.scrollForNextCalculateItemsInView = void 0;
2828
- const readyToRender = peek$(ctx, "readyToRender");
2829
- if (readyToRender) {
2830
- doit();
2831
- } else {
2832
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2833
- requestAnimationFrame(doit);
2834
- }
2835
- }
2836
- }
2837
-
2838
2979
  // src/core/mvcp.ts
2839
2980
  var MVCP_POSITION_EPSILON = 0.1;
2840
2981
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -2980,6 +3121,10 @@ function prepareMVCP(ctx, dataChanged) {
2980
3121
  const now = Date.now();
2981
3122
  const enableMVCPAnchorLock = (!!dataChanged || !!state.mvcpAnchorLock);
2982
3123
  const scrollingTo = state.scrollingTo;
3124
+ if (dataChanged && state.pendingScrollToEnd && scrollingTo === void 0) {
3125
+ state.mvcpAnchorLock = void 0;
3126
+ return void 0;
3127
+ }
2983
3128
  const anchorLock = resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) ;
2984
3129
  let prevPosition;
2985
3130
  let targetId;
@@ -3108,7 +3253,7 @@ function prepareMVCP(ctx, dataChanged) {
3108
3253
  return;
3109
3254
  }
3110
3255
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
3111
- const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
3256
+ const shouldSkipAdjustForMaintainedEnd = (state.maintainingScrollAtEnd === "pending-animated" || state.maintainingScrollAtEnd === "animated") && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
3112
3257
  if (!shouldSkipAdjustForMaintainedEnd) {
3113
3258
  requestAdjust(ctx, positionDiff);
3114
3259
  }
@@ -3117,6 +3262,45 @@ function prepareMVCP(ctx, dataChanged) {
3117
3262
  }
3118
3263
  }
3119
3264
 
3265
+ // src/utils/getScrollVelocity.ts
3266
+ var getScrollVelocity = (state) => {
3267
+ const { scrollHistory } = state;
3268
+ const newestIndex = scrollHistory.length - 1;
3269
+ if (newestIndex < 1) {
3270
+ return 0;
3271
+ }
3272
+ const newest = scrollHistory[newestIndex];
3273
+ const now = Date.now();
3274
+ let direction = 0;
3275
+ for (let i = newestIndex; i > 0; i--) {
3276
+ const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
3277
+ if (delta !== 0) {
3278
+ direction = Math.sign(delta);
3279
+ break;
3280
+ }
3281
+ }
3282
+ if (direction === 0) {
3283
+ return 0;
3284
+ }
3285
+ let oldest = newest;
3286
+ for (let i = newestIndex - 1; i >= 0; i--) {
3287
+ const current = scrollHistory[i];
3288
+ const next = scrollHistory[i + 1];
3289
+ const delta = next.scroll - current.scroll;
3290
+ const deltaSign = Math.sign(delta);
3291
+ if (deltaSign !== 0 && deltaSign !== direction) {
3292
+ break;
3293
+ }
3294
+ if (now - current.time > 1e3) {
3295
+ break;
3296
+ }
3297
+ oldest = current;
3298
+ }
3299
+ const scrollDiff = newest.scroll - oldest.scroll;
3300
+ const timeDiff = newest.time - oldest.time;
3301
+ return timeDiff > 0 ? scrollDiff / timeDiff : 0;
3302
+ };
3303
+
3120
3304
  // src/core/updateScroll.ts
3121
3305
  function updateScroll(ctx, newScroll, forceUpdate, options) {
3122
3306
  var _a3;
@@ -3142,6 +3326,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
3142
3326
  if (scrollHistory.length > 5) {
3143
3327
  scrollHistory.shift();
3144
3328
  }
3329
+ const scrollVelocity = getScrollVelocity(state);
3330
+ updateAdaptiveRender(ctx, scrollVelocity);
3145
3331
  if (ignoreScrollFromMVCP && !scrollingTo) {
3146
3332
  const { lt, gt } = ignoreScrollFromMVCP;
3147
3333
  if (lt && newScroll < lt || gt && newScroll > gt) {
@@ -3165,7 +3351,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
3165
3351
  state.lastScrollDelta = scrollDelta;
3166
3352
  const runCalculateItems = () => {
3167
3353
  var _a4;
3168
- (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0 });
3354
+ (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0, scrollVelocity });
3169
3355
  checkThresholds(ctx);
3170
3356
  };
3171
3357
  if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength && !state.pendingNativeMVCPAdjust) {
@@ -4245,9 +4431,32 @@ function initializeInitialScrollOnMount(ctx, options) {
4245
4431
  }
4246
4432
  function handleInitialScrollDataChange(ctx, options) {
4247
4433
  var _a3, _b, _c;
4248
- const { dataLength, didDataChange, initialScrollAtEnd, stylePaddingBottom, useBootstrapInitialScroll } = options;
4434
+ const {
4435
+ dataLength,
4436
+ didDataChange,
4437
+ initialScrollAtEnd,
4438
+ latestInitialScroll,
4439
+ latestInitialScrollSessionKind,
4440
+ stylePaddingBottom,
4441
+ useBootstrapInitialScroll
4442
+ } = options;
4249
4443
  const state = ctx.state;
4250
4444
  const previousDataLength = (_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.previousDataLength) != null ? _b : 0;
4445
+ const isFirstNonEmptyData = !state.hasHadNonEmptyData && dataLength > 0;
4446
+ if (dataLength > 0) {
4447
+ state.hasHadNonEmptyData = true;
4448
+ }
4449
+ if (isFirstNonEmptyData) {
4450
+ if (latestInitialScroll) {
4451
+ setInitialScrollTarget(state, latestInitialScroll);
4452
+ setInitialScrollSession(state, {
4453
+ kind: latestInitialScrollSessionKind,
4454
+ previousDataLength
4455
+ });
4456
+ } else {
4457
+ clearPreservedInitialScrollTarget(state);
4458
+ }
4459
+ }
4251
4460
  if (state.initialScrollSession) {
4252
4461
  state.initialScrollSession.previousDataLength = dataLength;
4253
4462
  }
@@ -4471,45 +4680,6 @@ function updateTotalSize(ctx) {
4471
4680
  }
4472
4681
  }
4473
4682
 
4474
- // src/utils/getScrollVelocity.ts
4475
- var getScrollVelocity = (state) => {
4476
- const { scrollHistory } = state;
4477
- const newestIndex = scrollHistory.length - 1;
4478
- if (newestIndex < 1) {
4479
- return 0;
4480
- }
4481
- const newest = scrollHistory[newestIndex];
4482
- const now = Date.now();
4483
- let direction = 0;
4484
- for (let i = newestIndex; i > 0; i--) {
4485
- const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
4486
- if (delta !== 0) {
4487
- direction = Math.sign(delta);
4488
- break;
4489
- }
4490
- }
4491
- if (direction === 0) {
4492
- return 0;
4493
- }
4494
- let oldest = newest;
4495
- for (let i = newestIndex - 1; i >= 0; i--) {
4496
- const current = scrollHistory[i];
4497
- const next = scrollHistory[i + 1];
4498
- const delta = next.scroll - current.scroll;
4499
- const deltaSign = Math.sign(delta);
4500
- if (deltaSign !== 0 && deltaSign !== direction) {
4501
- break;
4502
- }
4503
- if (now - current.time > 1e3) {
4504
- break;
4505
- }
4506
- oldest = current;
4507
- }
4508
- const scrollDiff = newest.scroll - oldest.scroll;
4509
- const timeDiff = newest.time - oldest.time;
4510
- return timeDiff > 0 ? scrollDiff / timeDiff : 0;
4511
- };
4512
-
4513
4683
  // src/utils/updateSnapToOffsets.ts
4514
4684
  function updateSnapToOffsets(ctx) {
4515
4685
  const state = ctx.state;
@@ -5245,7 +5415,7 @@ function updateViewabilityForCachedRange(ctx, viewabilityConfigCallbackPairs, sc
5245
5415
  function calculateItemsInView(ctx, params = {}) {
5246
5416
  const state = ctx.state;
5247
5417
  batchedUpdates(() => {
5248
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
5418
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
5249
5419
  const {
5250
5420
  columns,
5251
5421
  containerItemKeys,
@@ -5254,14 +5424,7 @@ function calculateItemsInView(ctx, params = {}) {
5254
5424
  indexByKey,
5255
5425
  minIndexSizeChanged,
5256
5426
  positions,
5257
- props: {
5258
- alwaysRenderIndicesArr,
5259
- alwaysRenderIndicesSet,
5260
- drawDistance,
5261
- getItemType,
5262
- keyExtractor,
5263
- onStickyHeaderChange
5264
- },
5427
+ props: { alwaysRenderIndicesArr, alwaysRenderIndicesSet, getItemType, keyExtractor, onStickyHeaderChange },
5265
5428
  scrollForNextCalculateItemsInView,
5266
5429
  scrollLength,
5267
5430
  sizes,
@@ -5273,6 +5436,7 @@ function calculateItemsInView(ctx, params = {}) {
5273
5436
  const stickyHeaderIndicesSet = state.props.stickyHeaderIndicesSet || /* @__PURE__ */ new Set();
5274
5437
  const alwaysRenderArr = alwaysRenderIndicesArr || [];
5275
5438
  const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
5439
+ const drawDistance = getEffectiveDrawDistance(ctx);
5276
5440
  const { dataChanged, doMVCP, forceFullItemPositions } = params;
5277
5441
  const bootstrapInitialScrollState = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
5278
5442
  const suppressInitialScrollSideEffects = !!bootstrapInitialScrollState;
@@ -5283,10 +5447,10 @@ function calculateItemsInView(ctx, params = {}) {
5283
5447
  let totalSize = getContentSize(ctx);
5284
5448
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "alignItemsAtEndPadding") + peek$(ctx, "headerSize");
5285
5449
  const numColumns = peek$(ctx, "numColumns");
5286
- const speed = getScrollVelocity(state);
5450
+ const speed = (_b = params.scrollVelocity) != null ? _b : getScrollVelocity(state);
5287
5451
  const scrollExtra = 0;
5288
5452
  const { initialScroll, queuedInitialLayout } = state;
5289
- const scrollState = suppressInitialScrollSideEffects ? (_b = bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.scroll) != null ? _b : state.scroll : !queuedInitialLayout && hasActiveInitialScroll(state) && initialScroll ? (
5453
+ const scrollState = suppressInitialScrollSideEffects ? (_c = bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.scroll) != null ? _c : state.scroll : !queuedInitialLayout && hasActiveInitialScroll(state) && initialScroll ? (
5290
5454
  // Before the initial layout settles, keep viewport math anchored to the
5291
5455
  // current initial-scroll target instead of transient native adjustments.
5292
5456
  resolveInitialScrollOffset(ctx, initialScroll)
@@ -5310,19 +5474,25 @@ function calculateItemsInView(ctx, params = {}) {
5310
5474
  };
5311
5475
  updateScroll2(scrollState);
5312
5476
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
5313
- const currentStickyIdx = stickyHeaderIndicesArr.length > 0 ? findCurrentStickyIndex(stickyHeaderIndicesArr, scroll, state) : -1;
5314
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyHeaderIndicesArr[currentStickyIdx] : -1;
5315
- const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
5316
- if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
5317
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
5318
- }
5319
- const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyHeaderIndicesArr.length > 0 && stickyIndexDidChange;
5320
- const finishCalculateItemsInView = shouldNotifyStickyHeaderChange ? () => {
5321
- const item = data[nextActiveStickyIndex];
5322
- if (item !== void 0) {
5323
- onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
5477
+ const resolveStickyState = () => {
5478
+ const currentStickyIdx = stickyHeaderIndicesArr.length > 0 ? findCurrentStickyIndex(stickyHeaderIndicesArr, scroll, state) : -1;
5479
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyHeaderIndicesArr[currentStickyIdx] : -1;
5480
+ const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
5481
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
5482
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
5324
5483
  }
5325
- } : void 0;
5484
+ const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyHeaderIndicesArr.length > 0 && stickyIndexDidChange;
5485
+ return {
5486
+ currentStickyIdx,
5487
+ finishCalculateItemsInView: shouldNotifyStickyHeaderChange ? () => {
5488
+ const item = data[nextActiveStickyIndex];
5489
+ if (item !== void 0) {
5490
+ onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
5491
+ }
5492
+ } : void 0
5493
+ };
5494
+ };
5495
+ let stickyState = dataChanged ? void 0 : resolveStickyState();
5326
5496
  let scrollBufferTop = drawDistance;
5327
5497
  let scrollBufferBottom = drawDistance;
5328
5498
  if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
@@ -5355,7 +5525,7 @@ function calculateItemsInView(ctx, params = {}) {
5355
5525
  scrollBottom
5356
5526
  );
5357
5527
  }
5358
- finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
5528
+ (_d = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _d.call(stickyState);
5359
5529
  return;
5360
5530
  }
5361
5531
  }
@@ -5364,7 +5534,7 @@ function calculateItemsInView(ctx, params = {}) {
5364
5534
  if (dataChanged) {
5365
5535
  resetLayoutCachesForDataChange(state);
5366
5536
  }
5367
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
5537
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_e = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _e : 0;
5368
5538
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
5369
5539
  updateItemPositions(ctx, dataChanged, {
5370
5540
  doMVCP,
@@ -5390,21 +5560,24 @@ function calculateItemsInView(ctx, params = {}) {
5390
5560
  }
5391
5561
  }
5392
5562
  const scrollBeforeMVCP = state.scroll;
5393
- const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
5563
+ const scrollAdjustPendingBeforeMVCP = (_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0;
5394
5564
  checkMVCP == null ? void 0 : checkMVCP();
5395
- const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0) !== scrollAdjustPendingBeforeMVCP);
5565
+ const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_g = peek$(ctx, "scrollAdjustPending")) != null ? _g : 0) !== scrollAdjustPendingBeforeMVCP);
5396
5566
  if (didMVCPAdjustScroll && initialScroll) {
5397
5567
  updateScroll2(state.scroll);
5398
5568
  updateScrollRange();
5399
5569
  }
5570
+ if (dataChanged) {
5571
+ stickyState = resolveStickyState();
5572
+ }
5400
5573
  let startBuffered = null;
5401
5574
  let startBufferedId = null;
5402
5575
  let endBuffered = null;
5403
- let loopStart = (_f = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _f : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
5576
+ let loopStart = (_h = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _h : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
5404
5577
  for (let i = loopStart; i >= 0; i--) {
5405
- const id = (_g = idCache[i]) != null ? _g : getId(state, i);
5578
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
5406
5579
  const top = positions[i];
5407
- const size = (_h = sizes.get(id)) != null ? _h : getItemSize(ctx, id, i, data[i]);
5580
+ const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
5408
5581
  const bottom = top + size;
5409
5582
  if (bottom > scrollTopBuffered) {
5410
5583
  loopStart = i;
@@ -5439,8 +5612,8 @@ function calculateItemsInView(ctx, params = {}) {
5439
5612
  };
5440
5613
  const dataLength = data.length;
5441
5614
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
5442
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
5443
- const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
5615
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
5616
+ const size = (_l = sizes.get(id)) != null ? _l : getItemSize(ctx, id, i, data[i]);
5444
5617
  const top = positions[i];
5445
5618
  if (!foundEnd) {
5446
5619
  trackVisibleRange(visibleRange, i, top, size, scroll, scrollBottom);
@@ -5496,7 +5669,7 @@ function calculateItemsInView(ctx, params = {}) {
5496
5669
  const needNewContainers = [];
5497
5670
  const needNewContainersSet = /* @__PURE__ */ new Set();
5498
5671
  for (let i = startBuffered; i <= endBuffered; i++) {
5499
- const id = (_k = idCache[i]) != null ? _k : getId(state, i);
5672
+ const id = (_m = idCache[i]) != null ? _m : getId(state, i);
5500
5673
  if (!containerItemKeys.has(id)) {
5501
5674
  needNewContainersSet.add(i);
5502
5675
  needNewContainers.push(i);
@@ -5505,7 +5678,7 @@ function calculateItemsInView(ctx, params = {}) {
5505
5678
  if (alwaysRenderArr.length > 0) {
5506
5679
  for (const index of alwaysRenderArr) {
5507
5680
  if (index < 0 || index >= dataLength) continue;
5508
- const id = (_l = idCache[index]) != null ? _l : getId(state, index);
5681
+ const id = (_n = idCache[index]) != null ? _n : getId(state, index);
5509
5682
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
5510
5683
  needNewContainersSet.add(index);
5511
5684
  needNewContainers.push(index);
@@ -5516,7 +5689,7 @@ function calculateItemsInView(ctx, params = {}) {
5516
5689
  handleStickyActivation(
5517
5690
  ctx,
5518
5691
  stickyHeaderIndicesArr,
5519
- currentStickyIdx,
5692
+ (_o = stickyState == null ? void 0 : stickyState.currentStickyIdx) != null ? _o : -1,
5520
5693
  needNewContainers,
5521
5694
  needNewContainersSet,
5522
5695
  startBuffered,
@@ -5542,7 +5715,7 @@ function calculateItemsInView(ctx, params = {}) {
5542
5715
  for (const allocation of availableContainerAllocations) {
5543
5716
  const i = allocation.itemIndex;
5544
5717
  const containerIndex = allocation.containerIndex;
5545
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
5718
+ const id = (_p = idCache[i]) != null ? _p : getId(state, i);
5546
5719
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
5547
5720
  if (oldKey && oldKey !== id) {
5548
5721
  containerItemKeys.delete(oldKey);
@@ -5553,7 +5726,7 @@ function calculateItemsInView(ctx, params = {}) {
5553
5726
  state.containerItemTypes.set(containerIndex, allocation.itemType);
5554
5727
  }
5555
5728
  containerItemKeys.set(id, containerIndex);
5556
- (_n = state.userScrollAnchorReset) == null ? void 0 : _n.keys.add(id);
5729
+ (_q = state.userScrollAnchorReset) == null ? void 0 : _q.keys.add(id);
5557
5730
  const containerSticky = `containerSticky${containerIndex}`;
5558
5731
  const isSticky = stickyHeaderIndicesSet.has(i);
5559
5732
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -5584,14 +5757,12 @@ function calculateItemsInView(ctx, params = {}) {
5584
5757
  if (state.userScrollAnchorReset) {
5585
5758
  if (state.userScrollAnchorReset.keys.size === 0) {
5586
5759
  state.userScrollAnchorReset = void 0;
5587
- } else {
5588
- state.userScrollAnchorReset.batchSize = state.userScrollAnchorReset.keys.size;
5589
5760
  }
5590
5761
  }
5591
5762
  if (alwaysRenderArr.length > 0) {
5592
5763
  for (const index of alwaysRenderArr) {
5593
5764
  if (index < 0 || index >= dataLength) continue;
5594
- const id = (_o = idCache[index]) != null ? _o : getId(state, index);
5765
+ const id = (_r = idCache[index]) != null ? _r : getId(state, index);
5595
5766
  const containerIndex = containerItemKeys.get(id);
5596
5767
  if (containerIndex !== void 0) {
5597
5768
  state.stickyContainerPool.add(containerIndex);
@@ -5605,7 +5776,7 @@ function calculateItemsInView(ctx, params = {}) {
5605
5776
  stickyHeaderIndicesArr,
5606
5777
  scroll,
5607
5778
  drawDistance,
5608
- currentStickyIdx,
5779
+ (_s = stickyState == null ? void 0 : stickyState.currentStickyIdx) != null ? _s : -1,
5609
5780
  pendingRemoval,
5610
5781
  alwaysRenderSet
5611
5782
  );
@@ -5666,7 +5837,7 @@ function calculateItemsInView(ctx, params = {}) {
5666
5837
  );
5667
5838
  }
5668
5839
  }
5669
- finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
5840
+ (_t = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _t.call(stickyState);
5670
5841
  });
5671
5842
  }
5672
5843
 
@@ -5749,8 +5920,9 @@ function doInitialAllocateContainers(ctx) {
5749
5920
  const state = ctx.state;
5750
5921
  const {
5751
5922
  scrollLength,
5752
- props: { data, drawDistance, getFixedItemSize, getItemType, numColumns, estimatedItemSize }
5923
+ props: { data, getFixedItemSize, getItemType, numColumns, estimatedItemSize }
5753
5924
  } = state;
5925
+ const drawDistance = getEffectiveDrawDistance(ctx);
5754
5926
  const hasContainers = peek$(ctx, "numContainers");
5755
5927
  if (scrollLength > 0 && data.length > 0 && !hasContainers) {
5756
5928
  let averageItemSize;
@@ -5761,12 +5933,12 @@ function doInitialAllocateContainers(ctx) {
5761
5933
  const item = data[i];
5762
5934
  if (item !== void 0) {
5763
5935
  const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
5764
- totalSize += (_b = getFixedItemSize(item, i, itemType)) != null ? _b : estimatedItemSize;
5936
+ totalSize += ((_b = getFixedItemSize(item, i, itemType)) != null ? _b : estimatedItemSize) + ctx.scrollAxisGap;
5765
5937
  }
5766
5938
  }
5767
5939
  averageItemSize = totalSize / num;
5768
5940
  } else {
5769
- averageItemSize = estimatedItemSize;
5941
+ averageItemSize = estimatedItemSize + ctx.scrollAxisGap;
5770
5942
  }
5771
5943
  const numContainers = Math.max(
5772
5944
  1,
@@ -5825,7 +5997,7 @@ function handleLayout(ctx, layoutParam, setCanRender) {
5825
5997
  if (didChange) {
5826
5998
  state.scrollLength = scrollLength;
5827
5999
  state.otherAxisSize = otherAxisSize;
5828
- updateContentMetrics(ctx);
6000
+ updateContentMetricsState(ctx);
5829
6001
  state.lastBatchingAction = Date.now();
5830
6002
  state.scrollForNextCalculateItemsInView = void 0;
5831
6003
  if (scrollLength > 0) {
@@ -6062,28 +6234,12 @@ function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment)
6062
6234
 
6063
6235
  // src/core/updateItemSize.ts
6064
6236
  function runOrScheduleMVCPRecalculate(ctx) {
6065
- var _a3, _b;
6237
+ var _a3;
6066
6238
  const state = ctx.state;
6067
6239
  if (state.userScrollAnchorReset !== void 0) {
6068
- const replacementBatchSize = (_a3 = state.userScrollAnchorReset.batchSize) != null ? _a3 : state.userScrollAnchorReset.keys.size;
6069
- const replacementMeasurementBatchThreshold = 3;
6070
- const shouldBatchReplacementMeasurements = replacementBatchSize > replacementMeasurementBatchThreshold;
6071
- if (shouldBatchReplacementMeasurements) {
6072
- if (state.queuedMVCPRecalculate === void 0) {
6073
- state.queuedMVCPRecalculate = requestAnimationFrame(() => {
6074
- var _a4;
6075
- state.queuedMVCPRecalculate = void 0;
6076
- calculateItemsInView(ctx);
6077
- if (((_a4 = state.userScrollAnchorReset) == null ? void 0 : _a4.keys.size) === 0) {
6078
- state.userScrollAnchorReset = void 0;
6079
- }
6080
- });
6081
- }
6082
- } else {
6083
- calculateItemsInView(ctx);
6084
- if (((_b = state.userScrollAnchorReset) == null ? void 0 : _b.keys.size) === 0) {
6085
- state.userScrollAnchorReset = void 0;
6086
- }
6240
+ calculateItemsInView(ctx);
6241
+ if (((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
6242
+ state.userScrollAnchorReset = void 0;
6087
6243
  }
6088
6244
  } else {
6089
6245
  if (!state.mvcpAnchorLock) {
@@ -6543,6 +6699,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6543
6699
  scrollTo(ctx, params);
6544
6700
  return true;
6545
6701
  }),
6702
+ setItemSize: (itemKey, size) => {
6703
+ updateItemSize(ctx, itemKey, size);
6704
+ },
6546
6705
  setScrollProcessingEnabled: (enabled) => {
6547
6706
  state.scrollProcessingEnabled = enabled;
6548
6707
  },
@@ -6767,7 +6926,7 @@ var LegendList = typedMemo(
6767
6926
  })
6768
6927
  );
6769
6928
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
6770
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
6929
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
6771
6930
  const noopOnScroll = useCallback((_event) => {
6772
6931
  }, []);
6773
6932
  if (props.recycleItems === void 0) {
@@ -6798,6 +6957,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6798
6957
  initialScrollAtEnd = false,
6799
6958
  initialScrollIndex: initialScrollIndexProp,
6800
6959
  initialScrollOffset: initialScrollOffsetProp,
6960
+ experimental_adaptiveRender,
6801
6961
  itemsAreEqual,
6802
6962
  keyExtractor: keyExtractorProp,
6803
6963
  ListEmptyComponent,
@@ -6894,6 +7054,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6894
7054
  const [, scheduleImperativeScrollCommit] = React3.useReducer((value) => value + 1, 0);
6895
7055
  const ctx = useStateContext();
6896
7056
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
7057
+ 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;
7058
+ const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
6897
7059
  const refScroller = useRef(null);
6898
7060
  const combinedRef = useCombinedRef(refScroller, refScrollView);
6899
7061
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
@@ -6907,8 +7069,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6907
7069
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
6908
7070
  alwaysRender == null ? void 0 : alwaysRender.top,
6909
7071
  alwaysRender == null ? void 0 : alwaysRender.bottom,
6910
- (_d = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _d.join(","),
6911
- (_e = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _e.join(","),
7072
+ (_j = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _j.join(","),
7073
+ (_k = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _k.join(","),
6912
7074
  dataProp,
6913
7075
  dataVersion,
6914
7076
  keyExtractor
@@ -6936,6 +7098,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6936
7098
  endNoBuffer: -1,
6937
7099
  endReachedSnapshot: void 0,
6938
7100
  firstFullyOnScreenIndex: -1,
7101
+ hasHadNonEmptyData: dataProp.length > 0,
6939
7102
  idCache: [],
6940
7103
  idsInView: [],
6941
7104
  indexByKey: /* @__PURE__ */ new Map(),
@@ -6978,6 +7141,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6978
7141
  startReachedSnapshotDataChangeEpoch: void 0,
6979
7142
  stickyContainerPool: /* @__PURE__ */ new Set(),
6980
7143
  stickyContainers: /* @__PURE__ */ new Map(),
7144
+ timeoutAdaptiveRender: void 0,
6981
7145
  timeouts: /* @__PURE__ */ new Set(),
6982
7146
  totalSize: 0,
6983
7147
  viewabilityConfigCallbackPairs: void 0
@@ -6996,11 +7160,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6996
7160
  const state = refState.current;
6997
7161
  const isFirstLocal = state.isFirst;
6998
7162
  const previousNumColumnsProp = state.props.numColumns;
6999
- state.didColumnsChange = numColumnsProp !== previousNumColumnsProp;
7163
+ const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
7164
+ ctx.scrollAxisGap = nextScrollAxisGap;
7165
+ state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
7000
7166
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
7001
7167
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
7002
7168
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
7003
- if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
7169
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_l = state.initialScroll) == null ? void 0 : _l.viewPosition) === 1 && state.props.data.length > 0) {
7004
7170
  clearPreservedInitialScrollTarget(state);
7005
7171
  }
7006
7172
  if (didDataChangeLocal) {
@@ -7012,8 +7178,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7012
7178
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
7013
7179
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? throttledOnScroll : onScrollProp;
7014
7180
  const anchoredEndSpaceResolved = anchoredEndSpace ? { ...anchoredEndSpace, includeInEndInset: true } : anchoredEndSpace;
7015
- const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_g = state.props.anchoredEndSpace) == null ? void 0 : _g.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
7181
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_m = state.props.anchoredEndSpace) == null ? void 0 : _m.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
7016
7182
  state.props = {
7183
+ adaptiveRender: experimental_adaptiveRender,
7017
7184
  alignItemsAtEnd,
7018
7185
  alignItemsAtEndPaddingEnabled: useAlignItemsAtEndPadding,
7019
7186
  alwaysRender,
@@ -7021,6 +7188,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7021
7188
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
7022
7189
  anchoredEndSpace: anchoredEndSpaceResolved,
7023
7190
  animatedProps: animatedPropsInternal,
7191
+ contentContainerAlignItems: contentContainerStyle.alignItems,
7024
7192
  contentInset,
7025
7193
  contentInsetEndAdjustment: contentInsetEndAdjustmentResolved,
7026
7194
  data: dataProp,
@@ -7073,7 +7241,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7073
7241
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
7074
7242
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
7075
7243
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
7076
- updateContentMetrics(ctx);
7244
+ updateContentMetricsState(ctx);
7077
7245
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
7078
7246
  if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") ;
7079
7247
  };
@@ -7105,7 +7273,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7105
7273
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7106
7274
  });
7107
7275
  }, []);
7108
- if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
7276
+ if (isFirstLocal || didDataChangeLocal || state.didColumnsChange) {
7109
7277
  refState.current.lastBatchingAction = Date.now();
7110
7278
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
7111
7279
  refState.current.sizes.clear();
@@ -7122,6 +7290,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7122
7290
  dataLength: dataProp.length,
7123
7291
  didDataChange: didDataChangeLocal,
7124
7292
  initialScrollAtEnd,
7293
+ latestInitialScroll: initialScrollProp,
7294
+ latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
7125
7295
  stylePaddingBottom: stylePaddingBottomState,
7126
7296
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7127
7297
  });
@@ -7196,6 +7366,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7196
7366
  dataVersion,
7197
7367
  memoizedLastItemKeys.join(","),
7198
7368
  numColumnsProp,
7369
+ nextScrollAxisGap,
7199
7370
  stylePaddingBottomState,
7200
7371
  stylePaddingTopState,
7201
7372
  useAlignItemsAtEndPadding
@@ -7218,7 +7389,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7218
7389
  state.didColumnsChange = false;
7219
7390
  state.didDataChange = false;
7220
7391
  state.isFirst = false;
7221
- }, [dataProp, dataVersion, numColumnsProp]);
7392
+ }, [dataProp, dataVersion, numColumnsProp, nextScrollAxisGap]);
7222
7393
  useLayoutEffect(() => {
7223
7394
  var _a4;
7224
7395
  set$(ctx, "extraData", extraData);
@@ -7266,6 +7437,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7266
7437
  useInit(() => {
7267
7438
  });
7268
7439
  useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
7440
+ useEffect(() => {
7441
+ return () => {
7442
+ for (const timeout of state.timeouts) {
7443
+ clearTimeout(timeout);
7444
+ }
7445
+ state.timeouts.clear();
7446
+ };
7447
+ }, [state]);
7269
7448
  useLayoutEffect(() => {
7270
7449
  var _a4;
7271
7450
  (_a4 = state.runPendingScrollToEnd) == null ? void 0 : _a4.call(state);
@@ -7313,7 +7492,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7313
7492
  onScroll: onScrollHandler,
7314
7493
  recycleItems,
7315
7494
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControlElement, {
7316
- progressViewOffset: ((_h = refreshControlElement.props.progressViewOffset) != null ? _h : 0) + stylePaddingTopState
7495
+ progressViewOffset: ((_n = refreshControlElement.props.progressViewOffset) != null ? _n : 0) + stylePaddingTopState
7317
7496
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React3.createElement(
7318
7497
  RefreshControl,
7319
7498
  {
@@ -7324,7 +7503,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7324
7503
  ),
7325
7504
  refScrollView: combinedRef,
7326
7505
  renderScrollComponent,
7327
- scrollAdjustHandler: (_i = refState.current) == null ? void 0 : _i.scrollAdjustHandler,
7506
+ scrollAdjustHandler: (_o = refState.current) == null ? void 0 : _o.scrollAdjustHandler,
7328
7507
  scrollEventThrottle: 0,
7329
7508
  snapToIndices,
7330
7509
  stickyHeaderIndices,
@@ -7380,4 +7559,4 @@ var internal = {
7380
7559
  var LegendList3 = LegendListRuntime;
7381
7560
  var internal2 = internal;
7382
7561
 
7383
- export { LegendList3 as LegendList, internal2 as internal, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
7562
+ export { LegendList3 as LegendList, internal2 as internal, useAdaptiveRender, useAdaptiveRenderChange, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };