@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.
@@ -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
@@ -682,8 +692,52 @@ function isInMVCPActiveMode(state) {
682
692
  }
683
693
 
684
694
  // src/components/Container.tsx
695
+ function getContainerPositionStyle({
696
+ columnWrapperStyle,
697
+ horizontal,
698
+ hasItemSeparator,
699
+ numColumns,
700
+ otherAxisPos,
701
+ otherAxisSize
702
+ }) {
703
+ let paddingStyles;
704
+ if (columnWrapperStyle) {
705
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
706
+ if (horizontal) {
707
+ paddingStyles = {
708
+ paddingBottom: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0,
709
+ paddingRight: columnGap || gap || void 0,
710
+ paddingTop: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
711
+ };
712
+ } else {
713
+ paddingStyles = {
714
+ paddingBottom: rowGap || gap || void 0,
715
+ paddingLeft: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0,
716
+ paddingRight: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
717
+ };
718
+ }
719
+ }
720
+ return horizontal ? {
721
+ boxSizing: paddingStyles ? "border-box" : void 0,
722
+ flexDirection: hasItemSeparator ? "row" : void 0,
723
+ height: otherAxisSize,
724
+ left: 0,
725
+ position: "absolute",
726
+ top: otherAxisPos,
727
+ ...paddingStyles || {}
728
+ } : {
729
+ boxSizing: paddingStyles ? "border-box" : void 0,
730
+ left: otherAxisPos,
731
+ position: "absolute",
732
+ right: numColumns > 1 ? null : 0,
733
+ top: 0,
734
+ width: otherAxisSize,
735
+ ...paddingStyles || {}
736
+ };
737
+ }
685
738
  var Container = typedMemo(function Container2({
686
739
  id,
740
+ itemKey,
687
741
  recycleItems,
688
742
  horizontal,
689
743
  getRenderedItem: getRenderedItem2,
@@ -695,11 +749,10 @@ var Container = typedMemo(function Container2({
695
749
  const { columnWrapperStyle, animatedScrollY } = ctx;
696
750
  const positionComponentInternal = ctx.state.props.positionComponentInternal;
697
751
  const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
698
- const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
752
+ const [column = 0, span = 1, data, numColumns = 1, extraData, isSticky] = useArr$([
699
753
  `containerColumn${id}`,
700
754
  `containerSpan${id}`,
701
755
  `containerItemData${id}`,
702
- `containerItemKey${id}`,
703
756
  "numColumns",
704
757
  "extraData",
705
758
  `containerSticky${id}`
@@ -720,42 +773,17 @@ var Container = typedMemo(function Container2({
720
773
  const resolvedSpan = Math.min(Math.max(span || 1, 1), numColumns);
721
774
  const otherAxisPos = numColumns > 1 ? `${(resolvedColumn - 1) / numColumns * 100}%` : 0;
722
775
  const otherAxisSize = numColumns > 1 ? `${resolvedSpan / numColumns * 100}%` : void 0;
723
- const style = React3.useMemo(() => {
724
- let paddingStyles;
725
- if (columnWrapperStyle) {
726
- const { columnGap, rowGap, gap } = columnWrapperStyle;
727
- if (horizontal) {
728
- paddingStyles = {
729
- paddingBottom: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0,
730
- paddingRight: columnGap || gap || void 0,
731
- paddingTop: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
732
- };
733
- } else {
734
- paddingStyles = {
735
- paddingBottom: rowGap || gap || void 0,
736
- paddingLeft: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0,
737
- paddingRight: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
738
- };
739
- }
740
- }
741
- return horizontal ? {
742
- boxSizing: paddingStyles ? "border-box" : void 0,
743
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
744
- height: otherAxisSize,
745
- left: 0,
746
- position: "absolute",
747
- top: otherAxisPos,
748
- ...paddingStyles || {}
749
- } : {
750
- boxSizing: paddingStyles ? "border-box" : void 0,
751
- left: otherAxisPos,
752
- position: "absolute",
753
- right: numColumns > 1 ? null : 0,
754
- top: 0,
755
- width: otherAxisSize,
756
- ...paddingStyles || {}
757
- };
758
- }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
776
+ const style = React3.useMemo(
777
+ () => getContainerPositionStyle({
778
+ columnWrapperStyle,
779
+ hasItemSeparator: !!ItemSeparatorComponent,
780
+ horizontal,
781
+ numColumns,
782
+ otherAxisPos,
783
+ otherAxisSize
784
+ }),
785
+ [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns, ItemSeparatorComponent]
786
+ );
759
787
  const renderedItemInfo = React3.useMemo(
760
788
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
761
789
  [itemKey, data, extraData]
@@ -842,6 +870,39 @@ var Container = typedMemo(function Container2({
842
870
  );
843
871
  });
844
872
 
873
+ // src/components/ContainerSlot.tsx
874
+ function ContainerSlotBase({
875
+ id,
876
+ horizontal,
877
+ recycleItems,
878
+ ItemSeparatorComponent,
879
+ updateItemSize: updateItemSize2,
880
+ getRenderedItem: getRenderedItem2,
881
+ stickyHeaderConfig,
882
+ ContainerComponent = Container
883
+ }) {
884
+ const [itemKey] = useArr$([`containerItemKey${id}`]);
885
+ if (itemKey === void 0) {
886
+ return null;
887
+ }
888
+ return /* @__PURE__ */ React3__namespace.createElement(
889
+ ContainerComponent,
890
+ {
891
+ getRenderedItem: getRenderedItem2,
892
+ horizontal,
893
+ ItemSeparatorComponent,
894
+ id,
895
+ itemKey,
896
+ recycleItems,
897
+ stickyHeaderConfig,
898
+ updateItemSize: updateItemSize2
899
+ }
900
+ );
901
+ }
902
+ var ContainerSlot = typedMemo(function ContainerSlot2(props) {
903
+ return /* @__PURE__ */ React3__namespace.createElement(ContainerSlotBase, { ...props });
904
+ });
905
+
845
906
  // src/utils/reordering.ts
846
907
  var mapFn = (element) => {
847
908
  const indexStr = element.getAttribute("data-index");
@@ -961,9 +1022,12 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
961
1022
  const ref = React3.useRef(null);
962
1023
  const ctx = useStateContext();
963
1024
  const columnWrapperStyle = ctx.columnWrapperStyle;
964
- const [otherAxisSize, totalSize] = useArr$(["otherAxisSize", "totalSize"]);
1025
+ const [otherAxisSize, readyToRender, totalSize] = useArr$(["otherAxisSize", "readyToRender", "totalSize"]);
965
1026
  useDOMOrder(ref);
966
- const style = horizontal ? { minHeight: otherAxisSize, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, position: "relative" };
1027
+ const style = horizontal ? { minHeight: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative" };
1028
+ if (!readyToRender) {
1029
+ style.pointerEvents = "none";
1030
+ }
967
1031
  if (columnWrapperStyle && numColumns > 1) {
968
1032
  const { columnGap, rowGap, gap } = columnWrapperStyle;
969
1033
  const gapX = columnGap || gap || 0;
@@ -991,12 +1055,12 @@ var Containers = typedMemo(function Containers2({
991
1055
  getRenderedItem: getRenderedItem2,
992
1056
  stickyHeaderConfig
993
1057
  }) {
994
- const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
1058
+ const [numContainersPooled, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
995
1059
  const containers = [];
996
- for (let i = 0; i < numContainers; i++) {
1060
+ for (let i = 0; i < numContainersPooled; i++) {
997
1061
  containers.push(
998
1062
  /* @__PURE__ */ React3__namespace.createElement(
999
- Container,
1063
+ ContainerSlot,
1000
1064
  {
1001
1065
  getRenderedItem: getRenderedItem2,
1002
1066
  horizontal,
@@ -1066,6 +1130,11 @@ function useRafCoalescer(callback) {
1066
1130
  return coalescer;
1067
1131
  }
1068
1132
 
1133
+ // src/components/webConstants.ts
1134
+ var LEGEND_LIST_CONTENT_CONTAINER_CLASS = "legend-list-content-container";
1135
+ var LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS = "legend-list-scrollbar-x-hidden";
1136
+ var LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS = "legend-list-scrollbar-y-hidden";
1137
+
1069
1138
  // src/components/webScrollUtils.ts
1070
1139
  function getDocumentScrollerNode() {
1071
1140
  if (typeof document === "undefined") {
@@ -1150,6 +1219,22 @@ function resolveWindowScrollTarget({ clampedOffset, horizontal, listPos, scroll
1150
1219
  }
1151
1220
 
1152
1221
  // src/components/ListComponentScrollView.tsx
1222
+ var SCROLLBAR_HIDDEN_STYLE_ID = "legend-list-scrollbar-axis-hidden-style";
1223
+ 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;}`;
1224
+ function ensureScrollbarHiddenStyle() {
1225
+ if (typeof document === "undefined" || document.getElementById(SCROLLBAR_HIDDEN_STYLE_ID)) {
1226
+ return;
1227
+ }
1228
+ const styleElement = document.createElement("style");
1229
+ styleElement.id = SCROLLBAR_HIDDEN_STYLE_ID;
1230
+ styleElement.textContent = SCROLLBAR_HIDDEN_STYLE;
1231
+ document.head.appendChild(styleElement);
1232
+ }
1233
+ function getContentInsetEndAdjustmentEnd2(ctx) {
1234
+ var _a3, _b;
1235
+ const adjustment = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.contentInsetEndAdjustment;
1236
+ return Math.max(0, adjustment != null ? adjustment : 0);
1237
+ }
1153
1238
  var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView2({
1154
1239
  children,
1155
1240
  style,
@@ -1167,7 +1252,9 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1167
1252
  onLayout,
1168
1253
  ...props
1169
1254
  }, ref) {
1255
+ var _a3, _b, _c;
1170
1256
  const ctx = useStateContext();
1257
+ const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
1171
1258
  const scrollRef = React3.useRef(null);
1172
1259
  const contentRef = React3.useRef(null);
1173
1260
  const isWindowScroll = useWindowScroll;
@@ -1229,10 +1316,9 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1229
1316
  React3.useImperativeHandle(ref, () => {
1230
1317
  const api = {
1231
1318
  getBoundingClientRect: () => {
1232
- var _a3;
1233
- return (_a3 = scrollRef.current) == null ? void 0 : _a3.getBoundingClientRect();
1319
+ var _a4;
1320
+ return (_a4 = scrollRef.current) == null ? void 0 : _a4.getBoundingClientRect();
1234
1321
  },
1235
- getContentNode: () => contentRef.current,
1236
1322
  getCurrentScrollOffset,
1237
1323
  getScrollableNode: () => resolveScrollableNode(scrollRef.current, isWindowScroll),
1238
1324
  getScrollEventTarget: () => getScrollTarget(),
@@ -1348,6 +1434,12 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1348
1434
  }
1349
1435
  };
1350
1436
  }, [isWindowScroll, onLayout]);
1437
+ const hiddenScrollIndicatorClassName = !isWindowScroll && (horizontal ? !showsHorizontalScrollIndicator && LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS : !showsVerticalScrollIndicator && LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS);
1438
+ React3.useLayoutEffect(() => {
1439
+ if (hiddenScrollIndicatorClassName) {
1440
+ ensureScrollbarHiddenStyle();
1441
+ }
1442
+ }, [hiddenScrollIndicatorClassName]);
1351
1443
  const scrollViewStyle = {
1352
1444
  ...isWindowScroll ? {} : {
1353
1445
  overflow: "auto",
@@ -1358,6 +1450,10 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1358
1450
  },
1359
1451
  ...StyleSheet.flatten(style)
1360
1452
  };
1453
+ const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd2(ctx);
1454
+ 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;
1455
+ const renderedContentInsetEndAdjustment = Math.max(0, contentInsetEndAdjustment - anchoredEndInset);
1456
+ const contentInsetEndAdjustmentSpacerStyle = renderedContentInsetEndAdjustment ? horizontal ? { flexShrink: 0, width: renderedContentInsetEndAdjustment } : { height: renderedContentInsetEndAdjustment } : void 0;
1361
1457
  const contentStyle = {
1362
1458
  display: horizontal ? "flex" : "block",
1363
1459
  flexDirection: horizontal ? "row" : void 0,
@@ -1365,15 +1461,38 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1365
1461
  minWidth: horizontal ? "100%" : void 0,
1366
1462
  ...StyleSheet.flatten(contentContainerStyle)
1367
1463
  };
1464
+ const className = contentContainerClassName ? `${LEGEND_LIST_CONTENT_CONTAINER_CLASS} ${contentContainerClassName}` : LEGEND_LIST_CONTENT_CONTAINER_CLASS;
1368
1465
  const {
1369
1466
  contentContainerClassName: _contentContainerClassName,
1370
1467
  contentInset: _contentInset,
1371
1468
  scrollEventThrottle: _scrollEventThrottle,
1372
1469
  ScrollComponent: _ScrollComponent,
1373
1470
  useWindowScroll: _useWindowScroll,
1471
+ className: scrollViewClassNameProp,
1374
1472
  ...webProps
1375
1473
  } = props;
1376
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3__namespace.createElement("div", { className: contentContainerClassName, ref: contentRef, style: contentStyle }, children));
1474
+ const scrollViewClassName = hiddenScrollIndicatorClassName ? scrollViewClassNameProp ? `${scrollViewClassNameProp} ${hiddenScrollIndicatorClassName}` : hiddenScrollIndicatorClassName : scrollViewClassNameProp;
1475
+ if (IS_DEV) {
1476
+ if (/(?:^|\s)(?:[a-z0-9_-]+:)*gap(?:-[xy])?-(?:\[[^\]]+\]|[^\s]+)/.test(
1477
+ `${contentContainerClassName != null ? contentContainerClassName : ""} ${scrollViewClassNameProp != null ? scrollViewClassNameProp : ""}`
1478
+ )) {
1479
+ warnDevOnce(
1480
+ "className-gap",
1481
+ "className/contentContainerClassName gap classes are not supported in LegendList because it needs to use exact values internally. Use contentContainerStyle={{ gap: ... }} or columnWrapperStyle instead."
1482
+ );
1483
+ }
1484
+ }
1485
+ return /* @__PURE__ */ React3__namespace.createElement(
1486
+ "div",
1487
+ {
1488
+ className: scrollViewClassName,
1489
+ ref: scrollRef,
1490
+ ...webProps,
1491
+ style: scrollViewStyle
1492
+ },
1493
+ refreshControl,
1494
+ /* @__PURE__ */ React3__namespace.createElement("div", { className, ref: contentRef, style: contentStyle }, children, contentInsetEndAdjustmentSpacerStyle ? /* @__PURE__ */ React3__namespace.createElement("div", { "aria-hidden": true, style: contentInsetEndAdjustmentSpacerStyle }) : null)
1495
+ );
1377
1496
  });
1378
1497
  function useValueListener$(key, callback) {
1379
1498
  const ctx = useStateContext();
@@ -1401,48 +1520,63 @@ function getScrollAdjustAxis(horizontal) {
1401
1520
  y: 1
1402
1521
  };
1403
1522
  }
1523
+ function getScrollAdjustTarget(ctx, contentNode) {
1524
+ var _a3, _b, _c;
1525
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1526
+ const scrollElement = (_c = (_b = scrollView == null ? void 0 : scrollView.getScrollableNode) == null ? void 0 : _b.call(scrollView)) != null ? _c : null;
1527
+ let resolvedContentNode = null;
1528
+ if (scrollElement) {
1529
+ resolvedContentNode = (contentNode == null ? void 0 : contentNode.isConnected) && contentNode.parentElement === scrollElement ? contentNode : scrollElement.querySelector(`:scope > .${LEGEND_LIST_CONTENT_CONTAINER_CLASS}`);
1530
+ }
1531
+ return scrollElement ? { contentNode: resolvedContentNode, scrollElement } : null;
1532
+ }
1533
+ function scrollAdjustBy(el, left, top) {
1534
+ el.scrollBy({ behavior: "auto", left, top });
1535
+ }
1404
1536
  function ScrollAdjust() {
1405
1537
  const ctx = useStateContext();
1406
1538
  const lastScrollOffsetRef = React3__namespace.useRef(0);
1407
1539
  const resetPaddingRafRef = React3__namespace.useRef(void 0);
1408
1540
  const resetPaddingBaselineRef = React3__namespace.useRef(void 0);
1541
+ const contentNodeRef = React3__namespace.useRef(null);
1409
1542
  const callback = React3__namespace.useCallback(() => {
1410
- var _a3, _b;
1543
+ var _a3;
1411
1544
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1412
1545
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1413
1546
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1414
- const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1415
- if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1416
- const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1417
- if (scrollDelta !== 0) {
1418
- const axis = getScrollAdjustAxis(!!ctx.state.props.horizontal);
1419
- const contentNode = scrollView.getContentNode();
1420
- const prevScroll = scrollView.getCurrentScrollOffset();
1421
- const el = scrollView.getScrollableNode();
1422
- const scrollBy = () => scrollView.scrollBy(axis.x * scrollDelta, axis.y * scrollDelta);
1423
- if (!contentNode) {
1424
- scrollBy();
1425
- lastScrollOffsetRef.current = scrollOffset;
1426
- return;
1427
- }
1428
- const totalSize = contentNode[axis.contentSizeKey];
1429
- const viewportSize = el[axis.viewportSizeKey];
1430
- const nextScroll = prevScroll + scrollDelta;
1431
- if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize) {
1432
- const previousPaddingEnd = (_b = resetPaddingBaselineRef.current) != null ? _b : contentNode.style[axis.paddingEndProp];
1433
- resetPaddingBaselineRef.current = previousPaddingEnd;
1434
- const pad = (nextScroll + viewportSize - totalSize) * 2;
1435
- contentNode.style[axis.paddingEndProp] = `${pad}px`;
1436
- void contentNode.offsetHeight;
1437
- scrollBy();
1438
- if (resetPaddingRafRef.current !== void 0) {
1439
- cancelAnimationFrame(resetPaddingRafRef.current);
1547
+ const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1548
+ if (scrollDelta !== 0) {
1549
+ const target = getScrollAdjustTarget(ctx, contentNodeRef.current);
1550
+ if (target) {
1551
+ const horizontal = !!ctx.state.props.horizontal;
1552
+ const axis = getScrollAdjustAxis(horizontal);
1553
+ const { contentNode, scrollElement: el } = target;
1554
+ const scrollBy = () => scrollAdjustBy(el, axis.x * scrollDelta, axis.y * scrollDelta);
1555
+ contentNodeRef.current = contentNode;
1556
+ if (contentNode) {
1557
+ const prevScroll = horizontal ? el.scrollLeft : el.scrollTop;
1558
+ const totalSize = contentNode[axis.contentSizeKey];
1559
+ const viewportSize = el[axis.viewportSizeKey];
1560
+ const nextScroll = prevScroll + scrollDelta;
1561
+ const needsTemporaryPadding = scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize;
1562
+ if (needsTemporaryPadding) {
1563
+ const previousPaddingEnd = (_a3 = resetPaddingBaselineRef.current) != null ? _a3 : contentNode.style[axis.paddingEndProp];
1564
+ resetPaddingBaselineRef.current = previousPaddingEnd;
1565
+ const pad = (nextScroll + viewportSize - totalSize) * 2;
1566
+ contentNode.style[axis.paddingEndProp] = `${pad}px`;
1567
+ void contentNode.offsetHeight;
1568
+ scrollBy();
1569
+ if (resetPaddingRafRef.current !== void 0) {
1570
+ cancelAnimationFrame(resetPaddingRafRef.current);
1571
+ }
1572
+ resetPaddingRafRef.current = requestAnimationFrame(() => {
1573
+ resetPaddingRafRef.current = void 0;
1574
+ resetPaddingBaselineRef.current = void 0;
1575
+ contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1576
+ });
1577
+ } else {
1578
+ scrollBy();
1440
1579
  }
1441
- resetPaddingRafRef.current = requestAnimationFrame(() => {
1442
- resetPaddingRafRef.current = void 0;
1443
- resetPaddingBaselineRef.current = void 0;
1444
- contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1445
- });
1446
1580
  } else {
1447
1581
  scrollBy();
1448
1582
  }
@@ -1753,10 +1887,9 @@ var initialScrollWatchdog = {
1753
1887
  clear(state) {
1754
1888
  initialScrollWatchdog.set(state, void 0);
1755
1889
  },
1756
- didObserveProgress(newScroll, watchdog) {
1757
- const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
1890
+ didReachTarget(newScroll, watchdog) {
1758
1891
  const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
1759
- return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET || nextDistance + INITIAL_SCROLL_MIN_TARGET_OFFSET < previousDistance;
1892
+ return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET;
1760
1893
  },
1761
1894
  get(state) {
1762
1895
  var _a3, _b;
@@ -1781,19 +1914,19 @@ var initialScrollWatchdog = {
1781
1914
  }
1782
1915
  };
1783
1916
  function setInitialScrollSession(state, options = {}) {
1784
- var _a3, _b, _c;
1917
+ var _a3, _b, _c, _d;
1785
1918
  const existingSession = state.initialScrollSession;
1786
1919
  const kind = (_a3 = options.kind) != null ? _a3 : existingSession == null ? void 0 : existingSession.kind;
1787
1920
  const completion = existingSession == null ? void 0 : existingSession.completion;
1788
- const hasBootstrapOverride = Object.hasOwn(options, "bootstrap");
1789
- const bootstrap = kind === "bootstrap" ? hasBootstrapOverride ? options.bootstrap : (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0 : void 0;
1921
+ const existingBootstrap = (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0;
1922
+ const bootstrap = kind === "bootstrap" ? options.bootstrap === null ? void 0 : (_b = options.bootstrap) != null ? _b : existingBootstrap : void 0;
1790
1923
  if (!kind) {
1791
1924
  return clearInitialScrollSession(state);
1792
1925
  }
1793
1926
  if (!state.initialScroll && !bootstrap && !hasInitialScrollSessionCompletion(completion)) {
1794
1927
  return clearInitialScrollSession(state);
1795
1928
  }
1796
- const previousDataLength = (_c = (_b = options.previousDataLength) != null ? _b : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _c : 0;
1929
+ const previousDataLength = (_d = (_c = options.previousDataLength) != null ? _c : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _d : 0;
1797
1930
  state.initialScrollSession = createInitialScrollSession({
1798
1931
  bootstrap,
1799
1932
  completion,
@@ -2545,7 +2678,7 @@ function advanceMeasuredInitialScroll(ctx, options) {
2545
2678
  const activeInitialTargetOffset = scrollingTo ? (_a3 = scrollingTo.targetOffset) != null ? _a3 : scrollingTo.offset : void 0;
2546
2679
  const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - resolvedOffset) > 1;
2547
2680
  const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - resolvedOffset) > 1;
2548
- const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - activeInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - activeInitialTargetOffset) <= 1;
2681
+ const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - resolvedOffset) <= 1 && Math.abs(state.scrollPending - resolvedOffset) <= 1;
2549
2682
  if (!(options == null ? void 0 : options.forceScroll) && !didOffsetChange && isInitialScrollInProgress && !didActiveInitialTargetChange) {
2550
2683
  return false;
2551
2684
  }
@@ -2617,6 +2750,30 @@ function checkAllSizesKnown(state, indices) {
2617
2750
  });
2618
2751
  }
2619
2752
 
2753
+ // src/utils/requestAdjust.ts
2754
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2755
+ const state = ctx.state;
2756
+ if (Math.abs(positionDiff) > 0.1) {
2757
+ const doit = () => {
2758
+ {
2759
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
2760
+ if (state.adjustingFromInitialMount) {
2761
+ state.adjustingFromInitialMount--;
2762
+ }
2763
+ }
2764
+ };
2765
+ state.scroll += positionDiff;
2766
+ state.scrollForNextCalculateItemsInView = void 0;
2767
+ const readyToRender = peek$(ctx, "readyToRender");
2768
+ if (readyToRender) {
2769
+ doit();
2770
+ } else {
2771
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2772
+ requestAnimationFrame(doit);
2773
+ }
2774
+ }
2775
+ }
2776
+
2620
2777
  // src/core/bootstrapInitialScroll.ts
2621
2778
  var DEFAULT_BOOTSTRAP_REVEAL_EPSILON = 1;
2622
2779
  var DEFAULT_BOOTSTRAP_REVEAL_MAX_FRAMES = 8;
@@ -2710,7 +2867,7 @@ function clearBootstrapInitialScrollSession(state) {
2710
2867
  bootstrapInitialScroll.frameHandle = void 0;
2711
2868
  }
2712
2869
  setInitialScrollSession(state, {
2713
- bootstrap: void 0,
2870
+ bootstrap: null,
2714
2871
  kind: (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind
2715
2872
  });
2716
2873
  }
@@ -2866,15 +3023,18 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2866
3023
  return;
2867
3024
  }
2868
3025
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2869
- if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2870
- clearPendingInitialScrollFooterLayout(ctx, {
2871
- dataLength: state.props.data.length,
2872
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2873
- target: initialScroll
2874
- });
2875
- return;
3026
+ const shouldKeepEndTargetAlive = isRetargetableBottomAlignedInitialScrollTarget(initialScroll) && peek$(ctx, "isAtEnd");
3027
+ if (!shouldKeepEndTargetAlive) {
3028
+ if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
3029
+ clearPendingInitialScrollFooterLayout(ctx, {
3030
+ dataLength: state.props.data.length,
3031
+ stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
3032
+ target: initialScroll
3033
+ });
3034
+ } else {
3035
+ clearFinishedViewportRetargetableInitialScroll(state);
3036
+ }
2876
3037
  }
2877
- clearFinishedViewportRetargetableInitialScroll(state);
2878
3038
  }
2879
3039
  }
2880
3040
  function startBootstrapInitialScrollOnMount(ctx, options) {
@@ -2913,7 +3073,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2913
3073
  }
2914
3074
  const shouldResetDidFinish = !!(state.didFinishInitialScroll && previousDataLength === 0 && dataLength > 0 && initialScroll.index !== void 0);
2915
3075
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2916
- const shouldClearFinishedResizePreservation = didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
3076
+ const shouldClearFinishedResizePreservation = !initialScrollAtEnd && didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
2917
3077
  if (shouldClearFinishedResizePreservation) {
2918
3078
  clearPreservedInitialScrollTarget(state);
2919
3079
  return;
@@ -3016,27 +3176,46 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
3016
3176
  }
3017
3177
  }
3018
3178
  function handleBootstrapInitialScrollLayoutChange(ctx) {
3179
+ var _a3, _b, _c, _d;
3019
3180
  const state = ctx.state;
3020
3181
  const initialScroll = state.initialScroll;
3021
- if (isOffsetInitialScrollSession(state) || state.props.data.length === 0 || !initialScroll) {
3022
- return;
3023
- }
3024
3182
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
3025
- if (!bootstrapInitialScroll && initialScroll.viewPosition !== 1) {
3026
- return;
3027
- }
3028
- const didFinishInitialScroll = state.didFinishInitialScroll;
3029
- if (didFinishInitialScroll) {
3030
- setInitialScrollTarget(state, initialScroll, {
3031
- resetDidFinish: true
3032
- });
3033
- state.clearPreservedInitialScrollOnNextFinish = true;
3183
+ if (initialScroll && state.props.data.length > 0 && !isOffsetInitialScrollSession(state) && (bootstrapInitialScroll || initialScroll.viewPosition === 1)) {
3184
+ const resolvedOffset = resolveInitialScrollOffset(ctx, initialScroll);
3185
+ const scrollingTo = ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) ? state.scrollingTo : void 0;
3186
+ if (!bootstrapInitialScroll && (scrollingTo || state.didFinishInitialScroll)) {
3187
+ const currentOffset = scrollingTo ? (_b = scrollingTo.targetOffset) != null ? _b : scrollingTo.offset : getObservedBootstrapInitialScrollOffset(state);
3188
+ const offsetDiff = resolvedOffset - currentOffset;
3189
+ if (Math.abs(offsetDiff) > DEFAULT_BOOTSTRAP_REVEAL_EPSILON) {
3190
+ if (scrollingTo) {
3191
+ const existingWatchdog = initialScrollWatchdog.get(state);
3192
+ scrollingTo.offset = resolvedOffset;
3193
+ scrollingTo.targetOffset = resolvedOffset;
3194
+ state.initialScroll = {
3195
+ ...initialScroll,
3196
+ contentOffset: resolvedOffset
3197
+ };
3198
+ state.hasScrolled = false;
3199
+ initialScrollWatchdog.set(state, {
3200
+ startScroll: (_c = existingWatchdog == null ? void 0 : existingWatchdog.startScroll) != null ? _c : state.scroll,
3201
+ targetOffset: resolvedOffset
3202
+ });
3203
+ }
3204
+ requestAdjust(ctx, offsetDiff);
3205
+ if (state.didFinishInitialScroll) {
3206
+ (_d = state.triggerCalculateItemsInView) == null ? void 0 : _d.call(state, { forceFullItemPositions: true });
3207
+ }
3208
+ }
3209
+ if (state.didFinishInitialScroll) {
3210
+ clearFinishedViewportRetargetableInitialScroll(state);
3211
+ }
3212
+ } else {
3213
+ rearmBootstrapInitialScroll(ctx, {
3214
+ scroll: resolvedOffset,
3215
+ targetIndexSeed: initialScroll.index
3216
+ });
3217
+ }
3034
3218
  }
3035
- rearmBootstrapInitialScroll(ctx, {
3036
- scroll: resolveInitialScrollOffset(ctx, initialScroll),
3037
- seedContentOffset: didFinishInitialScroll && !bootstrapInitialScroll ? getObservedBootstrapInitialScrollOffset(state) : void 0,
3038
- targetIndexSeed: initialScroll.index
3039
- });
3040
3219
  }
3041
3220
  function evaluateBootstrapInitialScroll(ctx) {
3042
3221
  var _a3, _b;
@@ -3243,7 +3422,7 @@ function checkFinishedScrollFallback(ctx) {
3243
3422
  state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
3244
3423
  };
3245
3424
  const checkHasScrolled = () => {
3246
- var _c;
3425
+ var _c, _d;
3247
3426
  state.timeoutCheckFinishedScrollFallback = void 0;
3248
3427
  const isStillScrollingTo = state.scrollingTo;
3249
3428
  if (isStillScrollingTo) {
@@ -3256,11 +3435,13 @@ function checkFinishedScrollFallback(ctx) {
3256
3435
  isStillScrollingTo
3257
3436
  );
3258
3437
  const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
3259
- const canFinishAfterSilentNativeDispatch = silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
3260
- if (shouldFinishZeroTarget || state.hasScrolled || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3438
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
3439
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
3440
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
3441
+ if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3261
3442
  finishScrollTo(ctx);
3262
- } else if (isNativeInitialPending && numChecks <= maxChecks) {
3263
- const targetOffset = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : state.scrollPending;
3443
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
3444
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
3264
3445
  scrollToFallbackOffset(ctx, targetOffset);
3265
3446
  scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3266
3447
  } else {
@@ -3273,6 +3454,15 @@ function checkFinishedScrollFallback(ctx) {
3273
3454
  }
3274
3455
 
3275
3456
  // src/core/initialScrollLifecycle.ts
3457
+ function retargetActiveInitialScrollAtEnd(ctx) {
3458
+ var _a3;
3459
+ const state = ctx.state;
3460
+ const initialScroll = state.initialScroll;
3461
+ if (!initialScroll || state.didFinishInitialScroll || ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset" || initialScroll.viewPosition !== 1 || state.props.data.length === 0) {
3462
+ return false;
3463
+ }
3464
+ return advanceCurrentInitialScrollSession(ctx, { forceScroll: true });
3465
+ }
3276
3466
  function handleInitialScrollLayoutReady(ctx) {
3277
3467
  var _a3;
3278
3468
  if (!ctx.state.initialScroll) {
@@ -3346,30 +3536,6 @@ function handleInitialScrollDataChange(ctx, options) {
3346
3536
  advanceCurrentInitialScrollSession(ctx);
3347
3537
  }
3348
3538
 
3349
- // src/utils/requestAdjust.ts
3350
- function requestAdjust(ctx, positionDiff, dataChanged) {
3351
- const state = ctx.state;
3352
- if (Math.abs(positionDiff) > 0.1) {
3353
- const doit = () => {
3354
- {
3355
- state.scrollAdjustHandler.requestAdjust(positionDiff);
3356
- if (state.adjustingFromInitialMount) {
3357
- state.adjustingFromInitialMount--;
3358
- }
3359
- }
3360
- };
3361
- state.scroll += positionDiff;
3362
- state.scrollForNextCalculateItemsInView = void 0;
3363
- const readyToRender = peek$(ctx, "readyToRender");
3364
- if (readyToRender) {
3365
- doit();
3366
- } else {
3367
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
3368
- requestAnimationFrame(doit);
3369
- }
3370
- }
3371
- }
3372
-
3373
3539
  // src/core/mvcp.ts
3374
3540
  var MVCP_POSITION_EPSILON = 0.1;
3375
3541
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -3643,7 +3809,10 @@ function prepareMVCP(ctx, dataChanged) {
3643
3809
  return;
3644
3810
  }
3645
3811
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
3646
- requestAdjust(ctx, positionDiff);
3812
+ const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
3813
+ if (!shouldSkipAdjustForMaintainedEnd) {
3814
+ requestAdjust(ctx, positionDiff);
3815
+ }
3647
3816
  }
3648
3817
  };
3649
3818
  }
@@ -4262,6 +4431,30 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
4262
4431
  var unstableBatchedUpdates = ReactDOM__namespace.unstable_batchedUpdates;
4263
4432
  var batchedUpdates = typeof unstableBatchedUpdates === "function" ? unstableBatchedUpdates : (fn) => fn();
4264
4433
 
4434
+ // src/utils/containerPool.ts
4435
+ var MIN_INITIAL_CONTAINER_POOL_SIZE = 32;
4436
+ var MAX_INITIAL_SPARE_CONTAINERS = 64;
4437
+ function getInitialContainerPoolSize(dataLength, numContainers, initialContainerPoolRatio) {
4438
+ if (dataLength <= 0 || numContainers <= 0) {
4439
+ return 0;
4440
+ }
4441
+ const ratioPoolSize = Math.ceil(numContainers * initialContainerPoolRatio);
4442
+ const cappedSparePoolSize = numContainers + MAX_INITIAL_SPARE_CONTAINERS;
4443
+ const targetPoolSize = Math.max(
4444
+ numContainers,
4445
+ Math.min(ratioPoolSize, cappedSparePoolSize),
4446
+ Math.min(dataLength, MIN_INITIAL_CONTAINER_POOL_SIZE)
4447
+ );
4448
+ const maxUsefulPoolSize = Math.max(dataLength, numContainers);
4449
+ return Math.min(maxUsefulPoolSize, targetPoolSize);
4450
+ }
4451
+ function getExpandedContainerPoolSize(dataLength, numContainers) {
4452
+ if (dataLength <= 0 || numContainers <= 0) {
4453
+ return 0;
4454
+ }
4455
+ return Math.min(Math.max(dataLength, numContainers), Math.max(numContainers, Math.ceil(numContainers * 1.5)));
4456
+ }
4457
+
4265
4458
  // src/utils/findAvailableContainers.ts
4266
4459
  function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers, protectedKeys) {
4267
4460
  const numContainers = peek$(ctx, "numContainers");
@@ -4467,7 +4660,7 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
4467
4660
  function calculateItemsInView(ctx, params = {}) {
4468
4661
  const state = ctx.state;
4469
4662
  batchedUpdates(() => {
4470
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
4663
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
4471
4664
  const {
4472
4665
  columns,
4473
4666
  columnSpans,
@@ -4514,12 +4707,22 @@ function calculateItemsInView(ctx, params = {}) {
4514
4707
  // current initial-scroll target instead of transient native adjustments.
4515
4708
  resolveInitialScrollOffset(ctx, initialScroll)
4516
4709
  ) : state.scroll;
4517
- const scrollAdjustPending = (_c = peek$(ctx, "scrollAdjustPending")) != null ? _c : 0;
4518
- const scrollAdjustPad = scrollAdjustPending - topPad;
4519
- let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
4520
- if (scroll + scrollLength > totalSize) {
4521
- scroll = Math.max(0, totalSize - scrollLength);
4522
- }
4710
+ let scrollAdjustPending = 0;
4711
+ let scrollAdjustPad = 0;
4712
+ let scroll = 0;
4713
+ let scrollTopBuffered = 0;
4714
+ let scrollBottom = 0;
4715
+ let scrollBottomBuffered = 0;
4716
+ const updateScroll2 = (nextScrollState) => {
4717
+ var _a4;
4718
+ scrollAdjustPending = (_a4 = peek$(ctx, "scrollAdjustPending")) != null ? _a4 : 0;
4719
+ scrollAdjustPad = scrollAdjustPending - topPad;
4720
+ scroll = Math.round(nextScrollState + scrollExtra + scrollAdjustPad);
4721
+ if (scroll + scrollLength > totalSize) {
4722
+ scroll = Math.max(0, totalSize - scrollLength);
4723
+ }
4724
+ };
4725
+ updateScroll2(scrollState);
4523
4726
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
4524
4727
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
4525
4728
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
@@ -4535,9 +4738,12 @@ function calculateItemsInView(ctx, params = {}) {
4535
4738
  scrollBufferTop = drawDistance * 1.5;
4536
4739
  scrollBufferBottom = drawDistance * 0.5;
4537
4740
  }
4538
- const scrollTopBuffered = scroll - scrollBufferTop;
4539
- const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
4540
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4741
+ const updateScrollRange = () => {
4742
+ scrollTopBuffered = scroll - scrollBufferTop;
4743
+ scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
4744
+ scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4745
+ };
4746
+ updateScrollRange();
4541
4747
  if (!suppressInitialScrollSideEffects && !dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
4542
4748
  const { top, bottom } = scrollForNextCalculateItemsInView;
4543
4749
  if (top === null && bottom === null) {
@@ -4556,7 +4762,7 @@ function calculateItemsInView(ctx, params = {}) {
4556
4762
  columns.length = 0;
4557
4763
  columnSpans.length = 0;
4558
4764
  }
4559
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_d = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _d : 0;
4765
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4560
4766
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4561
4767
  updateItemPositions(ctx, dataChanged, {
4562
4768
  doMVCP,
@@ -4581,21 +4787,25 @@ function calculateItemsInView(ctx, params = {}) {
4581
4787
  }
4582
4788
  }
4583
4789
  const scrollBeforeMVCP = state.scroll;
4584
- const scrollAdjustPendingBeforeMVCP = (_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0;
4790
+ const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
4585
4791
  checkMVCP == null ? void 0 : checkMVCP();
4586
- const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0) !== scrollAdjustPendingBeforeMVCP);
4792
+ const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0) !== scrollAdjustPendingBeforeMVCP);
4793
+ if (didMVCPAdjustScroll && initialScroll) {
4794
+ updateScroll2(state.scroll);
4795
+ updateScrollRange();
4796
+ }
4587
4797
  let startNoBuffer = null;
4588
4798
  let startBuffered = null;
4589
4799
  let startBufferedId = null;
4590
4800
  let endNoBuffer = null;
4591
4801
  let endBuffered = null;
4592
- let loopStart = (_g = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _g : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4802
+ let loopStart = (_f = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _f : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4593
4803
  for (let i = loopStart; i >= 0; i--) {
4594
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
4804
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
4595
4805
  const top = positions[i];
4596
- const size = (_i = sizes.get(id)) != null ? _i : getItemSize(ctx, id, i, data[i]);
4806
+ const size = (_h = sizes.get(id)) != null ? _h : getItemSize(ctx, id, i, data[i]);
4597
4807
  const bottom = top + size;
4598
- if (bottom > scroll - scrollBufferTop) {
4808
+ if (bottom > scrollTopBuffered) {
4599
4809
  loopStart = i;
4600
4810
  } else {
4601
4811
  break;
@@ -4624,8 +4834,8 @@ function calculateItemsInView(ctx, params = {}) {
4624
4834
  let firstFullyOnScreenIndex;
4625
4835
  const dataLength = data.length;
4626
4836
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
4627
- const id = (_j = idCache[i]) != null ? _j : getId(state, i);
4628
- const size = (_k = sizes.get(id)) != null ? _k : getItemSize(ctx, id, i, data[i]);
4837
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
4838
+ const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
4629
4839
  const top = positions[i];
4630
4840
  if (!foundEnd) {
4631
4841
  if (startNoBuffer === null && top + size > scroll) {
@@ -4664,7 +4874,7 @@ function calculateItemsInView(ctx, params = {}) {
4664
4874
  const firstVisibleAnchorIndex = firstFullyOnScreenIndex != null ? firstFullyOnScreenIndex : startNoBuffer;
4665
4875
  if (firstVisibleAnchorIndex !== null && firstVisibleAnchorIndex !== void 0 && endNoBuffer !== null) {
4666
4876
  for (let i = firstVisibleAnchorIndex; i <= endNoBuffer; i++) {
4667
- const id = (_l = idCache[i]) != null ? _l : getId(state, i);
4877
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
4668
4878
  idsInView.push(id);
4669
4879
  }
4670
4880
  }
@@ -4697,7 +4907,7 @@ function calculateItemsInView(ctx, params = {}) {
4697
4907
  const needNewContainers = [];
4698
4908
  const needNewContainersSet = /* @__PURE__ */ new Set();
4699
4909
  for (let i = startBuffered; i <= endBuffered; i++) {
4700
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
4910
+ const id = (_l = idCache[i]) != null ? _l : getId(state, i);
4701
4911
  if (!containerItemKeys.has(id)) {
4702
4912
  needNewContainersSet.add(i);
4703
4913
  needNewContainers.push(i);
@@ -4706,7 +4916,7 @@ function calculateItemsInView(ctx, params = {}) {
4706
4916
  if (alwaysRenderArr.length > 0) {
4707
4917
  for (const index of alwaysRenderArr) {
4708
4918
  if (index < 0 || index >= dataLength) continue;
4709
- const id = (_n = idCache[index]) != null ? _n : getId(state, index);
4919
+ const id = (_m = idCache[index]) != null ? _m : getId(state, index);
4710
4920
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
4711
4921
  needNewContainersSet.add(index);
4712
4922
  needNewContainers.push(index);
@@ -4745,7 +4955,7 @@ function calculateItemsInView(ctx, params = {}) {
4745
4955
  for (let idx = 0; idx < needNewContainers.length; idx++) {
4746
4956
  const i = needNewContainers[idx];
4747
4957
  const containerIndex = availableContainers[idx];
4748
- const id = (_o = idCache[i]) != null ? _o : getId(state, i);
4958
+ const id = (_n = idCache[i]) != null ? _n : getId(state, i);
4749
4959
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
4750
4960
  if (oldKey && oldKey !== id) {
4751
4961
  containerItemKeys.delete(oldKey);
@@ -4756,7 +4966,7 @@ function calculateItemsInView(ctx, params = {}) {
4756
4966
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
4757
4967
  }
4758
4968
  containerItemKeys.set(id, containerIndex);
4759
- (_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.add(id);
4969
+ (_o = state.userScrollAnchorResetKeys) == null ? void 0 : _o.add(id);
4760
4970
  const containerSticky = `containerSticky${containerIndex}`;
4761
4971
  const isSticky = stickyIndicesSet.has(i);
4762
4972
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -4780,17 +4990,17 @@ function calculateItemsInView(ctx, params = {}) {
4780
4990
  if (numContainers !== prevNumContainers) {
4781
4991
  set$(ctx, "numContainers", numContainers);
4782
4992
  if (numContainers > peek$(ctx, "numContainersPooled")) {
4783
- set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
4993
+ set$(ctx, "numContainersPooled", getExpandedContainerPoolSize(dataLength, numContainers));
4784
4994
  }
4785
4995
  }
4786
4996
  }
4787
- if (((_q = state.userScrollAnchorResetKeys) == null ? void 0 : _q.size) === 0) {
4997
+ if (((_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.size) === 0) {
4788
4998
  state.userScrollAnchorResetKeys = void 0;
4789
4999
  }
4790
5000
  if (alwaysRenderArr.length > 0) {
4791
5001
  for (const index of alwaysRenderArr) {
4792
5002
  if (index < 0 || index >= dataLength) continue;
4793
- const id = (_r = idCache[index]) != null ? _r : getId(state, index);
5003
+ const id = (_q = idCache[index]) != null ? _q : getId(state, index);
4794
5004
  const containerIndex = containerItemKeys.get(id);
4795
5005
  if (containerIndex !== void 0) {
4796
5006
  state.stickyContainerPool.add(containerIndex);
@@ -4894,21 +5104,25 @@ function doMaintainScrollAtEnd(ctx) {
4894
5104
  if (contentSize < state.scrollLength) {
4895
5105
  state.scroll = 0;
4896
5106
  }
4897
- requestAnimationFrame(() => {
4898
- var _a3;
4899
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
4900
- state.maintainingScrollAtEnd = true;
4901
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
4902
- animated: maintainScrollAtEnd.animated
4903
- });
4904
- setTimeout(
4905
- () => {
4906
- state.maintainingScrollAtEnd = false;
4907
- },
4908
- maintainScrollAtEnd.animated ? 500 : 0
4909
- );
4910
- }
4911
- });
5107
+ if (!state.maintainingScrollAtEnd) {
5108
+ state.maintainingScrollAtEnd = true;
5109
+ requestAnimationFrame(() => {
5110
+ var _a3;
5111
+ if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
5112
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
5113
+ animated: maintainScrollAtEnd.animated
5114
+ });
5115
+ setTimeout(
5116
+ () => {
5117
+ state.maintainingScrollAtEnd = false;
5118
+ },
5119
+ maintainScrollAtEnd.animated ? 500 : 0
5120
+ );
5121
+ } else {
5122
+ state.maintainingScrollAtEnd = false;
5123
+ }
5124
+ });
5125
+ }
4912
5126
  return true;
4913
5127
  }
4914
5128
  return false;
@@ -5020,14 +5234,21 @@ function doInitialAllocateContainers(ctx) {
5020
5234
  } else {
5021
5235
  averageItemSize = estimatedItemSize;
5022
5236
  }
5023
- const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
5237
+ const numContainers = Math.max(
5238
+ 1,
5239
+ Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns)
5240
+ );
5024
5241
  for (let i = 0; i < numContainers; i++) {
5025
5242
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
5026
5243
  set$(ctx, `containerColumn${i}`, -1);
5027
5244
  set$(ctx, `containerSpan${i}`, 1);
5028
5245
  }
5029
5246
  set$(ctx, "numContainers", numContainers);
5030
- set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
5247
+ set$(
5248
+ ctx,
5249
+ "numContainersPooled",
5250
+ getInitialContainerPoolSize(data.length, numContainers, state.props.initialContainerPoolRatio)
5251
+ );
5031
5252
  if (state.lastLayout) {
5032
5253
  if (state.initialScroll) {
5033
5254
  requestAnimationFrame(() => {
@@ -5178,8 +5399,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
5178
5399
  // src/core/onScroll.ts
5179
5400
  function trackInitialScrollNativeProgress(state, newScroll) {
5180
5401
  const initialNativeScrollWatchdog = initialScrollWatchdog.get(state);
5181
- const didInitialScrollProgress = !!initialNativeScrollWatchdog && initialScrollWatchdog.didObserveProgress(newScroll, initialNativeScrollWatchdog);
5182
- if (didInitialScrollProgress) {
5402
+ const didInitialScrollReachTarget = !!initialNativeScrollWatchdog && initialScrollWatchdog.didReachTarget(newScroll, initialNativeScrollWatchdog);
5403
+ if (didInitialScrollReachTarget) {
5183
5404
  initialScrollWatchdog.clear(state);
5184
5405
  return;
5185
5406
  }
@@ -5317,16 +5538,20 @@ function maybeUpdateAnchoredEndSpace(ctx) {
5317
5538
  let contentBelowAnchor = 0;
5318
5539
  const footerSize = ctx.values.get("footerSize") || 0;
5319
5540
  const stylePaddingBottom = state.props.stylePaddingBottom || 0;
5541
+ let hasUnknownTailSize = false;
5320
5542
  for (let index = anchorIndex; index < data.length; index++) {
5321
5543
  const itemKey = getId(state, index);
5322
5544
  const size = itemKey ? state.sizesKnown.get(itemKey) : void 0;
5323
5545
  const effectiveSize = index === anchorIndex && anchorMaxSize !== void 0 ? Math.min(size || 0, Math.max(0, anchorMaxSize)) : size;
5546
+ if (size === void 0) {
5547
+ hasUnknownTailSize = true;
5548
+ }
5324
5549
  if (effectiveSize !== null && effectiveSize !== void 0 && effectiveSize > 0) {
5325
5550
  contentBelowAnchor += effectiveSize;
5326
5551
  }
5327
5552
  }
5328
5553
  contentBelowAnchor += footerSize + stylePaddingBottom;
5329
- nextSize = Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5554
+ nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5330
5555
  }
5331
5556
  }
5332
5557
  if (previousSize !== nextSize) {
@@ -5339,6 +5564,22 @@ function maybeUpdateAnchoredEndSpace(ctx) {
5339
5564
  return nextSize;
5340
5565
  }
5341
5566
 
5567
+ // src/core/updateContentInsetEndAdjustment.ts
5568
+ function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment) {
5569
+ const state = ctx.state;
5570
+ const previousContentInsetEnd = getContentInsetEnd(ctx, previousContentInsetEndAdjustment);
5571
+ const nextContentInsetEnd = getContentInsetEnd(ctx);
5572
+ const insetDiff = nextContentInsetEnd - previousContentInsetEnd;
5573
+ if (insetDiff !== 0) {
5574
+ const wasWithinEndThreshold = !!peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
5575
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
5576
+ const didRetargetInitialScroll = retargetActiveInitialScrollAtEnd(ctx);
5577
+ if (!didRetargetInitialScroll && wasWithinEndThreshold && (insetDiff > 0)) {
5578
+ requestAdjust(ctx, insetDiff);
5579
+ }
5580
+ }
5581
+ }
5582
+
5342
5583
  // src/core/updateItemSize.ts
5343
5584
  function runOrScheduleMVCPRecalculate(ctx) {
5344
5585
  const state = ctx.state;
@@ -5382,15 +5623,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5382
5623
  const {
5383
5624
  didContainersLayout,
5384
5625
  sizesKnown,
5385
- props: {
5386
- getFixedItemSize,
5387
- getItemType,
5388
- horizontal,
5389
- suggestEstimatedItemSize,
5390
- onItemSizeChanged,
5391
- data,
5392
- maintainScrollAtEnd
5393
- }
5626
+ props: { getFixedItemSize, getItemType, horizontal, onItemSizeChanged, data, maintainScrollAtEnd }
5394
5627
  } = state;
5395
5628
  if (!data) return;
5396
5629
  const index = state.indexByKey.get(itemKey);
@@ -5441,18 +5674,6 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5441
5674
  if (minIndexSizeChanged !== void 0) {
5442
5675
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
5443
5676
  }
5444
- if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
5445
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
5446
- state.timeoutSizeMessage = setTimeout(() => {
5447
- var _a4;
5448
- state.timeoutSizeMessage = void 0;
5449
- const num = state.sizesKnown.size;
5450
- const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
5451
- console.warn(
5452
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
5453
- );
5454
- }, 1e3);
5455
- }
5456
5677
  const cur = peek$(ctx, "otherAxisSize");
5457
5678
  if (!cur || maxOtherAxisSize > cur) {
5458
5679
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
@@ -5557,12 +5778,47 @@ function createColumnWrapperStyle(contentContainerStyle) {
5557
5778
  }
5558
5779
 
5559
5780
  // src/utils/createImperativeHandle.ts
5781
+ var DEFAULT_AVERAGE_ITEM_SIZE_TYPE = "default";
5782
+ function getAverageItemSizes(state) {
5783
+ const averageItemSizes = {};
5784
+ for (const itemType in state.averageSizes) {
5785
+ const averageSize = state.averageSizes[itemType];
5786
+ if (averageSize) {
5787
+ averageItemSizes[itemType || DEFAULT_AVERAGE_ITEM_SIZE_TYPE] = {
5788
+ average: averageSize.avg,
5789
+ count: averageSize.num
5790
+ };
5791
+ }
5792
+ }
5793
+ return averageItemSizes;
5794
+ }
5560
5795
  function createImperativeHandle(ctx) {
5561
5796
  const state = ctx.state;
5562
5797
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
5563
5798
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
5564
5799
  let imperativeScrollToken = 0;
5565
5800
  const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
5801
+ const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
5802
+ var _a3;
5803
+ const props = state.props;
5804
+ const dataLength = props.data.length;
5805
+ const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5806
+ if (targetIndex < 0) {
5807
+ return allowEmpty;
5808
+ }
5809
+ if (targetIndex >= dataLength) {
5810
+ return false;
5811
+ }
5812
+ if (anchorIndex === void 0 || anchorIndex < 0 || anchorIndex >= dataLength || targetIndex < anchorIndex || props.getFixedItemSize) {
5813
+ return true;
5814
+ }
5815
+ for (let index = anchorIndex; index < dataLength; index++) {
5816
+ if (!state.sizesKnown.has(getId(state, index))) {
5817
+ return false;
5818
+ }
5819
+ }
5820
+ return true;
5821
+ };
5566
5822
  const runWhenReady = (token, run, isReady) => {
5567
5823
  const startedAt = Date.now();
5568
5824
  let stableFrames = 0;
@@ -5584,11 +5840,10 @@ function createImperativeHandle(ctx) {
5584
5840
  };
5585
5841
  requestAnimationFrame(check);
5586
5842
  };
5587
- const runScrollWithPromise = (run, options) => new Promise((resolve) => {
5588
- var _a3, _b;
5843
+ const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
5844
+ var _a3;
5589
5845
  const token = ++imperativeScrollToken;
5590
- const isReady = (_a3 = options == null ? void 0 : options.isReady) != null ? _a3 : (() => true);
5591
- (_b = state.pendingScrollResolve) == null ? void 0 : _b.call(state);
5846
+ (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
5592
5847
  state.pendingScrollResolve = resolve;
5593
5848
  const runNow = () => {
5594
5849
  if (token !== imperativeScrollToken) {
@@ -5663,6 +5918,7 @@ function createImperativeHandle(ctx) {
5663
5918
  },
5664
5919
  end: state.endNoBuffer,
5665
5920
  endBuffered: state.endBuffered,
5921
+ getAverageItemSizes: () => getAverageItemSizes(state),
5666
5922
  isAtEnd: peek$(ctx, "isAtEnd"),
5667
5923
  isAtStart: peek$(ctx, "isAtStart"),
5668
5924
  isEndReached: state.isEndReached,
@@ -5686,8 +5942,14 @@ function createImperativeHandle(ctx) {
5686
5942
  startBuffered: state.startBuffered
5687
5943
  }),
5688
5944
  reportContentInset: (inset) => {
5945
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
5946
+ const previousInset = state.contentInsetOverride;
5689
5947
  state.contentInsetOverride = inset != null ? inset : void 0;
5948
+ 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);
5690
5949
  updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
5950
+ if (didChange) {
5951
+ retargetActiveInitialScrollAtEnd(ctx);
5952
+ }
5691
5953
  },
5692
5954
  scrollIndexIntoView: (options) => runScrollWithPromise(() => scrollIndexIntoView(options)),
5693
5955
  scrollItemIntoView: ({ item, ...props }) => runScrollWithPromise(() => {
@@ -5699,40 +5961,34 @@ function createImperativeHandle(ctx) {
5699
5961
  }
5700
5962
  return false;
5701
5963
  }),
5702
- scrollToEnd: (options) => runScrollWithPromise(() => {
5703
- const data = state.props.data;
5704
- const stylePaddingBottom = state.props.stylePaddingBottom;
5705
- const index = data.length - 1;
5706
- if (index !== -1) {
5707
- const paddingBottom = stylePaddingBottom || 0;
5708
- const footerSize = peek$(ctx, "footerSize") || 0;
5709
- scrollToIndex(ctx, {
5710
- ...options,
5711
- index,
5712
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5713
- viewPosition: 1
5714
- });
5715
- return true;
5716
- }
5717
- return false;
5718
- }),
5719
- scrollToIndex: (params) => {
5720
- const shouldWaitForOutOfRangeTarget = params.index >= 0 && params.index >= state.props.data.length;
5721
- const options = shouldWaitForOutOfRangeTarget ? {
5722
- isReady: () => {
5723
- var _a3;
5724
- const props = state.props;
5725
- const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5726
- const lastIndex = props.data.length - 1;
5727
- const isInRange = params.index < props.data.length;
5728
- const shouldWaitForAnchorSize = isInRange && anchorIndex !== void 0 && anchorIndex >= 0 && params.index >= anchorIndex && !props.getFixedItemSize && !state.sizesKnown.has(getId(state, lastIndex));
5729
- return isInRange && !shouldWaitForAnchorSize;
5964
+ scrollToEnd: (options) => runScrollWithPromise(
5965
+ () => {
5966
+ const data = state.props.data;
5967
+ const stylePaddingBottom = state.props.stylePaddingBottom;
5968
+ const index = data.length - 1;
5969
+ if (index !== -1) {
5970
+ const paddingBottom = stylePaddingBottom || 0;
5971
+ const footerSize = peek$(ctx, "footerSize") || 0;
5972
+ scrollToIndex(ctx, {
5973
+ ...options,
5974
+ index,
5975
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5976
+ viewPosition: 1
5977
+ });
5978
+ return true;
5730
5979
  }
5731
- } : void 0;
5732
- return runScrollWithPromise(() => {
5733
- scrollToIndex(ctx, params);
5734
- return true;
5735
- }, options);
5980
+ return false;
5981
+ },
5982
+ () => isScrollToIndexReady(state.props.data.length - 1, true)
5983
+ ),
5984
+ scrollToIndex: (params) => {
5985
+ return runScrollWithPromise(
5986
+ () => {
5987
+ scrollToIndex(ctx, params);
5988
+ return true;
5989
+ },
5990
+ params.index >= 0 ? () => isScrollToIndexReady(params.index) : void 0
5991
+ );
5736
5992
  },
5737
5993
  scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
5738
5994
  const data = state.props.data;
@@ -5988,6 +6244,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5988
6244
  data: dataProp = [],
5989
6245
  dataVersion,
5990
6246
  drawDistance = 250,
6247
+ contentInsetEndAdjustment,
5991
6248
  estimatedItemSize = 100,
5992
6249
  estimatedListSize,
5993
6250
  extraData,
@@ -5995,7 +6252,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5995
6252
  getFixedItemSize,
5996
6253
  getItemType,
5997
6254
  horizontal,
5998
- initialContainerPoolRatio = 2,
6255
+ initialContainerPoolRatio = 3,
5999
6256
  initialScrollAtEnd = false,
6000
6257
  initialScrollIndex: initialScrollIndexProp,
6001
6258
  initialScrollOffset: initialScrollOffsetProp,
@@ -6036,7 +6293,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6036
6293
  stickyIndices: stickyIndicesDeprecated,
6037
6294
  // TODOV3: Remove from v3 release
6038
6295
  style: styleProp,
6039
- suggestEstimatedItemSize,
6040
6296
  useWindowScroll = false,
6041
6297
  viewabilityConfig,
6042
6298
  viewabilityConfigCallbackPairs,
@@ -6097,6 +6353,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6097
6353
  const combinedRef = useCombinedRef(refScroller, refScrollView);
6098
6354
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
6099
6355
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
6356
+ const contentInsetEndAdjustmentResolved = contentInsetEndAdjustment ;
6357
+ const previousContentInsetEndAdjustmentRef = React3.useRef(contentInsetEndAdjustmentResolved);
6100
6358
  const alwaysRenderIndices = React3.useMemo(() => {
6101
6359
  const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor, anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
6102
6360
  return { arr: indices, set: new Set(indices) };
@@ -6175,7 +6433,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6175
6433
  startReachedSnapshotDataChangeEpoch: void 0,
6176
6434
  stickyContainerPool: /* @__PURE__ */ new Set(),
6177
6435
  stickyContainers: /* @__PURE__ */ new Map(),
6178
- timeoutSizeMessage: 0,
6179
6436
  timeouts: /* @__PURE__ */ new Set(),
6180
6437
  totalSize: 0,
6181
6438
  viewabilityConfigCallbackPairs: void 0
@@ -6195,7 +6452,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6195
6452
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
6196
6453
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
6197
6454
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
6198
- if (didDataChangeLocal && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6455
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6199
6456
  clearPreservedInitialScrollTarget(state);
6200
6457
  }
6201
6458
  if (didDataChangeLocal) {
@@ -6216,6 +6473,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6216
6473
  anchoredEndSpace: anchoredEndSpaceResolved,
6217
6474
  animatedProps: animatedPropsInternal,
6218
6475
  contentInset,
6476
+ contentInsetEndAdjustment: contentInsetEndAdjustmentResolved,
6219
6477
  data: dataProp,
6220
6478
  dataVersion,
6221
6479
  drawDistance,
@@ -6249,7 +6507,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6249
6507
  stickyPositionComponentInternal,
6250
6508
  stylePaddingBottom: stylePaddingBottomState,
6251
6509
  stylePaddingTop: stylePaddingTopState,
6252
- suggestEstimatedItemSize: !!suggestEstimatedItemSize,
6253
6510
  useWindowScroll: useWindowScrollResolved
6254
6511
  };
6255
6512
  state.refScroller = refScroller;
@@ -6333,6 +6590,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6333
6590
  didAnchoredEndSpaceAnchorIndexChange,
6334
6591
  numColumnsProp
6335
6592
  ]);
6593
+ React3.useLayoutEffect(() => {
6594
+ const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
6595
+ previousContentInsetEndAdjustmentRef.current = contentInsetEndAdjustmentResolved;
6596
+ updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment);
6597
+ }, [ctx, contentInsetEndAdjustmentResolved]);
6336
6598
  const onLayoutFooter = React3.useCallback(
6337
6599
  (layout) => {
6338
6600
  if (!usesBootstrapInitialScroll) {