@legendapp/list 3.0.0-beta.52 → 3.0.0-beta.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -166,7 +166,10 @@ function useSelector$(signalName, selector) {
166
166
  }
167
167
 
168
168
  // src/state/getContentInsetEnd.ts
169
- function getContentInsetEnd(ctx) {
169
+ function getContentInsetEndAdjustmentEnd(adjustment) {
170
+ return Math.max(0, adjustment != null ? adjustment : 0);
171
+ }
172
+ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
170
173
  var _a3, _b;
171
174
  const state = ctx.state;
172
175
  const { props } = state;
@@ -174,14 +177,21 @@ function getContentInsetEnd(ctx) {
174
177
  const contentInset = props.contentInset;
175
178
  const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
176
179
  const baseEndInset = (horizontal ? baseInset == null ? void 0 : baseInset.right : baseInset == null ? void 0 : baseInset.bottom) || 0;
180
+ const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd(
181
+ contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
182
+ );
177
183
  const anchoredEndSpaceSize = peek$(ctx, "anchoredEndSpaceSize");
178
184
  const anchoredEndInset = ((_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
179
185
  const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
186
+ const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
180
187
  if (overrideInset) {
181
188
  const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
182
- return Math.max((horizontal ? mergedInset.right : mergedInset.bottom) || 0, anchoredEndInset);
189
+ return Math.max(
190
+ ((horizontal ? mergedInset.right : mergedInset.bottom) || 0) + contentInsetEndAdjustment,
191
+ anchoredEndInset
192
+ );
183
193
  }
184
- return Math.max(baseEndInset, anchoredEndInset);
194
+ return Math.max(adjustedBaseEndInset, anchoredEndInset);
185
195
  }
186
196
 
187
197
  // src/state/getContentSize.ts
@@ -679,8 +689,52 @@ function isInMVCPActiveMode(state) {
679
689
  }
680
690
 
681
691
  // src/components/Container.tsx
692
+ function getContainerPositionStyle({
693
+ columnWrapperStyle,
694
+ horizontal,
695
+ hasItemSeparator,
696
+ numColumns,
697
+ otherAxisPos,
698
+ otherAxisSize
699
+ }) {
700
+ let paddingStyles;
701
+ if (columnWrapperStyle) {
702
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
703
+ if (horizontal) {
704
+ paddingStyles = {
705
+ paddingBottom: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0,
706
+ paddingRight: columnGap || gap || void 0,
707
+ paddingTop: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
708
+ };
709
+ } else {
710
+ paddingStyles = {
711
+ paddingBottom: rowGap || gap || void 0,
712
+ paddingLeft: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0,
713
+ paddingRight: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
714
+ };
715
+ }
716
+ }
717
+ return horizontal ? {
718
+ boxSizing: paddingStyles ? "border-box" : void 0,
719
+ flexDirection: hasItemSeparator ? "row" : void 0,
720
+ height: otherAxisSize,
721
+ left: 0,
722
+ position: "absolute",
723
+ top: otherAxisPos,
724
+ ...paddingStyles || {}
725
+ } : {
726
+ boxSizing: paddingStyles ? "border-box" : void 0,
727
+ left: otherAxisPos,
728
+ position: "absolute",
729
+ right: numColumns > 1 ? null : 0,
730
+ top: 0,
731
+ width: otherAxisSize,
732
+ ...paddingStyles || {}
733
+ };
734
+ }
682
735
  var Container = typedMemo(function Container2({
683
736
  id,
737
+ itemKey,
684
738
  recycleItems,
685
739
  horizontal,
686
740
  getRenderedItem: getRenderedItem2,
@@ -692,11 +746,10 @@ var Container = typedMemo(function Container2({
692
746
  const { columnWrapperStyle, animatedScrollY } = ctx;
693
747
  const positionComponentInternal = ctx.state.props.positionComponentInternal;
694
748
  const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
695
- const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
749
+ const [column = 0, span = 1, data, numColumns = 1, extraData, isSticky] = useArr$([
696
750
  `containerColumn${id}`,
697
751
  `containerSpan${id}`,
698
752
  `containerItemData${id}`,
699
- `containerItemKey${id}`,
700
753
  "numColumns",
701
754
  "extraData",
702
755
  `containerSticky${id}`
@@ -717,42 +770,17 @@ var Container = typedMemo(function Container2({
717
770
  const resolvedSpan = Math.min(Math.max(span || 1, 1), numColumns);
718
771
  const otherAxisPos = numColumns > 1 ? `${(resolvedColumn - 1) / numColumns * 100}%` : 0;
719
772
  const otherAxisSize = numColumns > 1 ? `${resolvedSpan / numColumns * 100}%` : void 0;
720
- const style = React3.useMemo(() => {
721
- let paddingStyles;
722
- if (columnWrapperStyle) {
723
- const { columnGap, rowGap, gap } = columnWrapperStyle;
724
- if (horizontal) {
725
- paddingStyles = {
726
- paddingBottom: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0,
727
- paddingRight: columnGap || gap || void 0,
728
- paddingTop: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
729
- };
730
- } else {
731
- paddingStyles = {
732
- paddingBottom: rowGap || gap || void 0,
733
- paddingLeft: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0,
734
- paddingRight: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
735
- };
736
- }
737
- }
738
- return horizontal ? {
739
- boxSizing: paddingStyles ? "border-box" : void 0,
740
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
741
- height: otherAxisSize,
742
- left: 0,
743
- position: "absolute",
744
- top: otherAxisPos,
745
- ...paddingStyles || {}
746
- } : {
747
- boxSizing: paddingStyles ? "border-box" : void 0,
748
- left: otherAxisPos,
749
- position: "absolute",
750
- right: numColumns > 1 ? null : 0,
751
- top: 0,
752
- width: otherAxisSize,
753
- ...paddingStyles || {}
754
- };
755
- }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
773
+ const style = React3.useMemo(
774
+ () => getContainerPositionStyle({
775
+ columnWrapperStyle,
776
+ hasItemSeparator: !!ItemSeparatorComponent,
777
+ horizontal,
778
+ numColumns,
779
+ otherAxisPos,
780
+ otherAxisSize
781
+ }),
782
+ [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns, ItemSeparatorComponent]
783
+ );
756
784
  const renderedItemInfo = React3.useMemo(
757
785
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
758
786
  [itemKey, data, extraData]
@@ -839,6 +867,39 @@ var Container = typedMemo(function Container2({
839
867
  );
840
868
  });
841
869
 
870
+ // src/components/ContainerSlot.tsx
871
+ function ContainerSlotBase({
872
+ id,
873
+ horizontal,
874
+ recycleItems,
875
+ ItemSeparatorComponent,
876
+ updateItemSize: updateItemSize2,
877
+ getRenderedItem: getRenderedItem2,
878
+ stickyHeaderConfig,
879
+ ContainerComponent = Container
880
+ }) {
881
+ const [itemKey] = useArr$([`containerItemKey${id}`]);
882
+ if (itemKey === void 0) {
883
+ return null;
884
+ }
885
+ return /* @__PURE__ */ React3__namespace.createElement(
886
+ ContainerComponent,
887
+ {
888
+ getRenderedItem: getRenderedItem2,
889
+ horizontal,
890
+ ItemSeparatorComponent,
891
+ id,
892
+ itemKey,
893
+ recycleItems,
894
+ stickyHeaderConfig,
895
+ updateItemSize: updateItemSize2
896
+ }
897
+ );
898
+ }
899
+ var ContainerSlot = typedMemo(function ContainerSlot2(props) {
900
+ return /* @__PURE__ */ React3__namespace.createElement(ContainerSlotBase, { ...props });
901
+ });
902
+
842
903
  // src/utils/reordering.ts
843
904
  var mapFn = (element) => {
844
905
  const indexStr = element.getAttribute("data-index");
@@ -958,9 +1019,12 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
958
1019
  const ref = React3.useRef(null);
959
1020
  const ctx = useStateContext();
960
1021
  const columnWrapperStyle = ctx.columnWrapperStyle;
961
- const [otherAxisSize, totalSize] = useArr$(["otherAxisSize", "totalSize"]);
1022
+ const [otherAxisSize, readyToRender, totalSize] = useArr$(["otherAxisSize", "readyToRender", "totalSize"]);
962
1023
  useDOMOrder(ref);
963
- const style = horizontal ? { minHeight: otherAxisSize, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, position: "relative" };
1024
+ const style = horizontal ? { minHeight: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative" };
1025
+ if (!readyToRender) {
1026
+ style.pointerEvents = "none";
1027
+ }
964
1028
  if (columnWrapperStyle && numColumns > 1) {
965
1029
  const { columnGap, rowGap, gap } = columnWrapperStyle;
966
1030
  const gapX = columnGap || gap || 0;
@@ -988,12 +1052,12 @@ var Containers = typedMemo(function Containers2({
988
1052
  getRenderedItem: getRenderedItem2,
989
1053
  stickyHeaderConfig
990
1054
  }) {
991
- const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
1055
+ const [numContainersPooled, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
992
1056
  const containers = [];
993
- for (let i = 0; i < numContainers; i++) {
1057
+ for (let i = 0; i < numContainersPooled; i++) {
994
1058
  containers.push(
995
1059
  /* @__PURE__ */ React3__namespace.createElement(
996
- Container,
1060
+ ContainerSlot,
997
1061
  {
998
1062
  getRenderedItem: getRenderedItem2,
999
1063
  horizontal,
@@ -1063,6 +1127,11 @@ function useRafCoalescer(callback) {
1063
1127
  return coalescer;
1064
1128
  }
1065
1129
 
1130
+ // src/components/webConstants.ts
1131
+ var LEGEND_LIST_CONTENT_CONTAINER_CLASS = "legend-list-content-container";
1132
+ var LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS = "legend-list-scrollbar-x-hidden";
1133
+ var LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS = "legend-list-scrollbar-y-hidden";
1134
+
1066
1135
  // src/components/webScrollUtils.ts
1067
1136
  function getDocumentScrollerNode() {
1068
1137
  if (typeof document === "undefined") {
@@ -1147,6 +1216,22 @@ function resolveWindowScrollTarget({ clampedOffset, horizontal, listPos, scroll
1147
1216
  }
1148
1217
 
1149
1218
  // src/components/ListComponentScrollView.tsx
1219
+ var SCROLLBAR_HIDDEN_STYLE_ID = "legend-list-scrollbar-axis-hidden-style";
1220
+ var SCROLLBAR_HIDDEN_STYLE = `.${LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS}::-webkit-scrollbar:vertical{width:0;display:none;}.${LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS}::-webkit-scrollbar:horizontal{height:0;display:none;}`;
1221
+ function ensureScrollbarHiddenStyle() {
1222
+ if (typeof document === "undefined" || document.getElementById(SCROLLBAR_HIDDEN_STYLE_ID)) {
1223
+ return;
1224
+ }
1225
+ const styleElement = document.createElement("style");
1226
+ styleElement.id = SCROLLBAR_HIDDEN_STYLE_ID;
1227
+ styleElement.textContent = SCROLLBAR_HIDDEN_STYLE;
1228
+ document.head.appendChild(styleElement);
1229
+ }
1230
+ function getContentInsetEndAdjustmentEnd2(ctx) {
1231
+ var _a3, _b;
1232
+ const adjustment = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.contentInsetEndAdjustment;
1233
+ return Math.max(0, adjustment != null ? adjustment : 0);
1234
+ }
1150
1235
  var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView2({
1151
1236
  children,
1152
1237
  style,
@@ -1164,7 +1249,9 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1164
1249
  onLayout,
1165
1250
  ...props
1166
1251
  }, ref) {
1252
+ var _a3, _b, _c;
1167
1253
  const ctx = useStateContext();
1254
+ const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
1168
1255
  const scrollRef = React3.useRef(null);
1169
1256
  const contentRef = React3.useRef(null);
1170
1257
  const isWindowScroll = useWindowScroll;
@@ -1226,10 +1313,9 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1226
1313
  React3.useImperativeHandle(ref, () => {
1227
1314
  const api = {
1228
1315
  getBoundingClientRect: () => {
1229
- var _a3;
1230
- return (_a3 = scrollRef.current) == null ? void 0 : _a3.getBoundingClientRect();
1316
+ var _a4;
1317
+ return (_a4 = scrollRef.current) == null ? void 0 : _a4.getBoundingClientRect();
1231
1318
  },
1232
- getContentNode: () => contentRef.current,
1233
1319
  getCurrentScrollOffset,
1234
1320
  getScrollableNode: () => resolveScrollableNode(scrollRef.current, isWindowScroll),
1235
1321
  getScrollEventTarget: () => getScrollTarget(),
@@ -1345,6 +1431,12 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1345
1431
  }
1346
1432
  };
1347
1433
  }, [isWindowScroll, onLayout]);
1434
+ const hiddenScrollIndicatorClassName = !isWindowScroll && (horizontal ? !showsHorizontalScrollIndicator && LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS : !showsVerticalScrollIndicator && LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS);
1435
+ React3.useLayoutEffect(() => {
1436
+ if (hiddenScrollIndicatorClassName) {
1437
+ ensureScrollbarHiddenStyle();
1438
+ }
1439
+ }, [hiddenScrollIndicatorClassName]);
1348
1440
  const scrollViewStyle = {
1349
1441
  ...isWindowScroll ? {} : {
1350
1442
  overflow: "auto",
@@ -1355,6 +1447,10 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1355
1447
  },
1356
1448
  ...StyleSheet.flatten(style)
1357
1449
  };
1450
+ const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd2(ctx);
1451
+ 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;
1452
+ const renderedContentInsetEndAdjustment = Math.max(0, contentInsetEndAdjustment - anchoredEndInset);
1453
+ const contentInsetEndAdjustmentSpacerStyle = renderedContentInsetEndAdjustment ? horizontal ? { flexShrink: 0, width: renderedContentInsetEndAdjustment } : { height: renderedContentInsetEndAdjustment } : void 0;
1358
1454
  const contentStyle = {
1359
1455
  display: horizontal ? "flex" : "block",
1360
1456
  flexDirection: horizontal ? "row" : void 0,
@@ -1362,15 +1458,38 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1362
1458
  minWidth: horizontal ? "100%" : void 0,
1363
1459
  ...StyleSheet.flatten(contentContainerStyle)
1364
1460
  };
1461
+ const className = contentContainerClassName ? `${LEGEND_LIST_CONTENT_CONTAINER_CLASS} ${contentContainerClassName}` : LEGEND_LIST_CONTENT_CONTAINER_CLASS;
1365
1462
  const {
1366
1463
  contentContainerClassName: _contentContainerClassName,
1367
1464
  contentInset: _contentInset,
1368
1465
  scrollEventThrottle: _scrollEventThrottle,
1369
1466
  ScrollComponent: _ScrollComponent,
1370
1467
  useWindowScroll: _useWindowScroll,
1468
+ className: scrollViewClassNameProp,
1371
1469
  ...webProps
1372
1470
  } = props;
1373
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3__namespace.createElement("div", { className: contentContainerClassName, ref: contentRef, style: contentStyle }, children));
1471
+ const scrollViewClassName = hiddenScrollIndicatorClassName ? scrollViewClassNameProp ? `${scrollViewClassNameProp} ${hiddenScrollIndicatorClassName}` : hiddenScrollIndicatorClassName : scrollViewClassNameProp;
1472
+ if (IS_DEV) {
1473
+ if (/(?:^|\s)(?:[a-z0-9_-]+:)*gap(?:-[xy])?-(?:\[[^\]]+\]|[^\s]+)/.test(
1474
+ `${contentContainerClassName != null ? contentContainerClassName : ""} ${scrollViewClassNameProp != null ? scrollViewClassNameProp : ""}`
1475
+ )) {
1476
+ warnDevOnce(
1477
+ "className-gap",
1478
+ "className/contentContainerClassName gap classes are not supported in LegendList because it needs to use exact values internally. Use contentContainerStyle={{ gap: ... }} or columnWrapperStyle instead."
1479
+ );
1480
+ }
1481
+ }
1482
+ return /* @__PURE__ */ React3__namespace.createElement(
1483
+ "div",
1484
+ {
1485
+ className: scrollViewClassName,
1486
+ ref: scrollRef,
1487
+ ...webProps,
1488
+ style: scrollViewStyle
1489
+ },
1490
+ refreshControl,
1491
+ /* @__PURE__ */ React3__namespace.createElement("div", { className, ref: contentRef, style: contentStyle }, children, contentInsetEndAdjustmentSpacerStyle ? /* @__PURE__ */ React3__namespace.createElement("div", { "aria-hidden": true, style: contentInsetEndAdjustmentSpacerStyle }) : null)
1492
+ );
1374
1493
  });
1375
1494
  function useValueListener$(key, callback) {
1376
1495
  const ctx = useStateContext();
@@ -1398,48 +1517,63 @@ function getScrollAdjustAxis(horizontal) {
1398
1517
  y: 1
1399
1518
  };
1400
1519
  }
1520
+ function getScrollAdjustTarget(ctx, contentNode) {
1521
+ var _a3, _b, _c;
1522
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1523
+ const scrollElement = (_c = (_b = scrollView == null ? void 0 : scrollView.getScrollableNode) == null ? void 0 : _b.call(scrollView)) != null ? _c : null;
1524
+ let resolvedContentNode = null;
1525
+ if (scrollElement) {
1526
+ resolvedContentNode = (contentNode == null ? void 0 : contentNode.isConnected) && contentNode.parentElement === scrollElement ? contentNode : scrollElement.querySelector(`:scope > .${LEGEND_LIST_CONTENT_CONTAINER_CLASS}`);
1527
+ }
1528
+ return scrollElement ? { contentNode: resolvedContentNode, scrollElement } : null;
1529
+ }
1530
+ function scrollAdjustBy(el, left, top) {
1531
+ el.scrollBy({ behavior: "auto", left, top });
1532
+ }
1401
1533
  function ScrollAdjust() {
1402
1534
  const ctx = useStateContext();
1403
1535
  const lastScrollOffsetRef = React3__namespace.useRef(0);
1404
1536
  const resetPaddingRafRef = React3__namespace.useRef(void 0);
1405
1537
  const resetPaddingBaselineRef = React3__namespace.useRef(void 0);
1538
+ const contentNodeRef = React3__namespace.useRef(null);
1406
1539
  const callback = React3__namespace.useCallback(() => {
1407
- var _a3, _b;
1540
+ var _a3;
1408
1541
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1409
1542
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1410
1543
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1411
- const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1412
- if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1413
- const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1414
- if (scrollDelta !== 0) {
1415
- const axis = getScrollAdjustAxis(!!ctx.state.props.horizontal);
1416
- const contentNode = scrollView.getContentNode();
1417
- const prevScroll = scrollView.getCurrentScrollOffset();
1418
- const el = scrollView.getScrollableNode();
1419
- const scrollBy = () => scrollView.scrollBy(axis.x * scrollDelta, axis.y * scrollDelta);
1420
- if (!contentNode) {
1421
- scrollBy();
1422
- lastScrollOffsetRef.current = scrollOffset;
1423
- return;
1424
- }
1425
- const totalSize = contentNode[axis.contentSizeKey];
1426
- const viewportSize = el[axis.viewportSizeKey];
1427
- const nextScroll = prevScroll + scrollDelta;
1428
- if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize) {
1429
- const previousPaddingEnd = (_b = resetPaddingBaselineRef.current) != null ? _b : contentNode.style[axis.paddingEndProp];
1430
- resetPaddingBaselineRef.current = previousPaddingEnd;
1431
- const pad = (nextScroll + viewportSize - totalSize) * 2;
1432
- contentNode.style[axis.paddingEndProp] = `${pad}px`;
1433
- void contentNode.offsetHeight;
1434
- scrollBy();
1435
- if (resetPaddingRafRef.current !== void 0) {
1436
- cancelAnimationFrame(resetPaddingRafRef.current);
1544
+ const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1545
+ if (scrollDelta !== 0) {
1546
+ const target = getScrollAdjustTarget(ctx, contentNodeRef.current);
1547
+ if (target) {
1548
+ const horizontal = !!ctx.state.props.horizontal;
1549
+ const axis = getScrollAdjustAxis(horizontal);
1550
+ const { contentNode, scrollElement: el } = target;
1551
+ const scrollBy = () => scrollAdjustBy(el, axis.x * scrollDelta, axis.y * scrollDelta);
1552
+ contentNodeRef.current = contentNode;
1553
+ if (contentNode) {
1554
+ const prevScroll = horizontal ? el.scrollLeft : el.scrollTop;
1555
+ const totalSize = contentNode[axis.contentSizeKey];
1556
+ const viewportSize = el[axis.viewportSizeKey];
1557
+ const nextScroll = prevScroll + scrollDelta;
1558
+ const needsTemporaryPadding = scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize;
1559
+ if (needsTemporaryPadding) {
1560
+ const previousPaddingEnd = (_a3 = resetPaddingBaselineRef.current) != null ? _a3 : contentNode.style[axis.paddingEndProp];
1561
+ resetPaddingBaselineRef.current = previousPaddingEnd;
1562
+ const pad = (nextScroll + viewportSize - totalSize) * 2;
1563
+ contentNode.style[axis.paddingEndProp] = `${pad}px`;
1564
+ void contentNode.offsetHeight;
1565
+ scrollBy();
1566
+ if (resetPaddingRafRef.current !== void 0) {
1567
+ cancelAnimationFrame(resetPaddingRafRef.current);
1568
+ }
1569
+ resetPaddingRafRef.current = requestAnimationFrame(() => {
1570
+ resetPaddingRafRef.current = void 0;
1571
+ resetPaddingBaselineRef.current = void 0;
1572
+ contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1573
+ });
1574
+ } else {
1575
+ scrollBy();
1437
1576
  }
1438
- resetPaddingRafRef.current = requestAnimationFrame(() => {
1439
- resetPaddingRafRef.current = void 0;
1440
- resetPaddingBaselineRef.current = void 0;
1441
- contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1442
- });
1443
1577
  } else {
1444
1578
  scrollBy();
1445
1579
  }
@@ -1750,10 +1884,9 @@ var initialScrollWatchdog = {
1750
1884
  clear(state) {
1751
1885
  initialScrollWatchdog.set(state, void 0);
1752
1886
  },
1753
- didObserveProgress(newScroll, watchdog) {
1754
- const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
1887
+ didReachTarget(newScroll, watchdog) {
1755
1888
  const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
1756
- return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET || nextDistance + INITIAL_SCROLL_MIN_TARGET_OFFSET < previousDistance;
1889
+ return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET;
1757
1890
  },
1758
1891
  get(state) {
1759
1892
  var _a3, _b;
@@ -1778,19 +1911,19 @@ var initialScrollWatchdog = {
1778
1911
  }
1779
1912
  };
1780
1913
  function setInitialScrollSession(state, options = {}) {
1781
- var _a3, _b, _c;
1914
+ var _a3, _b, _c, _d;
1782
1915
  const existingSession = state.initialScrollSession;
1783
1916
  const kind = (_a3 = options.kind) != null ? _a3 : existingSession == null ? void 0 : existingSession.kind;
1784
1917
  const completion = existingSession == null ? void 0 : existingSession.completion;
1785
- const hasBootstrapOverride = Object.hasOwn(options, "bootstrap");
1786
- const bootstrap = kind === "bootstrap" ? hasBootstrapOverride ? options.bootstrap : (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0 : void 0;
1918
+ const existingBootstrap = (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0;
1919
+ const bootstrap = kind === "bootstrap" ? options.bootstrap === null ? void 0 : (_b = options.bootstrap) != null ? _b : existingBootstrap : void 0;
1787
1920
  if (!kind) {
1788
1921
  return clearInitialScrollSession(state);
1789
1922
  }
1790
1923
  if (!state.initialScroll && !bootstrap && !hasInitialScrollSessionCompletion(completion)) {
1791
1924
  return clearInitialScrollSession(state);
1792
1925
  }
1793
- const previousDataLength = (_c = (_b = options.previousDataLength) != null ? _b : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _c : 0;
1926
+ const previousDataLength = (_d = (_c = options.previousDataLength) != null ? _c : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _d : 0;
1794
1927
  state.initialScrollSession = createInitialScrollSession({
1795
1928
  bootstrap,
1796
1929
  completion,
@@ -2542,7 +2675,7 @@ function advanceMeasuredInitialScroll(ctx, options) {
2542
2675
  const activeInitialTargetOffset = scrollingTo ? (_a3 = scrollingTo.targetOffset) != null ? _a3 : scrollingTo.offset : void 0;
2543
2676
  const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - resolvedOffset) > 1;
2544
2677
  const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - resolvedOffset) > 1;
2545
- const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - activeInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - activeInitialTargetOffset) <= 1;
2678
+ const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - resolvedOffset) <= 1 && Math.abs(state.scrollPending - resolvedOffset) <= 1;
2546
2679
  if (!(options == null ? void 0 : options.forceScroll) && !didOffsetChange && isInitialScrollInProgress && !didActiveInitialTargetChange) {
2547
2680
  return false;
2548
2681
  }
@@ -2614,6 +2747,30 @@ function checkAllSizesKnown(state, indices) {
2614
2747
  });
2615
2748
  }
2616
2749
 
2750
+ // src/utils/requestAdjust.ts
2751
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2752
+ const state = ctx.state;
2753
+ if (Math.abs(positionDiff) > 0.1) {
2754
+ const doit = () => {
2755
+ {
2756
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
2757
+ if (state.adjustingFromInitialMount) {
2758
+ state.adjustingFromInitialMount--;
2759
+ }
2760
+ }
2761
+ };
2762
+ state.scroll += positionDiff;
2763
+ state.scrollForNextCalculateItemsInView = void 0;
2764
+ const readyToRender = peek$(ctx, "readyToRender");
2765
+ if (readyToRender) {
2766
+ doit();
2767
+ } else {
2768
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2769
+ requestAnimationFrame(doit);
2770
+ }
2771
+ }
2772
+ }
2773
+
2617
2774
  // src/core/bootstrapInitialScroll.ts
2618
2775
  var DEFAULT_BOOTSTRAP_REVEAL_EPSILON = 1;
2619
2776
  var DEFAULT_BOOTSTRAP_REVEAL_MAX_FRAMES = 8;
@@ -2707,7 +2864,7 @@ function clearBootstrapInitialScrollSession(state) {
2707
2864
  bootstrapInitialScroll.frameHandle = void 0;
2708
2865
  }
2709
2866
  setInitialScrollSession(state, {
2710
- bootstrap: void 0,
2867
+ bootstrap: null,
2711
2868
  kind: (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind
2712
2869
  });
2713
2870
  }
@@ -2863,15 +3020,18 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2863
3020
  return;
2864
3021
  }
2865
3022
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2866
- if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2867
- clearPendingInitialScrollFooterLayout(ctx, {
2868
- dataLength: state.props.data.length,
2869
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2870
- target: initialScroll
2871
- });
2872
- return;
3023
+ const shouldKeepEndTargetAlive = isRetargetableBottomAlignedInitialScrollTarget(initialScroll) && peek$(ctx, "isAtEnd");
3024
+ if (!shouldKeepEndTargetAlive) {
3025
+ if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
3026
+ clearPendingInitialScrollFooterLayout(ctx, {
3027
+ dataLength: state.props.data.length,
3028
+ stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
3029
+ target: initialScroll
3030
+ });
3031
+ } else {
3032
+ clearFinishedViewportRetargetableInitialScroll(state);
3033
+ }
2873
3034
  }
2874
- clearFinishedViewportRetargetableInitialScroll(state);
2875
3035
  }
2876
3036
  }
2877
3037
  function startBootstrapInitialScrollOnMount(ctx, options) {
@@ -2910,7 +3070,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2910
3070
  }
2911
3071
  const shouldResetDidFinish = !!(state.didFinishInitialScroll && previousDataLength === 0 && dataLength > 0 && initialScroll.index !== void 0);
2912
3072
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2913
- const shouldClearFinishedResizePreservation = didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
3073
+ const shouldClearFinishedResizePreservation = !initialScrollAtEnd && didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
2914
3074
  if (shouldClearFinishedResizePreservation) {
2915
3075
  clearPreservedInitialScrollTarget(state);
2916
3076
  return;
@@ -3013,27 +3173,46 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
3013
3173
  }
3014
3174
  }
3015
3175
  function handleBootstrapInitialScrollLayoutChange(ctx) {
3176
+ var _a3, _b, _c, _d;
3016
3177
  const state = ctx.state;
3017
3178
  const initialScroll = state.initialScroll;
3018
- if (isOffsetInitialScrollSession(state) || state.props.data.length === 0 || !initialScroll) {
3019
- return;
3020
- }
3021
3179
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
3022
- if (!bootstrapInitialScroll && initialScroll.viewPosition !== 1) {
3023
- return;
3024
- }
3025
- const didFinishInitialScroll = state.didFinishInitialScroll;
3026
- if (didFinishInitialScroll) {
3027
- setInitialScrollTarget(state, initialScroll, {
3028
- resetDidFinish: true
3029
- });
3030
- state.clearPreservedInitialScrollOnNextFinish = true;
3180
+ if (initialScroll && state.props.data.length > 0 && !isOffsetInitialScrollSession(state) && (bootstrapInitialScroll || initialScroll.viewPosition === 1)) {
3181
+ const resolvedOffset = resolveInitialScrollOffset(ctx, initialScroll);
3182
+ const scrollingTo = ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) ? state.scrollingTo : void 0;
3183
+ if (!bootstrapInitialScroll && (scrollingTo || state.didFinishInitialScroll)) {
3184
+ const currentOffset = scrollingTo ? (_b = scrollingTo.targetOffset) != null ? _b : scrollingTo.offset : getObservedBootstrapInitialScrollOffset(state);
3185
+ const offsetDiff = resolvedOffset - currentOffset;
3186
+ if (Math.abs(offsetDiff) > DEFAULT_BOOTSTRAP_REVEAL_EPSILON) {
3187
+ if (scrollingTo) {
3188
+ const existingWatchdog = initialScrollWatchdog.get(state);
3189
+ scrollingTo.offset = resolvedOffset;
3190
+ scrollingTo.targetOffset = resolvedOffset;
3191
+ state.initialScroll = {
3192
+ ...initialScroll,
3193
+ contentOffset: resolvedOffset
3194
+ };
3195
+ state.hasScrolled = false;
3196
+ initialScrollWatchdog.set(state, {
3197
+ startScroll: (_c = existingWatchdog == null ? void 0 : existingWatchdog.startScroll) != null ? _c : state.scroll,
3198
+ targetOffset: resolvedOffset
3199
+ });
3200
+ }
3201
+ requestAdjust(ctx, offsetDiff);
3202
+ if (state.didFinishInitialScroll) {
3203
+ (_d = state.triggerCalculateItemsInView) == null ? void 0 : _d.call(state, { forceFullItemPositions: true });
3204
+ }
3205
+ }
3206
+ if (state.didFinishInitialScroll) {
3207
+ clearFinishedViewportRetargetableInitialScroll(state);
3208
+ }
3209
+ } else {
3210
+ rearmBootstrapInitialScroll(ctx, {
3211
+ scroll: resolvedOffset,
3212
+ targetIndexSeed: initialScroll.index
3213
+ });
3214
+ }
3031
3215
  }
3032
- rearmBootstrapInitialScroll(ctx, {
3033
- scroll: resolveInitialScrollOffset(ctx, initialScroll),
3034
- seedContentOffset: didFinishInitialScroll && !bootstrapInitialScroll ? getObservedBootstrapInitialScrollOffset(state) : void 0,
3035
- targetIndexSeed: initialScroll.index
3036
- });
3037
3216
  }
3038
3217
  function evaluateBootstrapInitialScroll(ctx) {
3039
3218
  var _a3, _b;
@@ -3240,7 +3419,7 @@ function checkFinishedScrollFallback(ctx) {
3240
3419
  state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
3241
3420
  };
3242
3421
  const checkHasScrolled = () => {
3243
- var _c;
3422
+ var _c, _d;
3244
3423
  state.timeoutCheckFinishedScrollFallback = void 0;
3245
3424
  const isStillScrollingTo = state.scrollingTo;
3246
3425
  if (isStillScrollingTo) {
@@ -3253,11 +3432,13 @@ function checkFinishedScrollFallback(ctx) {
3253
3432
  isStillScrollingTo
3254
3433
  );
3255
3434
  const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
3256
- const canFinishAfterSilentNativeDispatch = silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
3257
- if (shouldFinishZeroTarget || state.hasScrolled || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3435
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
3436
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
3437
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
3438
+ if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3258
3439
  finishScrollTo(ctx);
3259
- } else if (isNativeInitialPending && numChecks <= maxChecks) {
3260
- const targetOffset = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : state.scrollPending;
3440
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
3441
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
3261
3442
  scrollToFallbackOffset(ctx, targetOffset);
3262
3443
  scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3263
3444
  } else {
@@ -3270,6 +3451,15 @@ function checkFinishedScrollFallback(ctx) {
3270
3451
  }
3271
3452
 
3272
3453
  // src/core/initialScrollLifecycle.ts
3454
+ function retargetActiveInitialScrollAtEnd(ctx) {
3455
+ var _a3;
3456
+ const state = ctx.state;
3457
+ const initialScroll = state.initialScroll;
3458
+ if (!initialScroll || state.didFinishInitialScroll || ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset" || initialScroll.viewPosition !== 1 || state.props.data.length === 0) {
3459
+ return false;
3460
+ }
3461
+ return advanceCurrentInitialScrollSession(ctx, { forceScroll: true });
3462
+ }
3273
3463
  function handleInitialScrollLayoutReady(ctx) {
3274
3464
  var _a3;
3275
3465
  if (!ctx.state.initialScroll) {
@@ -3343,30 +3533,6 @@ function handleInitialScrollDataChange(ctx, options) {
3343
3533
  advanceCurrentInitialScrollSession(ctx);
3344
3534
  }
3345
3535
 
3346
- // src/utils/requestAdjust.ts
3347
- function requestAdjust(ctx, positionDiff, dataChanged) {
3348
- const state = ctx.state;
3349
- if (Math.abs(positionDiff) > 0.1) {
3350
- const doit = () => {
3351
- {
3352
- state.scrollAdjustHandler.requestAdjust(positionDiff);
3353
- if (state.adjustingFromInitialMount) {
3354
- state.adjustingFromInitialMount--;
3355
- }
3356
- }
3357
- };
3358
- state.scroll += positionDiff;
3359
- state.scrollForNextCalculateItemsInView = void 0;
3360
- const readyToRender = peek$(ctx, "readyToRender");
3361
- if (readyToRender) {
3362
- doit();
3363
- } else {
3364
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
3365
- requestAnimationFrame(doit);
3366
- }
3367
- }
3368
- }
3369
-
3370
3536
  // src/core/mvcp.ts
3371
3537
  var MVCP_POSITION_EPSILON = 0.1;
3372
3538
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -3640,7 +3806,10 @@ function prepareMVCP(ctx, dataChanged) {
3640
3806
  return;
3641
3807
  }
3642
3808
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
3643
- requestAdjust(ctx, positionDiff);
3809
+ const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
3810
+ if (!shouldSkipAdjustForMaintainedEnd) {
3811
+ requestAdjust(ctx, positionDiff);
3812
+ }
3644
3813
  }
3645
3814
  };
3646
3815
  }
@@ -4259,6 +4428,30 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
4259
4428
  var unstableBatchedUpdates = ReactDOM__namespace.unstable_batchedUpdates;
4260
4429
  var batchedUpdates = typeof unstableBatchedUpdates === "function" ? unstableBatchedUpdates : (fn) => fn();
4261
4430
 
4431
+ // src/utils/containerPool.ts
4432
+ var MIN_INITIAL_CONTAINER_POOL_SIZE = 32;
4433
+ var MAX_INITIAL_SPARE_CONTAINERS = 64;
4434
+ function getInitialContainerPoolSize(dataLength, numContainers, initialContainerPoolRatio) {
4435
+ if (dataLength <= 0 || numContainers <= 0) {
4436
+ return 0;
4437
+ }
4438
+ const ratioPoolSize = Math.ceil(numContainers * initialContainerPoolRatio);
4439
+ const cappedSparePoolSize = numContainers + MAX_INITIAL_SPARE_CONTAINERS;
4440
+ const targetPoolSize = Math.max(
4441
+ numContainers,
4442
+ Math.min(ratioPoolSize, cappedSparePoolSize),
4443
+ Math.min(dataLength, MIN_INITIAL_CONTAINER_POOL_SIZE)
4444
+ );
4445
+ const maxUsefulPoolSize = Math.max(dataLength, numContainers);
4446
+ return Math.min(maxUsefulPoolSize, targetPoolSize);
4447
+ }
4448
+ function getExpandedContainerPoolSize(dataLength, numContainers) {
4449
+ if (dataLength <= 0 || numContainers <= 0) {
4450
+ return 0;
4451
+ }
4452
+ return Math.min(Math.max(dataLength, numContainers), Math.max(numContainers, Math.ceil(numContainers * 1.5)));
4453
+ }
4454
+
4262
4455
  // src/utils/findAvailableContainers.ts
4263
4456
  function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers, protectedKeys) {
4264
4457
  const numContainers = peek$(ctx, "numContainers");
@@ -4464,7 +4657,7 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
4464
4657
  function calculateItemsInView(ctx, params = {}) {
4465
4658
  const state = ctx.state;
4466
4659
  batchedUpdates(() => {
4467
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
4660
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
4468
4661
  const {
4469
4662
  columns,
4470
4663
  columnSpans,
@@ -4511,12 +4704,22 @@ function calculateItemsInView(ctx, params = {}) {
4511
4704
  // current initial-scroll target instead of transient native adjustments.
4512
4705
  resolveInitialScrollOffset(ctx, initialScroll)
4513
4706
  ) : state.scroll;
4514
- const scrollAdjustPending = (_c = peek$(ctx, "scrollAdjustPending")) != null ? _c : 0;
4515
- const scrollAdjustPad = scrollAdjustPending - topPad;
4516
- let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
4517
- if (scroll + scrollLength > totalSize) {
4518
- scroll = Math.max(0, totalSize - scrollLength);
4519
- }
4707
+ let scrollAdjustPending = 0;
4708
+ let scrollAdjustPad = 0;
4709
+ let scroll = 0;
4710
+ let scrollTopBuffered = 0;
4711
+ let scrollBottom = 0;
4712
+ let scrollBottomBuffered = 0;
4713
+ const updateScroll2 = (nextScrollState) => {
4714
+ var _a4;
4715
+ scrollAdjustPending = (_a4 = peek$(ctx, "scrollAdjustPending")) != null ? _a4 : 0;
4716
+ scrollAdjustPad = scrollAdjustPending - topPad;
4717
+ scroll = Math.round(nextScrollState + scrollExtra + scrollAdjustPad);
4718
+ if (scroll + scrollLength > totalSize) {
4719
+ scroll = Math.max(0, totalSize - scrollLength);
4720
+ }
4721
+ };
4722
+ updateScroll2(scrollState);
4520
4723
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
4521
4724
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
4522
4725
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
@@ -4532,9 +4735,12 @@ function calculateItemsInView(ctx, params = {}) {
4532
4735
  scrollBufferTop = drawDistance * 1.5;
4533
4736
  scrollBufferBottom = drawDistance * 0.5;
4534
4737
  }
4535
- const scrollTopBuffered = scroll - scrollBufferTop;
4536
- const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
4537
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4738
+ const updateScrollRange = () => {
4739
+ scrollTopBuffered = scroll - scrollBufferTop;
4740
+ scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
4741
+ scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4742
+ };
4743
+ updateScrollRange();
4538
4744
  if (!suppressInitialScrollSideEffects && !dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
4539
4745
  const { top, bottom } = scrollForNextCalculateItemsInView;
4540
4746
  if (top === null && bottom === null) {
@@ -4553,7 +4759,7 @@ function calculateItemsInView(ctx, params = {}) {
4553
4759
  columns.length = 0;
4554
4760
  columnSpans.length = 0;
4555
4761
  }
4556
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_d = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _d : 0;
4762
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4557
4763
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4558
4764
  updateItemPositions(ctx, dataChanged, {
4559
4765
  doMVCP,
@@ -4578,21 +4784,25 @@ function calculateItemsInView(ctx, params = {}) {
4578
4784
  }
4579
4785
  }
4580
4786
  const scrollBeforeMVCP = state.scroll;
4581
- const scrollAdjustPendingBeforeMVCP = (_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0;
4787
+ const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
4582
4788
  checkMVCP == null ? void 0 : checkMVCP();
4583
- const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0) !== scrollAdjustPendingBeforeMVCP);
4789
+ const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0) !== scrollAdjustPendingBeforeMVCP);
4790
+ if (didMVCPAdjustScroll && initialScroll) {
4791
+ updateScroll2(state.scroll);
4792
+ updateScrollRange();
4793
+ }
4584
4794
  let startNoBuffer = null;
4585
4795
  let startBuffered = null;
4586
4796
  let startBufferedId = null;
4587
4797
  let endNoBuffer = null;
4588
4798
  let endBuffered = null;
4589
- let loopStart = (_g = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _g : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4799
+ let loopStart = (_f = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _f : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4590
4800
  for (let i = loopStart; i >= 0; i--) {
4591
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
4801
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
4592
4802
  const top = positions[i];
4593
- const size = (_i = sizes.get(id)) != null ? _i : getItemSize(ctx, id, i, data[i]);
4803
+ const size = (_h = sizes.get(id)) != null ? _h : getItemSize(ctx, id, i, data[i]);
4594
4804
  const bottom = top + size;
4595
- if (bottom > scroll - scrollBufferTop) {
4805
+ if (bottom > scrollTopBuffered) {
4596
4806
  loopStart = i;
4597
4807
  } else {
4598
4808
  break;
@@ -4621,8 +4831,8 @@ function calculateItemsInView(ctx, params = {}) {
4621
4831
  let firstFullyOnScreenIndex;
4622
4832
  const dataLength = data.length;
4623
4833
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
4624
- const id = (_j = idCache[i]) != null ? _j : getId(state, i);
4625
- const size = (_k = sizes.get(id)) != null ? _k : getItemSize(ctx, id, i, data[i]);
4834
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
4835
+ const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
4626
4836
  const top = positions[i];
4627
4837
  if (!foundEnd) {
4628
4838
  if (startNoBuffer === null && top + size > scroll) {
@@ -4661,7 +4871,7 @@ function calculateItemsInView(ctx, params = {}) {
4661
4871
  const firstVisibleAnchorIndex = firstFullyOnScreenIndex != null ? firstFullyOnScreenIndex : startNoBuffer;
4662
4872
  if (firstVisibleAnchorIndex !== null && firstVisibleAnchorIndex !== void 0 && endNoBuffer !== null) {
4663
4873
  for (let i = firstVisibleAnchorIndex; i <= endNoBuffer; i++) {
4664
- const id = (_l = idCache[i]) != null ? _l : getId(state, i);
4874
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
4665
4875
  idsInView.push(id);
4666
4876
  }
4667
4877
  }
@@ -4694,7 +4904,7 @@ function calculateItemsInView(ctx, params = {}) {
4694
4904
  const needNewContainers = [];
4695
4905
  const needNewContainersSet = /* @__PURE__ */ new Set();
4696
4906
  for (let i = startBuffered; i <= endBuffered; i++) {
4697
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
4907
+ const id = (_l = idCache[i]) != null ? _l : getId(state, i);
4698
4908
  if (!containerItemKeys.has(id)) {
4699
4909
  needNewContainersSet.add(i);
4700
4910
  needNewContainers.push(i);
@@ -4703,7 +4913,7 @@ function calculateItemsInView(ctx, params = {}) {
4703
4913
  if (alwaysRenderArr.length > 0) {
4704
4914
  for (const index of alwaysRenderArr) {
4705
4915
  if (index < 0 || index >= dataLength) continue;
4706
- const id = (_n = idCache[index]) != null ? _n : getId(state, index);
4916
+ const id = (_m = idCache[index]) != null ? _m : getId(state, index);
4707
4917
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
4708
4918
  needNewContainersSet.add(index);
4709
4919
  needNewContainers.push(index);
@@ -4742,7 +4952,7 @@ function calculateItemsInView(ctx, params = {}) {
4742
4952
  for (let idx = 0; idx < needNewContainers.length; idx++) {
4743
4953
  const i = needNewContainers[idx];
4744
4954
  const containerIndex = availableContainers[idx];
4745
- const id = (_o = idCache[i]) != null ? _o : getId(state, i);
4955
+ const id = (_n = idCache[i]) != null ? _n : getId(state, i);
4746
4956
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
4747
4957
  if (oldKey && oldKey !== id) {
4748
4958
  containerItemKeys.delete(oldKey);
@@ -4753,7 +4963,7 @@ function calculateItemsInView(ctx, params = {}) {
4753
4963
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
4754
4964
  }
4755
4965
  containerItemKeys.set(id, containerIndex);
4756
- (_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.add(id);
4966
+ (_o = state.userScrollAnchorResetKeys) == null ? void 0 : _o.add(id);
4757
4967
  const containerSticky = `containerSticky${containerIndex}`;
4758
4968
  const isSticky = stickyIndicesSet.has(i);
4759
4969
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -4777,17 +4987,17 @@ function calculateItemsInView(ctx, params = {}) {
4777
4987
  if (numContainers !== prevNumContainers) {
4778
4988
  set$(ctx, "numContainers", numContainers);
4779
4989
  if (numContainers > peek$(ctx, "numContainersPooled")) {
4780
- set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
4990
+ set$(ctx, "numContainersPooled", getExpandedContainerPoolSize(dataLength, numContainers));
4781
4991
  }
4782
4992
  }
4783
4993
  }
4784
- if (((_q = state.userScrollAnchorResetKeys) == null ? void 0 : _q.size) === 0) {
4994
+ if (((_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.size) === 0) {
4785
4995
  state.userScrollAnchorResetKeys = void 0;
4786
4996
  }
4787
4997
  if (alwaysRenderArr.length > 0) {
4788
4998
  for (const index of alwaysRenderArr) {
4789
4999
  if (index < 0 || index >= dataLength) continue;
4790
- const id = (_r = idCache[index]) != null ? _r : getId(state, index);
5000
+ const id = (_q = idCache[index]) != null ? _q : getId(state, index);
4791
5001
  const containerIndex = containerItemKeys.get(id);
4792
5002
  if (containerIndex !== void 0) {
4793
5003
  state.stickyContainerPool.add(containerIndex);
@@ -4891,21 +5101,25 @@ function doMaintainScrollAtEnd(ctx) {
4891
5101
  if (contentSize < state.scrollLength) {
4892
5102
  state.scroll = 0;
4893
5103
  }
4894
- requestAnimationFrame(() => {
4895
- var _a3;
4896
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
4897
- state.maintainingScrollAtEnd = true;
4898
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
4899
- animated: maintainScrollAtEnd.animated
4900
- });
4901
- setTimeout(
4902
- () => {
4903
- state.maintainingScrollAtEnd = false;
4904
- },
4905
- maintainScrollAtEnd.animated ? 500 : 0
4906
- );
4907
- }
4908
- });
5104
+ if (!state.maintainingScrollAtEnd) {
5105
+ state.maintainingScrollAtEnd = true;
5106
+ requestAnimationFrame(() => {
5107
+ var _a3;
5108
+ if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
5109
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
5110
+ animated: maintainScrollAtEnd.animated
5111
+ });
5112
+ setTimeout(
5113
+ () => {
5114
+ state.maintainingScrollAtEnd = false;
5115
+ },
5116
+ maintainScrollAtEnd.animated ? 500 : 0
5117
+ );
5118
+ } else {
5119
+ state.maintainingScrollAtEnd = false;
5120
+ }
5121
+ });
5122
+ }
4909
5123
  return true;
4910
5124
  }
4911
5125
  return false;
@@ -5017,14 +5231,21 @@ function doInitialAllocateContainers(ctx) {
5017
5231
  } else {
5018
5232
  averageItemSize = estimatedItemSize;
5019
5233
  }
5020
- const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
5234
+ const numContainers = Math.max(
5235
+ 1,
5236
+ Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns)
5237
+ );
5021
5238
  for (let i = 0; i < numContainers; i++) {
5022
5239
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
5023
5240
  set$(ctx, `containerColumn${i}`, -1);
5024
5241
  set$(ctx, `containerSpan${i}`, 1);
5025
5242
  }
5026
5243
  set$(ctx, "numContainers", numContainers);
5027
- set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
5244
+ set$(
5245
+ ctx,
5246
+ "numContainersPooled",
5247
+ getInitialContainerPoolSize(data.length, numContainers, state.props.initialContainerPoolRatio)
5248
+ );
5028
5249
  if (state.lastLayout) {
5029
5250
  if (state.initialScroll) {
5030
5251
  requestAnimationFrame(() => {
@@ -5175,8 +5396,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
5175
5396
  // src/core/onScroll.ts
5176
5397
  function trackInitialScrollNativeProgress(state, newScroll) {
5177
5398
  const initialNativeScrollWatchdog = initialScrollWatchdog.get(state);
5178
- const didInitialScrollProgress = !!initialNativeScrollWatchdog && initialScrollWatchdog.didObserveProgress(newScroll, initialNativeScrollWatchdog);
5179
- if (didInitialScrollProgress) {
5399
+ const didInitialScrollReachTarget = !!initialNativeScrollWatchdog && initialScrollWatchdog.didReachTarget(newScroll, initialNativeScrollWatchdog);
5400
+ if (didInitialScrollReachTarget) {
5180
5401
  initialScrollWatchdog.clear(state);
5181
5402
  return;
5182
5403
  }
@@ -5314,16 +5535,20 @@ function maybeUpdateAnchoredEndSpace(ctx) {
5314
5535
  let contentBelowAnchor = 0;
5315
5536
  const footerSize = ctx.values.get("footerSize") || 0;
5316
5537
  const stylePaddingBottom = state.props.stylePaddingBottom || 0;
5538
+ let hasUnknownTailSize = false;
5317
5539
  for (let index = anchorIndex; index < data.length; index++) {
5318
5540
  const itemKey = getId(state, index);
5319
5541
  const size = itemKey ? state.sizesKnown.get(itemKey) : void 0;
5320
5542
  const effectiveSize = index === anchorIndex && anchorMaxSize !== void 0 ? Math.min(size || 0, Math.max(0, anchorMaxSize)) : size;
5543
+ if (size === void 0) {
5544
+ hasUnknownTailSize = true;
5545
+ }
5321
5546
  if (effectiveSize !== null && effectiveSize !== void 0 && effectiveSize > 0) {
5322
5547
  contentBelowAnchor += effectiveSize;
5323
5548
  }
5324
5549
  }
5325
5550
  contentBelowAnchor += footerSize + stylePaddingBottom;
5326
- nextSize = Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5551
+ nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5327
5552
  }
5328
5553
  }
5329
5554
  if (previousSize !== nextSize) {
@@ -5336,6 +5561,22 @@ function maybeUpdateAnchoredEndSpace(ctx) {
5336
5561
  return nextSize;
5337
5562
  }
5338
5563
 
5564
+ // src/core/updateContentInsetEndAdjustment.ts
5565
+ function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment) {
5566
+ const state = ctx.state;
5567
+ const previousContentInsetEnd = getContentInsetEnd(ctx, previousContentInsetEndAdjustment);
5568
+ const nextContentInsetEnd = getContentInsetEnd(ctx);
5569
+ const insetDiff = nextContentInsetEnd - previousContentInsetEnd;
5570
+ if (insetDiff !== 0) {
5571
+ const wasWithinEndThreshold = !!peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
5572
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
5573
+ const didRetargetInitialScroll = retargetActiveInitialScrollAtEnd(ctx);
5574
+ if (!didRetargetInitialScroll && wasWithinEndThreshold && (insetDiff > 0)) {
5575
+ requestAdjust(ctx, insetDiff);
5576
+ }
5577
+ }
5578
+ }
5579
+
5339
5580
  // src/core/updateItemSize.ts
5340
5581
  function runOrScheduleMVCPRecalculate(ctx) {
5341
5582
  const state = ctx.state;
@@ -5379,15 +5620,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5379
5620
  const {
5380
5621
  didContainersLayout,
5381
5622
  sizesKnown,
5382
- props: {
5383
- getFixedItemSize,
5384
- getItemType,
5385
- horizontal,
5386
- suggestEstimatedItemSize,
5387
- onItemSizeChanged,
5388
- data,
5389
- maintainScrollAtEnd
5390
- }
5623
+ props: { getFixedItemSize, getItemType, horizontal, onItemSizeChanged, data, maintainScrollAtEnd }
5391
5624
  } = state;
5392
5625
  if (!data) return;
5393
5626
  const index = state.indexByKey.get(itemKey);
@@ -5438,18 +5671,6 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5438
5671
  if (minIndexSizeChanged !== void 0) {
5439
5672
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
5440
5673
  }
5441
- if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
5442
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
5443
- state.timeoutSizeMessage = setTimeout(() => {
5444
- var _a4;
5445
- state.timeoutSizeMessage = void 0;
5446
- const num = state.sizesKnown.size;
5447
- const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
5448
- console.warn(
5449
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
5450
- );
5451
- }, 1e3);
5452
- }
5453
5674
  const cur = peek$(ctx, "otherAxisSize");
5454
5675
  if (!cur || maxOtherAxisSize > cur) {
5455
5676
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
@@ -5554,12 +5775,47 @@ function createColumnWrapperStyle(contentContainerStyle) {
5554
5775
  }
5555
5776
 
5556
5777
  // src/utils/createImperativeHandle.ts
5778
+ var DEFAULT_AVERAGE_ITEM_SIZE_TYPE = "default";
5779
+ function getAverageItemSizes(state) {
5780
+ const averageItemSizes = {};
5781
+ for (const itemType in state.averageSizes) {
5782
+ const averageSize = state.averageSizes[itemType];
5783
+ if (averageSize) {
5784
+ averageItemSizes[itemType || DEFAULT_AVERAGE_ITEM_SIZE_TYPE] = {
5785
+ average: averageSize.avg,
5786
+ count: averageSize.num
5787
+ };
5788
+ }
5789
+ }
5790
+ return averageItemSizes;
5791
+ }
5557
5792
  function createImperativeHandle(ctx) {
5558
5793
  const state = ctx.state;
5559
5794
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
5560
5795
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
5561
5796
  let imperativeScrollToken = 0;
5562
5797
  const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
5798
+ const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
5799
+ var _a3;
5800
+ const props = state.props;
5801
+ const dataLength = props.data.length;
5802
+ const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5803
+ if (targetIndex < 0) {
5804
+ return allowEmpty;
5805
+ }
5806
+ if (targetIndex >= dataLength) {
5807
+ return false;
5808
+ }
5809
+ if (anchorIndex === void 0 || anchorIndex < 0 || anchorIndex >= dataLength || targetIndex < anchorIndex || props.getFixedItemSize) {
5810
+ return true;
5811
+ }
5812
+ for (let index = anchorIndex; index < dataLength; index++) {
5813
+ if (!state.sizesKnown.has(getId(state, index))) {
5814
+ return false;
5815
+ }
5816
+ }
5817
+ return true;
5818
+ };
5563
5819
  const runWhenReady = (token, run, isReady) => {
5564
5820
  const startedAt = Date.now();
5565
5821
  let stableFrames = 0;
@@ -5581,11 +5837,10 @@ function createImperativeHandle(ctx) {
5581
5837
  };
5582
5838
  requestAnimationFrame(check);
5583
5839
  };
5584
- const runScrollWithPromise = (run, options) => new Promise((resolve) => {
5585
- var _a3, _b;
5840
+ const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
5841
+ var _a3;
5586
5842
  const token = ++imperativeScrollToken;
5587
- const isReady = (_a3 = options == null ? void 0 : options.isReady) != null ? _a3 : (() => true);
5588
- (_b = state.pendingScrollResolve) == null ? void 0 : _b.call(state);
5843
+ (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
5589
5844
  state.pendingScrollResolve = resolve;
5590
5845
  const runNow = () => {
5591
5846
  if (token !== imperativeScrollToken) {
@@ -5660,6 +5915,7 @@ function createImperativeHandle(ctx) {
5660
5915
  },
5661
5916
  end: state.endNoBuffer,
5662
5917
  endBuffered: state.endBuffered,
5918
+ getAverageItemSizes: () => getAverageItemSizes(state),
5663
5919
  isAtEnd: peek$(ctx, "isAtEnd"),
5664
5920
  isAtStart: peek$(ctx, "isAtStart"),
5665
5921
  isEndReached: state.isEndReached,
@@ -5683,8 +5939,14 @@ function createImperativeHandle(ctx) {
5683
5939
  startBuffered: state.startBuffered
5684
5940
  }),
5685
5941
  reportContentInset: (inset) => {
5942
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
5943
+ const previousInset = state.contentInsetOverride;
5686
5944
  state.contentInsetOverride = inset != null ? inset : void 0;
5945
+ const didChange = ((_a3 = previousInset == null ? void 0 : previousInset.top) != null ? _a3 : 0) !== ((_c = (_b = state.contentInsetOverride) == null ? void 0 : _b.top) != null ? _c : 0) || ((_d = previousInset == null ? void 0 : previousInset.bottom) != null ? _d : 0) !== ((_f = (_e = state.contentInsetOverride) == null ? void 0 : _e.bottom) != null ? _f : 0) || ((_g = previousInset == null ? void 0 : previousInset.left) != null ? _g : 0) !== ((_i = (_h = state.contentInsetOverride) == null ? void 0 : _h.left) != null ? _i : 0) || ((_j = previousInset == null ? void 0 : previousInset.right) != null ? _j : 0) !== ((_l = (_k = state.contentInsetOverride) == null ? void 0 : _k.right) != null ? _l : 0);
5687
5946
  updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
5947
+ if (didChange) {
5948
+ retargetActiveInitialScrollAtEnd(ctx);
5949
+ }
5688
5950
  },
5689
5951
  scrollIndexIntoView: (options) => runScrollWithPromise(() => scrollIndexIntoView(options)),
5690
5952
  scrollItemIntoView: ({ item, ...props }) => runScrollWithPromise(() => {
@@ -5696,40 +5958,34 @@ function createImperativeHandle(ctx) {
5696
5958
  }
5697
5959
  return false;
5698
5960
  }),
5699
- scrollToEnd: (options) => runScrollWithPromise(() => {
5700
- const data = state.props.data;
5701
- const stylePaddingBottom = state.props.stylePaddingBottom;
5702
- const index = data.length - 1;
5703
- if (index !== -1) {
5704
- const paddingBottom = stylePaddingBottom || 0;
5705
- const footerSize = peek$(ctx, "footerSize") || 0;
5706
- scrollToIndex(ctx, {
5707
- ...options,
5708
- index,
5709
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5710
- viewPosition: 1
5711
- });
5712
- return true;
5713
- }
5714
- return false;
5715
- }),
5716
- scrollToIndex: (params) => {
5717
- const shouldWaitForOutOfRangeTarget = params.index >= 0 && params.index >= state.props.data.length;
5718
- const options = shouldWaitForOutOfRangeTarget ? {
5719
- isReady: () => {
5720
- var _a3;
5721
- const props = state.props;
5722
- const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5723
- const lastIndex = props.data.length - 1;
5724
- const isInRange = params.index < props.data.length;
5725
- const shouldWaitForAnchorSize = isInRange && anchorIndex !== void 0 && anchorIndex >= 0 && params.index >= anchorIndex && !props.getFixedItemSize && !state.sizesKnown.has(getId(state, lastIndex));
5726
- return isInRange && !shouldWaitForAnchorSize;
5961
+ scrollToEnd: (options) => runScrollWithPromise(
5962
+ () => {
5963
+ const data = state.props.data;
5964
+ const stylePaddingBottom = state.props.stylePaddingBottom;
5965
+ const index = data.length - 1;
5966
+ if (index !== -1) {
5967
+ const paddingBottom = stylePaddingBottom || 0;
5968
+ const footerSize = peek$(ctx, "footerSize") || 0;
5969
+ scrollToIndex(ctx, {
5970
+ ...options,
5971
+ index,
5972
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5973
+ viewPosition: 1
5974
+ });
5975
+ return true;
5727
5976
  }
5728
- } : void 0;
5729
- return runScrollWithPromise(() => {
5730
- scrollToIndex(ctx, params);
5731
- return true;
5732
- }, options);
5977
+ return false;
5978
+ },
5979
+ () => isScrollToIndexReady(state.props.data.length - 1, true)
5980
+ ),
5981
+ scrollToIndex: (params) => {
5982
+ return runScrollWithPromise(
5983
+ () => {
5984
+ scrollToIndex(ctx, params);
5985
+ return true;
5986
+ },
5987
+ params.index >= 0 ? () => isScrollToIndexReady(params.index) : void 0
5988
+ );
5733
5989
  },
5734
5990
  scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
5735
5991
  const data = state.props.data;
@@ -5985,6 +6241,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5985
6241
  data: dataProp = [],
5986
6242
  dataVersion,
5987
6243
  drawDistance = 250,
6244
+ contentInsetEndAdjustment,
5988
6245
  estimatedItemSize = 100,
5989
6246
  estimatedListSize,
5990
6247
  extraData,
@@ -5992,7 +6249,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5992
6249
  getFixedItemSize,
5993
6250
  getItemType,
5994
6251
  horizontal,
5995
- initialContainerPoolRatio = 2,
6252
+ initialContainerPoolRatio = 3,
5996
6253
  initialScrollAtEnd = false,
5997
6254
  initialScrollIndex: initialScrollIndexProp,
5998
6255
  initialScrollOffset: initialScrollOffsetProp,
@@ -6033,7 +6290,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6033
6290
  stickyIndices: stickyIndicesDeprecated,
6034
6291
  // TODOV3: Remove from v3 release
6035
6292
  style: styleProp,
6036
- suggestEstimatedItemSize,
6037
6293
  useWindowScroll = false,
6038
6294
  viewabilityConfig,
6039
6295
  viewabilityConfigCallbackPairs,
@@ -6094,6 +6350,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6094
6350
  const combinedRef = useCombinedRef(refScroller, refScrollView);
6095
6351
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
6096
6352
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
6353
+ const contentInsetEndAdjustmentResolved = contentInsetEndAdjustment ;
6354
+ const previousContentInsetEndAdjustmentRef = React3.useRef(contentInsetEndAdjustmentResolved);
6097
6355
  const alwaysRenderIndices = React3.useMemo(() => {
6098
6356
  const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor, anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
6099
6357
  return { arr: indices, set: new Set(indices) };
@@ -6172,7 +6430,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6172
6430
  startReachedSnapshotDataChangeEpoch: void 0,
6173
6431
  stickyContainerPool: /* @__PURE__ */ new Set(),
6174
6432
  stickyContainers: /* @__PURE__ */ new Map(),
6175
- timeoutSizeMessage: 0,
6176
6433
  timeouts: /* @__PURE__ */ new Set(),
6177
6434
  totalSize: 0,
6178
6435
  viewabilityConfigCallbackPairs: void 0
@@ -6192,7 +6449,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6192
6449
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
6193
6450
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
6194
6451
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
6195
- if (didDataChangeLocal && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6452
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6196
6453
  clearPreservedInitialScrollTarget(state);
6197
6454
  }
6198
6455
  if (didDataChangeLocal) {
@@ -6213,6 +6470,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6213
6470
  anchoredEndSpace: anchoredEndSpaceResolved,
6214
6471
  animatedProps: animatedPropsInternal,
6215
6472
  contentInset,
6473
+ contentInsetEndAdjustment: contentInsetEndAdjustmentResolved,
6216
6474
  data: dataProp,
6217
6475
  dataVersion,
6218
6476
  drawDistance,
@@ -6246,7 +6504,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6246
6504
  stickyPositionComponentInternal,
6247
6505
  stylePaddingBottom: stylePaddingBottomState,
6248
6506
  stylePaddingTop: stylePaddingTopState,
6249
- suggestEstimatedItemSize: !!suggestEstimatedItemSize,
6250
6507
  useWindowScroll: useWindowScrollResolved
6251
6508
  };
6252
6509
  state.refScroller = refScroller;
@@ -6330,6 +6587,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6330
6587
  didAnchoredEndSpaceAnchorIndexChange,
6331
6588
  numColumnsProp
6332
6589
  ]);
6590
+ React3.useLayoutEffect(() => {
6591
+ const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
6592
+ previousContentInsetEndAdjustmentRef.current = contentInsetEndAdjustmentResolved;
6593
+ updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment);
6594
+ }, [ctx, contentInsetEndAdjustmentResolved]);
6333
6595
  const onLayoutFooter = React3.useCallback(
6334
6596
  (layout) => {
6335
6597
  if (!usesBootstrapInitialScroll) {