@legendapp/list 3.0.0-beta.53 → 3.0.0-beta.55

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.
@@ -13,6 +13,115 @@ var View = forwardRef(function View2(props, ref) {
13
13
  });
14
14
  var Text = View;
15
15
 
16
+ // src/platform/Platform.ts
17
+ var Platform = {
18
+ // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
19
+ OS: "web"
20
+ };
21
+
22
+ // src/utils/rtl.ts
23
+ function clampHorizontalOffset(offset, maxOffset) {
24
+ if (maxOffset === void 0) {
25
+ return offset;
26
+ }
27
+ return Math.max(0, Math.min(maxOffset, offset));
28
+ }
29
+ function getHorizontalMaxOffset(state, contentWidth) {
30
+ if (contentWidth === void 0 || !Number.isFinite(contentWidth) || !Number.isFinite(state.scrollLength) || contentWidth <= state.scrollLength) {
31
+ return contentWidth !== void 0 && Number.isFinite(contentWidth) && Number.isFinite(state.scrollLength) ? 0 : void 0;
32
+ }
33
+ return Math.max(0, contentWidth - state.scrollLength);
34
+ }
35
+ function getDefaultHorizontalRTLScrollType() {
36
+ return "normal" ;
37
+ }
38
+ function getNativeHorizontalRTLScrollType(state) {
39
+ var _a3;
40
+ return (_a3 = state == null ? void 0 : state.horizontalRTLScrollType) != null ? _a3 : getDefaultHorizontalRTLScrollType();
41
+ }
42
+ function isRTLProps(props) {
43
+ var _a3;
44
+ return (_a3 = props == null ? void 0 : props.rtl) != null ? _a3 : false;
45
+ }
46
+ function isHorizontalRTL(state) {
47
+ return isHorizontalRTLProps(state == null ? void 0 : state.props);
48
+ }
49
+ function isHorizontalRTLProps(props) {
50
+ return !!(props == null ? void 0 : props.horizontal) && isRTLProps(props);
51
+ }
52
+ function getLogicalHorizontalMaxOffset(state, contentWidth) {
53
+ var _a3;
54
+ return (_a3 = getHorizontalMaxOffset(state, contentWidth)) != null ? _a3 : 0;
55
+ }
56
+ function getHorizontalInsetEnd(state, inset) {
57
+ if (!inset) {
58
+ return 0;
59
+ }
60
+ return (isHorizontalRTL(state) ? inset.left : inset.right) || 0;
61
+ }
62
+ function toPhysicalHorizontalItemPosition(state, logicalPosition, itemSize, listSize) {
63
+ if (!isHorizontalRTL(state) || listSize === void 0 || !Number.isFinite(listSize)) {
64
+ return logicalPosition;
65
+ }
66
+ return Math.max(0, listSize - logicalPosition - itemSize);
67
+ }
68
+ function toNativeHorizontalOffset(state, logicalOffset, contentWidth) {
69
+ if (!state || !isHorizontalRTL(state)) {
70
+ return logicalOffset;
71
+ }
72
+ const maxOffset = getHorizontalMaxOffset(state, contentWidth);
73
+ const clampedLogicalOffset = clampHorizontalOffset(logicalOffset, maxOffset);
74
+ const mode = getNativeHorizontalRTLScrollType(state);
75
+ if (mode === "negative") {
76
+ return clampedLogicalOffset === 0 ? 0 : -clampedLogicalOffset;
77
+ }
78
+ if (mode === "inverted") {
79
+ if (maxOffset === void 0) {
80
+ return clampedLogicalOffset;
81
+ }
82
+ return clampHorizontalOffset(maxOffset - clampedLogicalOffset, maxOffset);
83
+ }
84
+ return clampedLogicalOffset;
85
+ }
86
+ function toLogicalHorizontalOffset(state, rawOffset, contentWidth) {
87
+ if (!isHorizontalRTL(state)) {
88
+ state.horizontalRTLScrollType = void 0;
89
+ return rawOffset;
90
+ }
91
+ const maxOffset = getHorizontalMaxOffset(state, contentWidth);
92
+ if (rawOffset < 0) {
93
+ state.horizontalRTLScrollType = "negative";
94
+ return clampHorizontalOffset(-rawOffset, maxOffset);
95
+ }
96
+ if (maxOffset === void 0) {
97
+ return rawOffset;
98
+ }
99
+ const normalOffset = rawOffset;
100
+ const invertedOffset = maxOffset - rawOffset;
101
+ if (!Number.isFinite(invertedOffset)) {
102
+ state.horizontalRTLScrollType = "normal";
103
+ return normalOffset;
104
+ }
105
+ const previousMode = state.horizontalRTLScrollType;
106
+ if (previousMode === "inverted") {
107
+ return clampHorizontalOffset(invertedOffset, maxOffset);
108
+ }
109
+ if (previousMode === "normal") {
110
+ return clampHorizontalOffset(normalOffset, maxOffset);
111
+ }
112
+ if (!state.hasScrolled) {
113
+ const defaultMode = getDefaultHorizontalRTLScrollType();
114
+ state.horizontalRTLScrollType = defaultMode;
115
+ return clampHorizontalOffset(normalOffset, maxOffset);
116
+ }
117
+ const referenceScroll = state.scroll;
118
+ const distanceNormal = Math.abs(normalOffset - referenceScroll);
119
+ const distanceInverted = Math.abs(invertedOffset - referenceScroll);
120
+ const useInverted = distanceInverted + 0.5 < distanceNormal;
121
+ state.horizontalRTLScrollType = useInverted ? "inverted" : "normal";
122
+ return clampHorizontalOffset(useInverted ? invertedOffset : normalOffset, maxOffset);
123
+ }
124
+
16
125
  // src/platform/Animated.tsx
17
126
  var createAnimatedValue = (value) => value;
18
127
 
@@ -155,7 +264,7 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
155
264
  const horizontal = props.horizontal;
156
265
  const contentInset = props.contentInset;
157
266
  const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
158
- const baseEndInset = (horizontal ? baseInset == null ? void 0 : baseInset.right : baseInset == null ? void 0 : baseInset.bottom) || 0;
267
+ const baseEndInset = (horizontal ? getHorizontalInsetEnd(state, baseInset) : baseInset == null ? void 0 : baseInset.bottom) || 0;
159
268
  const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd(
160
269
  contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
161
270
  );
@@ -164,9 +273,9 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
164
273
  const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
165
274
  const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
166
275
  if (overrideInset) {
167
- const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
276
+ const mergedInset = { bottom: 0, left: 0, right: 0, ...baseInset, ...overrideInset };
168
277
  return Math.max(
169
- ((horizontal ? mergedInset.right : mergedInset.bottom) || 0) + contentInsetEndAdjustment,
278
+ ((horizontal ? getHorizontalInsetEnd(state, mergedInset) : mergedInset.bottom) || 0) + contentInsetEndAdjustment,
170
279
  anchoredEndInset
171
280
  );
172
281
  }
@@ -260,6 +369,15 @@ var ENABLE_DEVMODE = IS_DEV && false;
260
369
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
261
370
  var typedForwardRef = React3.forwardRef;
262
371
  var typedMemo = React3.memo;
372
+ var getComponent = (Component) => {
373
+ if (React3.isValidElement(Component)) {
374
+ return Component;
375
+ }
376
+ if (Component) {
377
+ return /* @__PURE__ */ React3.createElement(Component, null);
378
+ }
379
+ return null;
380
+ };
263
381
 
264
382
  // src/utils/helpers.ts
265
383
  function isFunction(obj) {
@@ -286,7 +404,8 @@ function comparatorDefault(a, b) {
286
404
  }
287
405
  function getPadding(s, type) {
288
406
  var _a3, _b, _c;
289
- return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
407
+ const axisPadding = type === "Left" || type === "Right" ? s.paddingHorizontal : s.paddingVertical;
408
+ return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : axisPadding) != null ? _b : s.padding) != null ? _c : 0;
290
409
  }
291
410
  function extractPadding(style, contentContainerStyle, type) {
292
411
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
@@ -308,6 +427,14 @@ function findContainerId(ctx, key) {
308
427
  }
309
428
 
310
429
  // src/components/PositionView.tsx
430
+ var isRNWeb = typeof document !== "undefined" && !!document.getElementById("react-native-stylesheet");
431
+ var baseCss = {
432
+ contain: "paint layout style",
433
+ ...isRNWeb ? {
434
+ display: "flex",
435
+ flexDirection: "column"
436
+ } : {}
437
+ };
311
438
  var PositionViewState = typedMemo(function PositionViewState2({
312
439
  id,
313
440
  horizontal,
@@ -316,11 +443,8 @@ var PositionViewState = typedMemo(function PositionViewState2({
316
443
  ...props
317
444
  }) {
318
445
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
319
- const base = {
320
- contain: "paint layout style"
321
- };
322
446
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
323
- const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
447
+ const combinedStyle = horizontal ? { ...baseCss, ...composed, left: position } : { ...baseCss, ...composed, top: position };
324
448
  const {
325
449
  animatedScrollY: _animatedScrollY,
326
450
  index,
@@ -348,9 +472,6 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
348
472
  `containerPosition${id}`,
349
473
  "activeStickyIndex"
350
474
  ]);
351
- const base = {
352
- contain: "paint layout style"
353
- };
354
475
  const composed = React3.useMemo(
355
476
  () => {
356
477
  var _a3;
@@ -360,10 +481,9 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
360
481
  );
361
482
  const viewStyle = React3.useMemo(() => {
362
483
  var _a3;
363
- const styleBase = { ...base, ...composed };
484
+ const styleBase = { ...baseCss, ...composed };
364
485
  delete styleBase.transform;
365
- const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
366
- const offset = stickyConfigOffset != null ? stickyConfigOffset : 0;
486
+ const offset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
367
487
  const isActive = activeStickyIndex === index;
368
488
  styleBase.position = isActive ? "sticky" : "absolute";
369
489
  styleBase.zIndex = index + 1e3;
@@ -374,6 +494,20 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
374
494
  }
375
495
  return styleBase;
376
496
  }, [composed, horizontal, position, index, activeStickyIndex, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
497
+ const renderStickyHeaderBackdrop = React3.useMemo(
498
+ () => (stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent) ? /* @__PURE__ */ React3.createElement(
499
+ "div",
500
+ {
501
+ style: {
502
+ inset: 0,
503
+ pointerEvents: "none",
504
+ position: "absolute"
505
+ }
506
+ },
507
+ getComponent(stickyHeaderConfig.backdropComponent)
508
+ ) : null,
509
+ [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]
510
+ );
377
511
  return /* @__PURE__ */ React3.createElement(
378
512
  "div",
379
513
  {
@@ -382,6 +516,7 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
382
516
  style: viewStyle,
383
517
  ...webProps
384
518
  },
519
+ renderStickyHeaderBackdrop,
385
520
  children
386
521
  );
387
522
  });
@@ -646,12 +781,6 @@ function toLayout(rect) {
646
781
  };
647
782
  }
648
783
 
649
- // src/platform/Platform.ts
650
- var Platform = {
651
- // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
652
- OS: "web"
653
- };
654
-
655
784
  // src/utils/hasActiveMVCPAnchorLock.ts
656
785
  function hasActiveMVCPAnchorLock(state) {
657
786
  const lock = state.mvcpAnchorLock;
@@ -675,6 +804,7 @@ function getContainerPositionStyle({
675
804
  columnWrapperStyle,
676
805
  horizontal,
677
806
  hasItemSeparator,
807
+ isHorizontalRTLList,
678
808
  numColumns,
679
809
  otherAxisPos,
680
810
  otherAxisSize
@@ -698,6 +828,7 @@ function getContainerPositionStyle({
698
828
  }
699
829
  return horizontal ? {
700
830
  boxSizing: paddingStyles ? "border-box" : void 0,
831
+ direction: isHorizontalRTLList && Platform.OS === "web" ? "ltr" : void 0,
701
832
  flexDirection: hasItemSeparator ? "row" : void 0,
702
833
  height: otherAxisSize,
703
834
  left: 0,
@@ -716,6 +847,7 @@ function getContainerPositionStyle({
716
847
  }
717
848
  var Container = typedMemo(function Container2({
718
849
  id,
850
+ itemKey,
719
851
  recycleItems,
720
852
  horizontal,
721
853
  getRenderedItem: getRenderedItem2,
@@ -725,13 +857,13 @@ var Container = typedMemo(function Container2({
725
857
  }) {
726
858
  const ctx = useStateContext();
727
859
  const { columnWrapperStyle, animatedScrollY } = ctx;
860
+ const isHorizontalRTLList = isHorizontalRTL(ctx.state);
728
861
  const positionComponentInternal = ctx.state.props.positionComponentInternal;
729
862
  const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
730
- const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
863
+ const [column = 0, span = 1, data, numColumns = 1, extraData, isSticky] = useArr$([
731
864
  `containerColumn${id}`,
732
865
  `containerSpan${id}`,
733
866
  `containerItemData${id}`,
734
- `containerItemKey${id}`,
735
867
  "numColumns",
736
868
  "extraData",
737
869
  `containerSticky${id}`
@@ -757,11 +889,20 @@ var Container = typedMemo(function Container2({
757
889
  columnWrapperStyle,
758
890
  hasItemSeparator: !!ItemSeparatorComponent,
759
891
  horizontal,
892
+ isHorizontalRTLList,
760
893
  numColumns,
761
894
  otherAxisPos,
762
895
  otherAxisSize
763
896
  }),
764
- [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns, ItemSeparatorComponent]
897
+ [
898
+ horizontal,
899
+ isHorizontalRTLList,
900
+ otherAxisPos,
901
+ otherAxisSize,
902
+ columnWrapperStyle,
903
+ numColumns,
904
+ ItemSeparatorComponent
905
+ ]
765
906
  );
766
907
  const renderedItemInfo = useMemo(
767
908
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
@@ -849,6 +990,39 @@ var Container = typedMemo(function Container2({
849
990
  );
850
991
  });
851
992
 
993
+ // src/components/ContainerSlot.tsx
994
+ function ContainerSlotBase({
995
+ id,
996
+ horizontal,
997
+ recycleItems,
998
+ ItemSeparatorComponent,
999
+ updateItemSize: updateItemSize2,
1000
+ getRenderedItem: getRenderedItem2,
1001
+ stickyHeaderConfig,
1002
+ ContainerComponent = Container
1003
+ }) {
1004
+ const [itemKey] = useArr$([`containerItemKey${id}`]);
1005
+ if (itemKey === void 0) {
1006
+ return null;
1007
+ }
1008
+ return /* @__PURE__ */ React3.createElement(
1009
+ ContainerComponent,
1010
+ {
1011
+ getRenderedItem: getRenderedItem2,
1012
+ horizontal,
1013
+ ItemSeparatorComponent,
1014
+ id,
1015
+ itemKey,
1016
+ recycleItems,
1017
+ stickyHeaderConfig,
1018
+ updateItemSize: updateItemSize2
1019
+ }
1020
+ );
1021
+ }
1022
+ var ContainerSlot = typedMemo(function ContainerSlot2(props) {
1023
+ return /* @__PURE__ */ React3.createElement(ContainerSlotBase, { ...props });
1024
+ });
1025
+
852
1026
  // src/utils/reordering.ts
853
1027
  var mapFn = (element) => {
854
1028
  const indexStr = element.getAttribute("data-index");
@@ -968,9 +1142,19 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
968
1142
  const ref = useRef(null);
969
1143
  const ctx = useStateContext();
970
1144
  const columnWrapperStyle = ctx.columnWrapperStyle;
971
- const [otherAxisSize, totalSize] = useArr$(["otherAxisSize", "totalSize"]);
1145
+ const isHorizontalRTLList = isHorizontalRTL(ctx.state);
1146
+ const [otherAxisSize, readyToRender, totalSize] = useArr$(["otherAxisSize", "readyToRender", "totalSize"]);
972
1147
  useDOMOrder(ref);
973
- const style = horizontal ? { minHeight: otherAxisSize, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, position: "relative" };
1148
+ const style = horizontal ? {
1149
+ direction: isHorizontalRTLList ? "ltr" : void 0,
1150
+ minHeight: otherAxisSize,
1151
+ opacity: readyToRender ? 1 : 0,
1152
+ position: "relative",
1153
+ width: totalSize
1154
+ } : { height: totalSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative" };
1155
+ if (!readyToRender) {
1156
+ style.pointerEvents = "none";
1157
+ }
974
1158
  if (columnWrapperStyle && numColumns > 1) {
975
1159
  const { columnGap, rowGap, gap } = columnWrapperStyle;
976
1160
  const gapX = columnGap || gap || 0;
@@ -998,12 +1182,12 @@ var Containers = typedMemo(function Containers2({
998
1182
  getRenderedItem: getRenderedItem2,
999
1183
  stickyHeaderConfig
1000
1184
  }) {
1001
- const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
1185
+ const [numContainersPooled, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
1002
1186
  const containers = [];
1003
- for (let i = 0; i < numContainers; i++) {
1187
+ for (let i = 0; i < numContainersPooled; i++) {
1004
1188
  containers.push(
1005
1189
  /* @__PURE__ */ React3.createElement(
1006
- Container,
1190
+ ContainerSlot,
1007
1191
  {
1008
1192
  getRenderedItem: getRenderedItem2,
1009
1193
  horizontal,
@@ -1075,6 +1259,8 @@ function useRafCoalescer(callback) {
1075
1259
 
1076
1260
  // src/components/webConstants.ts
1077
1261
  var LEGEND_LIST_CONTENT_CONTAINER_CLASS = "legend-list-content-container";
1262
+ var LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS = "legend-list-scrollbar-x-hidden";
1263
+ var LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS = "legend-list-scrollbar-y-hidden";
1078
1264
 
1079
1265
  // src/components/webScrollUtils.ts
1080
1266
  function getDocumentScrollerNode() {
@@ -1160,11 +1346,47 @@ function resolveWindowScrollTarget({ clampedOffset, horizontal, listPos, scroll
1160
1346
  }
1161
1347
 
1162
1348
  // src/components/ListComponentScrollView.tsx
1349
+ var SCROLLBAR_HIDDEN_STYLE_ID = "legend-list-scrollbar-axis-hidden-style";
1350
+ 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;}`;
1351
+ function ensureScrollbarHiddenStyle() {
1352
+ if (typeof document === "undefined" || document.getElementById(SCROLLBAR_HIDDEN_STYLE_ID)) {
1353
+ return;
1354
+ }
1355
+ const styleElement = document.createElement("style");
1356
+ styleElement.id = SCROLLBAR_HIDDEN_STYLE_ID;
1357
+ styleElement.textContent = SCROLLBAR_HIDDEN_STYLE;
1358
+ document.head.appendChild(styleElement);
1359
+ }
1163
1360
  function getContentInsetEndAdjustmentEnd2(ctx) {
1164
1361
  var _a3, _b;
1165
1362
  const adjustment = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.contentInsetEndAdjustment;
1166
1363
  return Math.max(0, adjustment != null ? adjustment : 0);
1167
1364
  }
1365
+ function getFiniteSnapOffsets(snapToOffsets) {
1366
+ if (!(snapToOffsets == null ? void 0 : snapToOffsets.length)) {
1367
+ return [];
1368
+ }
1369
+ const snapOffsets = [];
1370
+ const seen = /* @__PURE__ */ new Set();
1371
+ for (const offset of snapToOffsets) {
1372
+ if (Number.isFinite(offset) && !seen.has(offset)) {
1373
+ seen.add(offset);
1374
+ snapOffsets.push(offset);
1375
+ }
1376
+ }
1377
+ return snapOffsets;
1378
+ }
1379
+ function getSnapAnchorStyle(offset, horizontal) {
1380
+ return {
1381
+ height: horizontal ? "100%" : 1,
1382
+ left: horizontal ? offset : 0,
1383
+ pointerEvents: "none",
1384
+ position: "absolute",
1385
+ scrollSnapAlign: "start",
1386
+ top: horizontal ? 0 : offset,
1387
+ width: horizontal ? 1 : "100%"
1388
+ };
1389
+ }
1168
1390
  var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1169
1391
  children,
1170
1392
  style,
@@ -1182,7 +1404,7 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1182
1404
  onLayout,
1183
1405
  ...props
1184
1406
  }, ref) {
1185
- var _a3, _b, _c;
1407
+ var _a3, _b, _c, _d;
1186
1408
  const ctx = useStateContext();
1187
1409
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
1188
1410
  const scrollRef = useRef(null);
@@ -1364,6 +1586,12 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1364
1586
  }
1365
1587
  };
1366
1588
  }, [isWindowScroll, onLayout]);
1589
+ const hiddenScrollIndicatorClassName = !isWindowScroll && (horizontal ? !showsHorizontalScrollIndicator && LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS : !showsVerticalScrollIndicator && LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS);
1590
+ useLayoutEffect(() => {
1591
+ if (hiddenScrollIndicatorClassName) {
1592
+ ensureScrollbarHiddenStyle();
1593
+ }
1594
+ }, [hiddenScrollIndicatorClassName]);
1367
1595
  const scrollViewStyle = {
1368
1596
  ...isWindowScroll ? {} : {
1369
1597
  overflow: "auto",
@@ -1391,11 +1619,59 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1391
1619
  contentInset: _contentInset,
1392
1620
  scrollEventThrottle: _scrollEventThrottle,
1393
1621
  ScrollComponent: _ScrollComponent,
1622
+ snapToOffsets,
1394
1623
  useWindowScroll: _useWindowScroll,
1624
+ className: scrollViewClassNameProp,
1395
1625
  ...webProps
1396
1626
  } = props;
1397
- return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3.createElement("div", { className, ref: contentRef, style: contentStyle }, children, contentInsetEndAdjustmentSpacerStyle ? /* @__PURE__ */ React3.createElement("div", { "aria-hidden": true, style: contentInsetEndAdjustmentSpacerStyle }) : null));
1627
+ const snapOffsets = !isWindowScroll ? getFiniteSnapOffsets(snapToOffsets) : [];
1628
+ if (snapOffsets.length > 0) {
1629
+ scrollViewStyle.scrollSnapType = horizontal ? "x mandatory" : "y mandatory";
1630
+ contentStyle.position = (_d = contentStyle.position) != null ? _d : "relative";
1631
+ }
1632
+ const scrollViewClassName = hiddenScrollIndicatorClassName ? scrollViewClassNameProp ? `${scrollViewClassNameProp} ${hiddenScrollIndicatorClassName}` : hiddenScrollIndicatorClassName : scrollViewClassNameProp;
1633
+ if (IS_DEV) {
1634
+ if (/(?:^|\s)(?:[a-z0-9_-]+:)*gap(?:-[xy])?-(?:\[[^\]]+\]|[^\s]+)/.test(
1635
+ `${contentContainerClassName != null ? contentContainerClassName : ""} ${scrollViewClassNameProp != null ? scrollViewClassNameProp : ""}`
1636
+ )) {
1637
+ warnDevOnce(
1638
+ "className-gap",
1639
+ "className/contentContainerClassName gap classes are not supported in LegendList because it needs to use exact values internally. Use contentContainerStyle={{ gap: ... }} or columnWrapperStyle instead."
1640
+ );
1641
+ }
1642
+ }
1643
+ return /* @__PURE__ */ React3.createElement(
1644
+ "div",
1645
+ {
1646
+ className: scrollViewClassName,
1647
+ ref: scrollRef,
1648
+ ...webProps,
1649
+ style: scrollViewStyle
1650
+ },
1651
+ refreshControl,
1652
+ /* @__PURE__ */ React3.createElement("div", { className, ref: contentRef, style: contentStyle }, snapOffsets.map((offset) => /* @__PURE__ */ React3.createElement(
1653
+ "div",
1654
+ {
1655
+ "aria-hidden": true,
1656
+ "data-legend-list-snap-anchor": offset,
1657
+ key: `snap-${offset}`,
1658
+ style: getSnapAnchorStyle(offset, horizontal)
1659
+ }
1660
+ )), children, contentInsetEndAdjustmentSpacerStyle ? /* @__PURE__ */ React3.createElement("div", { "aria-hidden": true, style: contentInsetEndAdjustmentSpacerStyle }) : null)
1661
+ );
1398
1662
  });
1663
+
1664
+ // src/components/listComponentStyles.ts
1665
+ function getAutoOtherAxisStyle({
1666
+ horizontal,
1667
+ needsOtherAxisSize,
1668
+ otherAxisSize
1669
+ }) {
1670
+ if (!needsOtherAxisSize || !otherAxisSize || otherAxisSize <= 0) {
1671
+ return void 0;
1672
+ }
1673
+ return horizontal ? { height: otherAxisSize } : { width: otherAxisSize };
1674
+ }
1399
1675
  function useValueListener$(key, callback) {
1400
1676
  const ctx = useStateContext();
1401
1677
  useLayoutEffect(() => {
@@ -1422,11 +1698,18 @@ function getScrollAdjustAxis(horizontal) {
1422
1698
  y: 1
1423
1699
  };
1424
1700
  }
1425
- function resolveScrollAdjustContentNode(el, contentNode) {
1426
- if ((contentNode == null ? void 0 : contentNode.isConnected) && contentNode.parentElement === el) {
1427
- return contentNode;
1701
+ function getScrollAdjustTarget(ctx, contentNode) {
1702
+ var _a3, _b, _c;
1703
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1704
+ const scrollElement = (_c = (_b = scrollView == null ? void 0 : scrollView.getScrollableNode) == null ? void 0 : _b.call(scrollView)) != null ? _c : null;
1705
+ let resolvedContentNode = null;
1706
+ if (scrollElement) {
1707
+ resolvedContentNode = (contentNode == null ? void 0 : contentNode.isConnected) && contentNode.parentElement === scrollElement ? contentNode : scrollElement.querySelector(`:scope > .${LEGEND_LIST_CONTENT_CONTAINER_CLASS}`);
1428
1708
  }
1429
- return el.querySelector(`:scope > .${LEGEND_LIST_CONTENT_CONTAINER_CLASS}`);
1709
+ return scrollElement ? { contentNode: resolvedContentNode, scrollElement } : null;
1710
+ }
1711
+ function scrollAdjustBy(el, left, top) {
1712
+ el.scrollBy({ behavior: "auto", left, top });
1430
1713
  }
1431
1714
  function ScrollAdjust() {
1432
1715
  const ctx = useStateContext();
@@ -1435,43 +1718,43 @@ function ScrollAdjust() {
1435
1718
  const resetPaddingBaselineRef = React3.useRef(void 0);
1436
1719
  const contentNodeRef = React3.useRef(null);
1437
1720
  const callback = React3.useCallback(() => {
1438
- var _a3, _b;
1721
+ var _a3;
1439
1722
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1440
1723
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1441
1724
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1442
- const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1443
- if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1444
- const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1445
- if (scrollDelta !== 0) {
1446
- const axis = getScrollAdjustAxis(!!ctx.state.props.horizontal);
1447
- const prevScroll = scrollView.getCurrentScrollOffset();
1448
- const el = scrollView.getScrollableNode();
1449
- const contentNode = resolveScrollAdjustContentNode(el, contentNodeRef.current);
1725
+ const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1726
+ if (scrollDelta !== 0) {
1727
+ const target = getScrollAdjustTarget(ctx, contentNodeRef.current);
1728
+ if (target) {
1729
+ const horizontal = !!ctx.state.props.horizontal;
1730
+ const axis = getScrollAdjustAxis(horizontal);
1731
+ const { contentNode, scrollElement: el } = target;
1732
+ const scrollBy = () => scrollAdjustBy(el, axis.x * scrollDelta, axis.y * scrollDelta);
1450
1733
  contentNodeRef.current = contentNode;
1451
- const scrollBy = () => scrollView.scrollBy(axis.x * scrollDelta, axis.y * scrollDelta);
1452
- if (!contentNode) {
1453
- scrollBy();
1454
- lastScrollOffsetRef.current = scrollOffset;
1455
- return;
1456
- }
1457
- const totalSize = contentNode[axis.contentSizeKey];
1458
- const viewportSize = el[axis.viewportSizeKey];
1459
- const nextScroll = prevScroll + scrollDelta;
1460
- if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize) {
1461
- const previousPaddingEnd = (_b = resetPaddingBaselineRef.current) != null ? _b : contentNode.style[axis.paddingEndProp];
1462
- resetPaddingBaselineRef.current = previousPaddingEnd;
1463
- const pad = (nextScroll + viewportSize - totalSize) * 2;
1464
- contentNode.style[axis.paddingEndProp] = `${pad}px`;
1465
- void contentNode.offsetHeight;
1466
- scrollBy();
1467
- if (resetPaddingRafRef.current !== void 0) {
1468
- cancelAnimationFrame(resetPaddingRafRef.current);
1734
+ if (contentNode) {
1735
+ const prevScroll = horizontal ? el.scrollLeft : el.scrollTop;
1736
+ const totalSize = contentNode[axis.contentSizeKey];
1737
+ const viewportSize = el[axis.viewportSizeKey];
1738
+ const nextScroll = prevScroll + scrollDelta;
1739
+ const needsTemporaryPadding = scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize;
1740
+ if (needsTemporaryPadding) {
1741
+ const previousPaddingEnd = (_a3 = resetPaddingBaselineRef.current) != null ? _a3 : contentNode.style[axis.paddingEndProp];
1742
+ resetPaddingBaselineRef.current = previousPaddingEnd;
1743
+ const pad = (nextScroll + viewportSize - totalSize) * 2;
1744
+ contentNode.style[axis.paddingEndProp] = `${pad}px`;
1745
+ void contentNode.offsetHeight;
1746
+ scrollBy();
1747
+ if (resetPaddingRafRef.current !== void 0) {
1748
+ cancelAnimationFrame(resetPaddingRafRef.current);
1749
+ }
1750
+ resetPaddingRafRef.current = requestAnimationFrame(() => {
1751
+ resetPaddingRafRef.current = void 0;
1752
+ resetPaddingBaselineRef.current = void 0;
1753
+ contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1754
+ });
1755
+ } else {
1756
+ scrollBy();
1469
1757
  }
1470
- resetPaddingRafRef.current = requestAnimationFrame(() => {
1471
- resetPaddingRafRef.current = void 0;
1472
- resetPaddingBaselineRef.current = void 0;
1473
- contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1474
- });
1475
1758
  } else {
1476
1759
  scrollBy();
1477
1760
  }
@@ -1483,10 +1766,10 @@ function ScrollAdjust() {
1483
1766
  useValueListener$("scrollAdjustUserOffset", callback);
1484
1767
  return null;
1485
1768
  }
1486
- function SnapWrapper({ ScrollComponent, ...props }) {
1769
+ var SnapWrapper = React3.forwardRef(function SnapWrapperInner({ ScrollComponent, ...props }, ref) {
1487
1770
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
1488
- return /* @__PURE__ */ React3.createElement(ScrollComponent, { ...props, snapToOffsets });
1489
- }
1771
+ return /* @__PURE__ */ React3.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
1772
+ });
1490
1773
  function WebAnchoredEndSpace({ horizontal }) {
1491
1774
  const ctx = useStateContext();
1492
1775
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
@@ -1503,15 +1786,6 @@ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1503
1786
  useOnLayoutSync({ onLayoutChange, ref });
1504
1787
  return /* @__PURE__ */ React3.createElement("div", { ...rest, ref }, children);
1505
1788
  };
1506
- var getComponent = (Component) => {
1507
- if (React3.isValidElement(Component)) {
1508
- return Component;
1509
- }
1510
- if (Component) {
1511
- return /* @__PURE__ */ React3.createElement(Component, null);
1512
- }
1513
- return null;
1514
- };
1515
1789
 
1516
1790
  // src/components/ListComponent.tsx
1517
1791
  var ListComponent = typedMemo(function ListComponent2({
@@ -1544,6 +1818,12 @@ var ListComponent = typedMemo(function ListComponent2({
1544
1818
  }) {
1545
1819
  const ctx = useStateContext();
1546
1820
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1821
+ const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
1822
+ const autoOtherAxisStyle = getAutoOtherAxisStyle({
1823
+ horizontal,
1824
+ needsOtherAxisSize: ctx.state.needsOtherAxisSize,
1825
+ otherAxisSize
1826
+ });
1547
1827
  const ScrollComponent = useMemo(() => {
1548
1828
  if (!renderScrollComponent) {
1549
1829
  return ListComponentScrollView;
@@ -1582,10 +1862,10 @@ var ListComponent = typedMemo(function ListComponent2({
1582
1862
  ...rest,
1583
1863
  ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1584
1864
  contentContainerStyle: [
1585
- contentContainerStyle,
1586
1865
  horizontal ? {
1587
1866
  height: "100%"
1588
- } : {}
1867
+ } : {},
1868
+ contentContainerStyle
1589
1869
  ],
1590
1870
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1591
1871
  horizontal,
@@ -1594,7 +1874,7 @@ var ListComponent = typedMemo(function ListComponent2({
1594
1874
  onScroll: onScroll2,
1595
1875
  ref: refScrollView,
1596
1876
  ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1597
- style
1877
+ style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
1598
1878
  },
1599
1879
  /* @__PURE__ */ React3.createElement(ScrollAdjust, null),
1600
1880
  ListHeaderComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
@@ -1782,10 +2062,9 @@ var initialScrollWatchdog = {
1782
2062
  clear(state) {
1783
2063
  initialScrollWatchdog.set(state, void 0);
1784
2064
  },
1785
- didObserveProgress(newScroll, watchdog) {
1786
- const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
2065
+ didReachTarget(newScroll, watchdog) {
1787
2066
  const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
1788
- return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET || nextDistance + INITIAL_SCROLL_MIN_TARGET_OFFSET < previousDistance;
2067
+ return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET;
1789
2068
  },
1790
2069
  get(state) {
1791
2070
  var _a3, _b;
@@ -1810,19 +2089,19 @@ var initialScrollWatchdog = {
1810
2089
  }
1811
2090
  };
1812
2091
  function setInitialScrollSession(state, options = {}) {
1813
- var _a3, _b, _c;
2092
+ var _a3, _b, _c, _d;
1814
2093
  const existingSession = state.initialScrollSession;
1815
2094
  const kind = (_a3 = options.kind) != null ? _a3 : existingSession == null ? void 0 : existingSession.kind;
1816
2095
  const completion = existingSession == null ? void 0 : existingSession.completion;
1817
- const hasBootstrapOverride = Object.hasOwn(options, "bootstrap");
1818
- const bootstrap = kind === "bootstrap" ? hasBootstrapOverride ? options.bootstrap : (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0 : void 0;
2096
+ const existingBootstrap = (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0;
2097
+ const bootstrap = kind === "bootstrap" ? options.bootstrap === null ? void 0 : (_b = options.bootstrap) != null ? _b : existingBootstrap : void 0;
1819
2098
  if (!kind) {
1820
2099
  return clearInitialScrollSession(state);
1821
2100
  }
1822
2101
  if (!state.initialScroll && !bootstrap && !hasInitialScrollSessionCompletion(completion)) {
1823
2102
  return clearInitialScrollSession(state);
1824
2103
  }
1825
- const previousDataLength = (_c = (_b = options.previousDataLength) != null ? _b : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _c : 0;
2104
+ const previousDataLength = (_d = (_c = options.previousDataLength) != null ? _c : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _d : 0;
1826
2105
  state.initialScrollSession = createInitialScrollSession({
1827
2106
  bootstrap,
1828
2107
  completion,
@@ -2312,7 +2591,8 @@ function doScrollTo(ctx, params) {
2312
2591
  }
2313
2592
  const isAnimated = !!animated;
2314
2593
  const isHorizontal = !!horizontal;
2315
- const left = isHorizontal ? offset : 0;
2594
+ const contentSize = isHorizontal ? getContentSize(ctx) : void 0;
2595
+ const left = isHorizontal ? toNativeHorizontalOffset(state, offset, contentSize) : 0;
2316
2596
  const top = isHorizontal ? 0 : offset;
2317
2597
  scroller.scrollTo({ animated: isAnimated, x: left, y: top });
2318
2598
  if (isAnimated) {
@@ -2574,7 +2854,7 @@ function advanceMeasuredInitialScroll(ctx, options) {
2574
2854
  const activeInitialTargetOffset = scrollingTo ? (_a3 = scrollingTo.targetOffset) != null ? _a3 : scrollingTo.offset : void 0;
2575
2855
  const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - resolvedOffset) > 1;
2576
2856
  const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - resolvedOffset) > 1;
2577
- const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - activeInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - activeInitialTargetOffset) <= 1;
2857
+ const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - resolvedOffset) <= 1 && Math.abs(state.scrollPending - resolvedOffset) <= 1;
2578
2858
  if (!(options == null ? void 0 : options.forceScroll) && !didOffsetChange && isInitialScrollInProgress && !didActiveInitialTargetChange) {
2579
2859
  return false;
2580
2860
  }
@@ -2646,6 +2926,30 @@ function checkAllSizesKnown(state, indices) {
2646
2926
  });
2647
2927
  }
2648
2928
 
2929
+ // src/utils/requestAdjust.ts
2930
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2931
+ const state = ctx.state;
2932
+ if (Math.abs(positionDiff) > 0.1) {
2933
+ const doit = () => {
2934
+ {
2935
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
2936
+ if (state.adjustingFromInitialMount) {
2937
+ state.adjustingFromInitialMount--;
2938
+ }
2939
+ }
2940
+ };
2941
+ state.scroll += positionDiff;
2942
+ state.scrollForNextCalculateItemsInView = void 0;
2943
+ const readyToRender = peek$(ctx, "readyToRender");
2944
+ if (readyToRender) {
2945
+ doit();
2946
+ } else {
2947
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2948
+ requestAnimationFrame(doit);
2949
+ }
2950
+ }
2951
+ }
2952
+
2649
2953
  // src/core/bootstrapInitialScroll.ts
2650
2954
  var DEFAULT_BOOTSTRAP_REVEAL_EPSILON = 1;
2651
2955
  var DEFAULT_BOOTSTRAP_REVEAL_MAX_FRAMES = 8;
@@ -2739,7 +3043,7 @@ function clearBootstrapInitialScrollSession(state) {
2739
3043
  bootstrapInitialScroll.frameHandle = void 0;
2740
3044
  }
2741
3045
  setInitialScrollSession(state, {
2742
- bootstrap: void 0,
3046
+ bootstrap: null,
2743
3047
  kind: (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind
2744
3048
  });
2745
3049
  }
@@ -2895,15 +3199,18 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2895
3199
  return;
2896
3200
  }
2897
3201
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2898
- if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2899
- clearPendingInitialScrollFooterLayout(ctx, {
2900
- dataLength: state.props.data.length,
2901
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2902
- target: initialScroll
2903
- });
2904
- return;
3202
+ const shouldKeepEndTargetAlive = isRetargetableBottomAlignedInitialScrollTarget(initialScroll) && peek$(ctx, "isAtEnd");
3203
+ if (!shouldKeepEndTargetAlive) {
3204
+ if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
3205
+ clearPendingInitialScrollFooterLayout(ctx, {
3206
+ dataLength: state.props.data.length,
3207
+ stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
3208
+ target: initialScroll
3209
+ });
3210
+ } else {
3211
+ clearFinishedViewportRetargetableInitialScroll(state);
3212
+ }
2905
3213
  }
2906
- clearFinishedViewportRetargetableInitialScroll(state);
2907
3214
  }
2908
3215
  }
2909
3216
  function startBootstrapInitialScrollOnMount(ctx, options) {
@@ -2942,7 +3249,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2942
3249
  }
2943
3250
  const shouldResetDidFinish = !!(state.didFinishInitialScroll && previousDataLength === 0 && dataLength > 0 && initialScroll.index !== void 0);
2944
3251
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2945
- const shouldClearFinishedResizePreservation = didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
3252
+ const shouldClearFinishedResizePreservation = !initialScrollAtEnd && didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
2946
3253
  if (shouldClearFinishedResizePreservation) {
2947
3254
  clearPreservedInitialScrollTarget(state);
2948
3255
  return;
@@ -3045,27 +3352,46 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
3045
3352
  }
3046
3353
  }
3047
3354
  function handleBootstrapInitialScrollLayoutChange(ctx) {
3355
+ var _a3, _b, _c, _d;
3048
3356
  const state = ctx.state;
3049
3357
  const initialScroll = state.initialScroll;
3050
- if (isOffsetInitialScrollSession(state) || state.props.data.length === 0 || !initialScroll) {
3051
- return;
3052
- }
3053
3358
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
3054
- if (!bootstrapInitialScroll && initialScroll.viewPosition !== 1) {
3055
- return;
3056
- }
3057
- const didFinishInitialScroll = state.didFinishInitialScroll;
3058
- if (didFinishInitialScroll) {
3059
- setInitialScrollTarget(state, initialScroll, {
3060
- resetDidFinish: true
3061
- });
3062
- state.clearPreservedInitialScrollOnNextFinish = true;
3359
+ if (initialScroll && state.props.data.length > 0 && !isOffsetInitialScrollSession(state) && (bootstrapInitialScroll || initialScroll.viewPosition === 1)) {
3360
+ const resolvedOffset = resolveInitialScrollOffset(ctx, initialScroll);
3361
+ const scrollingTo = ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) ? state.scrollingTo : void 0;
3362
+ if (!bootstrapInitialScroll && (scrollingTo || state.didFinishInitialScroll)) {
3363
+ const currentOffset = scrollingTo ? (_b = scrollingTo.targetOffset) != null ? _b : scrollingTo.offset : getObservedBootstrapInitialScrollOffset(state);
3364
+ const offsetDiff = resolvedOffset - currentOffset;
3365
+ if (Math.abs(offsetDiff) > DEFAULT_BOOTSTRAP_REVEAL_EPSILON) {
3366
+ if (scrollingTo) {
3367
+ const existingWatchdog = initialScrollWatchdog.get(state);
3368
+ scrollingTo.offset = resolvedOffset;
3369
+ scrollingTo.targetOffset = resolvedOffset;
3370
+ state.initialScroll = {
3371
+ ...initialScroll,
3372
+ contentOffset: resolvedOffset
3373
+ };
3374
+ state.hasScrolled = false;
3375
+ initialScrollWatchdog.set(state, {
3376
+ startScroll: (_c = existingWatchdog == null ? void 0 : existingWatchdog.startScroll) != null ? _c : state.scroll,
3377
+ targetOffset: resolvedOffset
3378
+ });
3379
+ }
3380
+ requestAdjust(ctx, offsetDiff);
3381
+ if (state.didFinishInitialScroll) {
3382
+ (_d = state.triggerCalculateItemsInView) == null ? void 0 : _d.call(state, { forceFullItemPositions: true });
3383
+ }
3384
+ }
3385
+ if (state.didFinishInitialScroll) {
3386
+ clearFinishedViewportRetargetableInitialScroll(state);
3387
+ }
3388
+ } else {
3389
+ rearmBootstrapInitialScroll(ctx, {
3390
+ scroll: resolvedOffset,
3391
+ targetIndexSeed: initialScroll.index
3392
+ });
3393
+ }
3063
3394
  }
3064
- rearmBootstrapInitialScroll(ctx, {
3065
- scroll: resolveInitialScrollOffset(ctx, initialScroll),
3066
- seedContentOffset: didFinishInitialScroll && !bootstrapInitialScroll ? getObservedBootstrapInitialScrollOffset(state) : void 0,
3067
- targetIndexSeed: initialScroll.index
3068
- });
3069
3395
  }
3070
3396
  function evaluateBootstrapInitialScroll(ctx) {
3071
3397
  var _a3, _b;
@@ -3272,7 +3598,7 @@ function checkFinishedScrollFallback(ctx) {
3272
3598
  state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
3273
3599
  };
3274
3600
  const checkHasScrolled = () => {
3275
- var _c;
3601
+ var _c, _d;
3276
3602
  state.timeoutCheckFinishedScrollFallback = void 0;
3277
3603
  const isStillScrollingTo = state.scrollingTo;
3278
3604
  if (isStillScrollingTo) {
@@ -3285,11 +3611,13 @@ function checkFinishedScrollFallback(ctx) {
3285
3611
  isStillScrollingTo
3286
3612
  );
3287
3613
  const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
3288
- const canFinishAfterSilentNativeDispatch = silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
3289
- if (shouldFinishZeroTarget || state.hasScrolled || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3614
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
3615
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
3616
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
3617
+ if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3290
3618
  finishScrollTo(ctx);
3291
- } else if (isNativeInitialPending && numChecks <= maxChecks) {
3292
- const targetOffset = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : state.scrollPending;
3619
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
3620
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
3293
3621
  scrollToFallbackOffset(ctx, targetOffset);
3294
3622
  scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3295
3623
  } else {
@@ -3325,7 +3653,14 @@ function handleInitialScrollLayoutReady(ctx) {
3325
3653
  }
3326
3654
  function initializeInitialScrollOnMount(ctx, options) {
3327
3655
  var _a3, _b;
3328
- const { dataLength, hasFooterComponent, initialContentOffset, initialScrollAtEnd, useBootstrapInitialScroll } = options;
3656
+ const {
3657
+ alwaysDispatchInitialScroll,
3658
+ dataLength,
3659
+ hasFooterComponent,
3660
+ initialContentOffset,
3661
+ initialScrollAtEnd,
3662
+ useBootstrapInitialScroll
3663
+ } = options;
3329
3664
  const state = ctx.state;
3330
3665
  const initialScroll = state.initialScroll;
3331
3666
  const resolvedInitialContentOffset = initialContentOffset != null ? initialContentOffset : 0;
@@ -3345,7 +3680,7 @@ function initializeInitialScrollOnMount(ctx, options) {
3345
3680
  return;
3346
3681
  }
3347
3682
  const hasPendingDataDependentInitialScroll = !!initialScroll && dataLength === 0 && !(resolvedInitialContentOffset === 0 && !initialScrollAtEnd);
3348
- if (!resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
3683
+ if (!alwaysDispatchInitialScroll && !resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
3349
3684
  if (initialScroll && !initialScrollAtEnd) {
3350
3685
  finishInitialScroll(ctx, {
3351
3686
  resolvedOffset: resolvedInitialContentOffset
@@ -3384,30 +3719,6 @@ function handleInitialScrollDataChange(ctx, options) {
3384
3719
  advanceCurrentInitialScrollSession(ctx);
3385
3720
  }
3386
3721
 
3387
- // src/utils/requestAdjust.ts
3388
- function requestAdjust(ctx, positionDiff, dataChanged) {
3389
- const state = ctx.state;
3390
- if (Math.abs(positionDiff) > 0.1) {
3391
- const doit = () => {
3392
- {
3393
- state.scrollAdjustHandler.requestAdjust(positionDiff);
3394
- if (state.adjustingFromInitialMount) {
3395
- state.adjustingFromInitialMount--;
3396
- }
3397
- }
3398
- };
3399
- state.scroll += positionDiff;
3400
- state.scrollForNextCalculateItemsInView = void 0;
3401
- const readyToRender = peek$(ctx, "readyToRender");
3402
- if (readyToRender) {
3403
- doit();
3404
- } else {
3405
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
3406
- requestAnimationFrame(doit);
3407
- }
3408
- }
3409
- }
3410
-
3411
3722
  // src/core/mvcp.ts
3412
3723
  var MVCP_POSITION_EPSILON = 0.1;
3413
3724
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -3681,15 +3992,27 @@ function prepareMVCP(ctx, dataChanged) {
3681
3992
  return;
3682
3993
  }
3683
3994
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
3684
- requestAdjust(ctx, positionDiff);
3995
+ const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
3996
+ if (!shouldSkipAdjustForMaintainedEnd) {
3997
+ requestAdjust(ctx, positionDiff);
3998
+ }
3685
3999
  }
3686
4000
  };
3687
4001
  }
3688
4002
  }
3689
4003
 
4004
+ // src/core/resetLayoutCachesForDataChange.ts
4005
+ function resetLayoutCachesForDataChange(state) {
4006
+ state.indexByKey.clear();
4007
+ state.idCache.length = 0;
4008
+ state.positions.length = 0;
4009
+ state.columns.length = 0;
4010
+ state.columnSpans.length = 0;
4011
+ }
4012
+
3690
4013
  // src/core/syncMountedContainer.ts
3691
4014
  function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3692
- var _a3, _b, _c, _d, _e, _f, _g, _h;
4015
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
3693
4016
  const state = ctx.state;
3694
4017
  const {
3695
4018
  columns,
@@ -3701,7 +4024,8 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3701
4024
  if (item === void 0) {
3702
4025
  return { didChangePosition: false, didRefreshData: false };
3703
4026
  }
3704
- const updateLayout = (_a3 = options == null ? void 0 : options.updateLayout) != null ? _a3 : true;
4027
+ const itemKey = (_a3 = state.idCache[itemIndex]) != null ? _a3 : getId(state, itemIndex);
4028
+ const updateLayout = (_b = options == null ? void 0 : options.updateLayout) != null ? _b : true;
3705
4029
  let didChangePosition = false;
3706
4030
  let didRefreshData = false;
3707
4031
  if (updateLayout) {
@@ -3710,7 +4034,9 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3710
4034
  set$(ctx, `containerPosition${containerIndex}`, POSITION_OUT_OF_VIEW);
3711
4035
  return { didChangePosition: false, didRefreshData: false };
3712
4036
  }
3713
- const position = (positionValue || 0) - ((_b = options == null ? void 0 : options.scrollAdjustPending) != null ? _b : 0);
4037
+ const logicalPosition = (positionValue || 0) - ((_c = options == null ? void 0 : options.scrollAdjustPending) != null ? _c : 0);
4038
+ const itemSize = (_d = state.sizes.get(itemKey)) != null ? _d : getItemSize(ctx, itemKey, itemIndex, item);
4039
+ const position = toPhysicalHorizontalItemPosition(state, logicalPosition, itemSize, peek$(ctx, "totalSize"));
3714
4040
  const column = columns[itemIndex] || 1;
3715
4041
  const span = columnSpans[itemIndex] || 1;
3716
4042
  const prevPos = peek$(ctx, `containerPosition${containerIndex}`);
@@ -3729,15 +4055,15 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3729
4055
  }
3730
4056
  const prevData = peek$(ctx, `containerItemData${containerIndex}`);
3731
4057
  if (prevData !== item) {
3732
- const pendingDataComparison = ((_c = state.pendingDataComparison) == null ? void 0 : _c.previousData) === state.previousData && ((_d = state.pendingDataComparison) == null ? void 0 : _d.nextData) === data ? state.pendingDataComparison : void 0;
3733
- const cachedComparison = (_e = pendingDataComparison == null ? void 0 : pendingDataComparison.byIndex[itemIndex]) != null ? _e : 0;
4058
+ const pendingDataComparison = ((_e = state.pendingDataComparison) == null ? void 0 : _e.previousData) === state.previousData && ((_f = state.pendingDataComparison) == null ? void 0 : _f.nextData) === data ? state.pendingDataComparison : void 0;
4059
+ const cachedComparison = (_g = pendingDataComparison == null ? void 0 : pendingDataComparison.byIndex[itemIndex]) != null ? _g : 0;
3734
4060
  if (cachedComparison === 2) {
3735
4061
  set$(ctx, `containerItemData${containerIndex}`, item);
3736
4062
  didRefreshData = true;
3737
4063
  } else if (cachedComparison !== 1) {
3738
- const itemKey = (_g = (_f = peek$(ctx, `containerItemKey${containerIndex}`)) != null ? _f : state.idCache[itemIndex]) != null ? _g : getId(state, itemIndex);
4064
+ const nextItemKey = (_h = peek$(ctx, `containerItemKey${containerIndex}`)) != null ? _h : itemKey;
3739
4065
  const prevKey = keyExtractor == null ? void 0 : keyExtractor(prevData, itemIndex);
3740
- if (prevData === void 0 || !keyExtractor || prevKey !== itemKey) {
4066
+ if (prevData === void 0 || !keyExtractor || prevKey !== nextItemKey) {
3741
4067
  set$(ctx, `containerItemData${containerIndex}`, item);
3742
4068
  didRefreshData = true;
3743
4069
  } else if (!itemsAreEqual) {
@@ -3754,7 +4080,7 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3754
4080
  };
3755
4081
  }
3756
4082
  }
3757
- if ((_h = state.pendingDataComparison) == null ? void 0 : _h.byIndex) {
4083
+ if ((_i = state.pendingDataComparison) == null ? void 0 : _i.byIndex) {
3758
4084
  state.pendingDataComparison.byIndex[itemIndex] = isEqual ? 1 : 2;
3759
4085
  }
3760
4086
  if (!isEqual) {
@@ -3919,11 +4245,13 @@ function updateSnapToOffsets(ctx) {
3919
4245
  const {
3920
4246
  props: { snapToIndices }
3921
4247
  } = state;
4248
+ const contentSize = state.props.horizontal ? getContentSize(ctx) : void 0;
3922
4249
  const snapToOffsets = Array(snapToIndices.length);
3923
4250
  for (let i = 0; i < snapToIndices.length; i++) {
3924
4251
  const idx = snapToIndices[i];
3925
4252
  getId(state, idx);
3926
- snapToOffsets[i] = state.positions[idx];
4253
+ const logicalOffset = state.positions[idx];
4254
+ snapToOffsets[i] = toNativeHorizontalOffset(state, logicalOffset, contentSize);
3927
4255
  }
3928
4256
  set$(ctx, "snapToOffsets", snapToOffsets);
3929
4257
  }
@@ -4300,6 +4628,30 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
4300
4628
  var unstableBatchedUpdates = ReactDOM.unstable_batchedUpdates;
4301
4629
  var batchedUpdates = typeof unstableBatchedUpdates === "function" ? unstableBatchedUpdates : (fn) => fn();
4302
4630
 
4631
+ // src/utils/containerPool.ts
4632
+ var MIN_INITIAL_CONTAINER_POOL_SIZE = 32;
4633
+ var MAX_INITIAL_SPARE_CONTAINERS = 64;
4634
+ function getInitialContainerPoolSize(dataLength, numContainers, initialContainerPoolRatio) {
4635
+ if (dataLength <= 0 || numContainers <= 0) {
4636
+ return 0;
4637
+ }
4638
+ const ratioPoolSize = Math.ceil(numContainers * initialContainerPoolRatio);
4639
+ const cappedSparePoolSize = numContainers + MAX_INITIAL_SPARE_CONTAINERS;
4640
+ const targetPoolSize = Math.max(
4641
+ numContainers,
4642
+ Math.min(ratioPoolSize, cappedSparePoolSize),
4643
+ Math.min(dataLength, MIN_INITIAL_CONTAINER_POOL_SIZE)
4644
+ );
4645
+ const maxUsefulPoolSize = Math.max(dataLength, numContainers);
4646
+ return Math.min(maxUsefulPoolSize, targetPoolSize);
4647
+ }
4648
+ function getExpandedContainerPoolSize(dataLength, numContainers) {
4649
+ if (dataLength <= 0 || numContainers <= 0) {
4650
+ return 0;
4651
+ }
4652
+ return Math.min(Math.max(dataLength, numContainers), Math.max(numContainers, Math.ceil(numContainers * 1.5)));
4653
+ }
4654
+
4303
4655
  // src/utils/findAvailableContainers.ts
4304
4656
  function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers, protectedKeys) {
4305
4657
  const numContainers = peek$(ctx, "numContainers");
@@ -4505,10 +4857,9 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
4505
4857
  function calculateItemsInView(ctx, params = {}) {
4506
4858
  const state = ctx.state;
4507
4859
  batchedUpdates(() => {
4508
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
4860
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
4509
4861
  const {
4510
4862
  columns,
4511
- columnSpans,
4512
4863
  containerItemKeys,
4513
4864
  enableScrollForNextCalculateItemsInView,
4514
4865
  idCache,
@@ -4552,18 +4903,38 @@ function calculateItemsInView(ctx, params = {}) {
4552
4903
  // current initial-scroll target instead of transient native adjustments.
4553
4904
  resolveInitialScrollOffset(ctx, initialScroll)
4554
4905
  ) : state.scroll;
4555
- const scrollAdjustPending = (_c = peek$(ctx, "scrollAdjustPending")) != null ? _c : 0;
4556
- const scrollAdjustPad = scrollAdjustPending - topPad;
4557
- let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
4558
- if (scroll + scrollLength > totalSize) {
4559
- scroll = Math.max(0, totalSize - scrollLength);
4560
- }
4906
+ let scrollAdjustPending = 0;
4907
+ let scrollAdjustPad = 0;
4908
+ let scroll = 0;
4909
+ let scrollTopBuffered = 0;
4910
+ let scrollBottom = 0;
4911
+ let scrollBottomBuffered = 0;
4912
+ let nativeScrollState = scrollState;
4913
+ const updateScroll2 = (nextScrollState) => {
4914
+ var _a4;
4915
+ nativeScrollState = nextScrollState;
4916
+ scrollAdjustPending = (_a4 = peek$(ctx, "scrollAdjustPending")) != null ? _a4 : 0;
4917
+ scrollAdjustPad = scrollAdjustPending - topPad;
4918
+ scroll = Math.round(nextScrollState + scrollExtra + scrollAdjustPad);
4919
+ if (scroll + scrollLength > totalSize) {
4920
+ scroll = Math.max(0, totalSize - scrollLength);
4921
+ }
4922
+ };
4923
+ updateScroll2(scrollState);
4561
4924
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
4562
4925
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
4563
4926
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
4927
+ const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
4564
4928
  if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
4565
4929
  set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
4566
4930
  }
4931
+ const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyIndicesArr.length > 0 && stickyIndexDidChange;
4932
+ const finishCalculateItemsInView = shouldNotifyStickyHeaderChange ? () => {
4933
+ const item = data[nextActiveStickyIndex];
4934
+ if (item !== void 0) {
4935
+ onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4936
+ }
4937
+ } : void 0;
4567
4938
  let scrollBufferTop = drawDistance;
4568
4939
  let scrollBufferBottom = drawDistance;
4569
4940
  if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
@@ -4573,28 +4944,30 @@ function calculateItemsInView(ctx, params = {}) {
4573
4944
  scrollBufferTop = drawDistance * 1.5;
4574
4945
  scrollBufferBottom = drawDistance * 0.5;
4575
4946
  }
4576
- const scrollTopBuffered = scroll - scrollBufferTop;
4577
- const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
4578
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4947
+ const updateScrollRange = () => {
4948
+ const scrollStart = Math.max(0, scroll);
4949
+ const overscrollBeforeContent = Math.max(0, -nativeScrollState);
4950
+ scrollTopBuffered = scrollStart - scrollBufferTop;
4951
+ scrollBottom = Math.max(scrollStart, scroll + scrollLength + overscrollBeforeContent);
4952
+ scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4953
+ };
4954
+ updateScrollRange();
4579
4955
  if (!suppressInitialScrollSideEffects && !dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
4580
4956
  const { top, bottom } = scrollForNextCalculateItemsInView;
4581
4957
  if (top === null && bottom === null) {
4582
4958
  state.scrollForNextCalculateItemsInView = void 0;
4583
4959
  } else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
4584
4960
  if (!isInMVCPActiveMode(state)) {
4961
+ finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4585
4962
  return;
4586
4963
  }
4587
4964
  }
4588
4965
  }
4589
4966
  const checkMVCP = doMVCP && !suppressInitialScrollSideEffects ? prepareMVCP(ctx, dataChanged) : void 0;
4590
4967
  if (dataChanged) {
4591
- indexByKey.clear();
4592
- idCache.length = 0;
4593
- positions.length = 0;
4594
- columns.length = 0;
4595
- columnSpans.length = 0;
4968
+ resetLayoutCachesForDataChange(state);
4596
4969
  }
4597
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_d = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _d : 0;
4970
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4598
4971
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4599
4972
  updateItemPositions(ctx, dataChanged, {
4600
4973
  doMVCP,
@@ -4619,21 +4992,25 @@ function calculateItemsInView(ctx, params = {}) {
4619
4992
  }
4620
4993
  }
4621
4994
  const scrollBeforeMVCP = state.scroll;
4622
- const scrollAdjustPendingBeforeMVCP = (_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0;
4995
+ const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
4623
4996
  checkMVCP == null ? void 0 : checkMVCP();
4624
- const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0) !== scrollAdjustPendingBeforeMVCP);
4997
+ const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0) !== scrollAdjustPendingBeforeMVCP);
4998
+ if (didMVCPAdjustScroll && initialScroll) {
4999
+ updateScroll2(state.scroll);
5000
+ updateScrollRange();
5001
+ }
4625
5002
  let startNoBuffer = null;
4626
5003
  let startBuffered = null;
4627
5004
  let startBufferedId = null;
4628
5005
  let endNoBuffer = null;
4629
5006
  let endBuffered = null;
4630
- let loopStart = (_g = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _g : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
5007
+ let loopStart = (_f = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _f : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4631
5008
  for (let i = loopStart; i >= 0; i--) {
4632
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
5009
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
4633
5010
  const top = positions[i];
4634
- const size = (_i = sizes.get(id)) != null ? _i : getItemSize(ctx, id, i, data[i]);
5011
+ const size = (_h = sizes.get(id)) != null ? _h : getItemSize(ctx, id, i, data[i]);
4635
5012
  const bottom = top + size;
4636
- if (bottom > scroll - scrollBufferTop) {
5013
+ if (bottom > scrollTopBuffered) {
4637
5014
  loopStart = i;
4638
5015
  } else {
4639
5016
  break;
@@ -4662,8 +5039,8 @@ function calculateItemsInView(ctx, params = {}) {
4662
5039
  let firstFullyOnScreenIndex;
4663
5040
  const dataLength = data.length;
4664
5041
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
4665
- const id = (_j = idCache[i]) != null ? _j : getId(state, i);
4666
- const size = (_k = sizes.get(id)) != null ? _k : getItemSize(ctx, id, i, data[i]);
5042
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
5043
+ const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
4667
5044
  const top = positions[i];
4668
5045
  if (!foundEnd) {
4669
5046
  if (startNoBuffer === null && top + size > scroll) {
@@ -4702,7 +5079,7 @@ function calculateItemsInView(ctx, params = {}) {
4702
5079
  const firstVisibleAnchorIndex = firstFullyOnScreenIndex != null ? firstFullyOnScreenIndex : startNoBuffer;
4703
5080
  if (firstVisibleAnchorIndex !== null && firstVisibleAnchorIndex !== void 0 && endNoBuffer !== null) {
4704
5081
  for (let i = firstVisibleAnchorIndex; i <= endNoBuffer; i++) {
4705
- const id = (_l = idCache[i]) != null ? _l : getId(state, i);
5082
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
4706
5083
  idsInView.push(id);
4707
5084
  }
4708
5085
  }
@@ -4735,7 +5112,7 @@ function calculateItemsInView(ctx, params = {}) {
4735
5112
  const needNewContainers = [];
4736
5113
  const needNewContainersSet = /* @__PURE__ */ new Set();
4737
5114
  for (let i = startBuffered; i <= endBuffered; i++) {
4738
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
5115
+ const id = (_l = idCache[i]) != null ? _l : getId(state, i);
4739
5116
  if (!containerItemKeys.has(id)) {
4740
5117
  needNewContainersSet.add(i);
4741
5118
  needNewContainers.push(i);
@@ -4744,7 +5121,7 @@ function calculateItemsInView(ctx, params = {}) {
4744
5121
  if (alwaysRenderArr.length > 0) {
4745
5122
  for (const index of alwaysRenderArr) {
4746
5123
  if (index < 0 || index >= dataLength) continue;
4747
- const id = (_n = idCache[index]) != null ? _n : getId(state, index);
5124
+ const id = (_m = idCache[index]) != null ? _m : getId(state, index);
4748
5125
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
4749
5126
  needNewContainersSet.add(index);
4750
5127
  needNewContainers.push(index);
@@ -4783,7 +5160,7 @@ function calculateItemsInView(ctx, params = {}) {
4783
5160
  for (let idx = 0; idx < needNewContainers.length; idx++) {
4784
5161
  const i = needNewContainers[idx];
4785
5162
  const containerIndex = availableContainers[idx];
4786
- const id = (_o = idCache[i]) != null ? _o : getId(state, i);
5163
+ const id = (_n = idCache[i]) != null ? _n : getId(state, i);
4787
5164
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
4788
5165
  if (oldKey && oldKey !== id) {
4789
5166
  containerItemKeys.delete(oldKey);
@@ -4794,7 +5171,7 @@ function calculateItemsInView(ctx, params = {}) {
4794
5171
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
4795
5172
  }
4796
5173
  containerItemKeys.set(id, containerIndex);
4797
- (_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.add(id);
5174
+ (_o = state.userScrollAnchorResetKeys) == null ? void 0 : _o.add(id);
4798
5175
  const containerSticky = `containerSticky${containerIndex}`;
4799
5176
  const isSticky = stickyIndicesSet.has(i);
4800
5177
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -4818,17 +5195,17 @@ function calculateItemsInView(ctx, params = {}) {
4818
5195
  if (numContainers !== prevNumContainers) {
4819
5196
  set$(ctx, "numContainers", numContainers);
4820
5197
  if (numContainers > peek$(ctx, "numContainersPooled")) {
4821
- set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
5198
+ set$(ctx, "numContainersPooled", getExpandedContainerPoolSize(dataLength, numContainers));
4822
5199
  }
4823
5200
  }
4824
5201
  }
4825
- if (((_q = state.userScrollAnchorResetKeys) == null ? void 0 : _q.size) === 0) {
5202
+ if (((_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.size) === 0) {
4826
5203
  state.userScrollAnchorResetKeys = void 0;
4827
5204
  }
4828
5205
  if (alwaysRenderArr.length > 0) {
4829
5206
  for (const index of alwaysRenderArr) {
4830
5207
  if (index < 0 || index >= dataLength) continue;
4831
- const id = (_r = idCache[index]) != null ? _r : getId(state, index);
5208
+ const id = (_q = idCache[index]) != null ? _q : getId(state, index);
4832
5209
  const containerIndex = containerItemKeys.get(id);
4833
5210
  if (containerIndex !== void 0) {
4834
5211
  state.stickyContainerPool.add(containerIndex);
@@ -4902,12 +5279,7 @@ function calculateItemsInView(ctx, params = {}) {
4902
5279
  );
4903
5280
  }
4904
5281
  }
4905
- if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
4906
- const item = data[nextActiveStickyIndex];
4907
- if (item !== void 0) {
4908
- onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4909
- }
4910
- }
5282
+ finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4911
5283
  });
4912
5284
  }
4913
5285
 
@@ -4932,21 +5304,36 @@ function doMaintainScrollAtEnd(ctx) {
4932
5304
  if (contentSize < state.scrollLength) {
4933
5305
  state.scroll = 0;
4934
5306
  }
4935
- requestAnimationFrame(() => {
4936
- var _a3;
4937
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
4938
- state.maintainingScrollAtEnd = true;
4939
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
4940
- animated: maintainScrollAtEnd.animated
4941
- });
4942
- setTimeout(
4943
- () => {
4944
- state.maintainingScrollAtEnd = false;
4945
- },
4946
- maintainScrollAtEnd.animated ? 500 : 0
4947
- );
4948
- }
4949
- });
5307
+ if (!state.maintainingScrollAtEnd) {
5308
+ state.maintainingScrollAtEnd = true;
5309
+ requestAnimationFrame(() => {
5310
+ if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
5311
+ const scroller = refScroller.current;
5312
+ if (state.props.horizontal && isHorizontalRTL(state)) {
5313
+ const currentContentSize = getContentSize(ctx);
5314
+ const logicalEndOffset = getLogicalHorizontalMaxOffset(state, currentContentSize);
5315
+ const nativeOffset = toNativeHorizontalOffset(state, logicalEndOffset, currentContentSize);
5316
+ scroller == null ? void 0 : scroller.scrollTo({
5317
+ animated: maintainScrollAtEnd.animated,
5318
+ x: nativeOffset,
5319
+ y: 0
5320
+ });
5321
+ } else {
5322
+ scroller == null ? void 0 : scroller.scrollToEnd({
5323
+ animated: maintainScrollAtEnd.animated
5324
+ });
5325
+ }
5326
+ setTimeout(
5327
+ () => {
5328
+ state.maintainingScrollAtEnd = false;
5329
+ },
5330
+ maintainScrollAtEnd.animated ? 500 : 0
5331
+ );
5332
+ } else {
5333
+ state.maintainingScrollAtEnd = false;
5334
+ }
5335
+ });
5336
+ }
4950
5337
  return true;
4951
5338
  }
4952
5339
  return false;
@@ -5058,14 +5445,21 @@ function doInitialAllocateContainers(ctx) {
5058
5445
  } else {
5059
5446
  averageItemSize = estimatedItemSize;
5060
5447
  }
5061
- const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
5448
+ const numContainers = Math.max(
5449
+ 1,
5450
+ Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns)
5451
+ );
5062
5452
  for (let i = 0; i < numContainers; i++) {
5063
5453
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
5064
5454
  set$(ctx, `containerColumn${i}`, -1);
5065
5455
  set$(ctx, `containerSpan${i}`, 1);
5066
5456
  }
5067
5457
  set$(ctx, "numContainers", numContainers);
5068
- set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
5458
+ set$(
5459
+ ctx,
5460
+ "numContainersPooled",
5461
+ getInitialContainerPoolSize(data.length, numContainers, state.props.initialContainerPoolRatio)
5462
+ );
5069
5463
  if (state.lastLayout) {
5070
5464
  if (state.initialScroll) {
5071
5465
  requestAnimationFrame(() => {
@@ -5128,7 +5522,8 @@ function handleLayout(ctx, layoutParam, setCanRender) {
5128
5522
  }
5129
5523
  checkThresholds(ctx);
5130
5524
  if (state) {
5131
- state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
5525
+ const crossAxisPadding = state.props.horizontal ? (state.props.stylePaddingTop || 0) + (state.props.stylePaddingBottom || 0) : (state.props.stylePaddingLeft || 0) + (state.props.stylePaddingRight || 0);
5526
+ state.needsOtherAxisSize = otherAxisSize - crossAxisPadding < 10;
5132
5527
  }
5133
5528
  if (IS_DEV && measuredLength === 0) {
5134
5529
  warnDevOnce(
@@ -5216,8 +5611,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
5216
5611
  // src/core/onScroll.ts
5217
5612
  function trackInitialScrollNativeProgress(state, newScroll) {
5218
5613
  const initialNativeScrollWatchdog = initialScrollWatchdog.get(state);
5219
- const didInitialScrollProgress = !!initialNativeScrollWatchdog && initialScrollWatchdog.didObserveProgress(newScroll, initialNativeScrollWatchdog);
5220
- if (didInitialScrollProgress) {
5614
+ const didInitialScrollReachTarget = !!initialNativeScrollWatchdog && initialScrollWatchdog.didReachTarget(newScroll, initialNativeScrollWatchdog);
5615
+ if (didInitialScrollReachTarget) {
5221
5616
  initialScrollWatchdog.clear(state);
5222
5617
  return;
5223
5618
  }
@@ -5242,7 +5637,7 @@ function cloneScrollEvent(event) {
5242
5637
  };
5243
5638
  }
5244
5639
  function onScroll(ctx, event) {
5245
- var _a3, _b, _c, _d;
5640
+ var _a3, _b, _c, _d, _e;
5246
5641
  const state = ctx.state;
5247
5642
  const { scrollProcessingEnabled } = state;
5248
5643
  if (scrollProcessingEnabled === false) {
@@ -5261,6 +5656,9 @@ function onScroll(ctx, event) {
5261
5656
  }
5262
5657
  }
5263
5658
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
5659
+ if (state.props.horizontal) {
5660
+ newScroll = toLogicalHorizontalOffset(state, newScroll, (_e = event.nativeEvent.contentSize) == null ? void 0 : _e.width);
5661
+ }
5264
5662
  if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
5265
5663
  const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
5266
5664
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
@@ -5355,16 +5753,20 @@ function maybeUpdateAnchoredEndSpace(ctx) {
5355
5753
  let contentBelowAnchor = 0;
5356
5754
  const footerSize = ctx.values.get("footerSize") || 0;
5357
5755
  const stylePaddingBottom = state.props.stylePaddingBottom || 0;
5756
+ let hasUnknownTailSize = false;
5358
5757
  for (let index = anchorIndex; index < data.length; index++) {
5359
5758
  const itemKey = getId(state, index);
5360
5759
  const size = itemKey ? state.sizesKnown.get(itemKey) : void 0;
5361
5760
  const effectiveSize = index === anchorIndex && anchorMaxSize !== void 0 ? Math.min(size || 0, Math.max(0, anchorMaxSize)) : size;
5761
+ if (size === void 0) {
5762
+ hasUnknownTailSize = true;
5763
+ }
5362
5764
  if (effectiveSize !== null && effectiveSize !== void 0 && effectiveSize > 0) {
5363
5765
  contentBelowAnchor += effectiveSize;
5364
5766
  }
5365
5767
  }
5366
5768
  contentBelowAnchor += footerSize + stylePaddingBottom;
5367
- nextSize = Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5769
+ nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5368
5770
  }
5369
5771
  }
5370
5772
  if (previousSize !== nextSize) {
@@ -5428,6 +5830,16 @@ function runOrScheduleMVCPRecalculate(ctx) {
5428
5830
  });
5429
5831
  }
5430
5832
  }
5833
+ function updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal) {
5834
+ const state = ctx.state;
5835
+ if (state.needsOtherAxisSize) {
5836
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
5837
+ const currentOtherAxisSize = peek$(ctx, "otherAxisSize");
5838
+ if (!currentOtherAxisSize || otherAxisSize > currentOtherAxisSize) {
5839
+ set$(ctx, "otherAxisSize", otherAxisSize);
5840
+ }
5841
+ }
5842
+ }
5431
5843
  function updateItemSize(ctx, itemKey, sizeObj) {
5432
5844
  var _a3;
5433
5845
  const state = ctx.state;
@@ -5436,15 +5848,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5436
5848
  const {
5437
5849
  didContainersLayout,
5438
5850
  sizesKnown,
5439
- props: {
5440
- getFixedItemSize,
5441
- getItemType,
5442
- horizontal,
5443
- suggestEstimatedItemSize,
5444
- onItemSizeChanged,
5445
- data,
5446
- maintainScrollAtEnd
5447
- }
5851
+ props: { getFixedItemSize, getItemType, horizontal, onItemSizeChanged, data, maintainScrollAtEnd }
5448
5852
  } = state;
5449
5853
  if (!data) return;
5450
5854
  const index = state.indexByKey.get(itemKey);
@@ -5459,13 +5863,13 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5459
5863
  const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
5460
5864
  const size2 = getFixedItemSize(itemData, index, type);
5461
5865
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
5866
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5462
5867
  return;
5463
5868
  }
5464
5869
  }
5465
5870
  let needsRecalculate = !didContainersLayout;
5466
5871
  let shouldMaintainScrollAtEnd = false;
5467
5872
  let minIndexSizeChanged;
5468
- let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
5469
5873
  const prevSizeKnown = state.sizesKnown.get(itemKey);
5470
5874
  const diff = updateOneItemSize(ctx, itemKey, sizeObj);
5471
5875
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
@@ -5476,10 +5880,6 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5476
5880
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
5477
5881
  needsRecalculate = true;
5478
5882
  }
5479
- if (state.needsOtherAxisSize) {
5480
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
5481
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
5482
- }
5483
5883
  if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
5484
5884
  shouldMaintainScrollAtEnd = true;
5485
5885
  }
@@ -5495,22 +5895,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5495
5895
  if (minIndexSizeChanged !== void 0) {
5496
5896
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
5497
5897
  }
5498
- if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
5499
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
5500
- state.timeoutSizeMessage = setTimeout(() => {
5501
- var _a4;
5502
- state.timeoutSizeMessage = void 0;
5503
- const num = state.sizesKnown.size;
5504
- const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
5505
- console.warn(
5506
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
5507
- );
5508
- }, 1e3);
5509
- }
5510
- const cur = peek$(ctx, "otherAxisSize");
5511
- if (!cur || maxOtherAxisSize > cur) {
5512
- set$(ctx, "otherAxisSize", maxOtherAxisSize);
5513
- }
5898
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5514
5899
  if (didContainersLayout || checkAllSizesKnown(state, getMountedBufferedIndices(state))) {
5515
5900
  if (needsRecalculate) {
5516
5901
  state.scrollForNextCalculateItemsInView = void 0;
@@ -5611,12 +5996,47 @@ function createColumnWrapperStyle(contentContainerStyle) {
5611
5996
  }
5612
5997
 
5613
5998
  // src/utils/createImperativeHandle.ts
5999
+ var DEFAULT_AVERAGE_ITEM_SIZE_TYPE = "default";
6000
+ function getAverageItemSizes(state) {
6001
+ const averageItemSizes = {};
6002
+ for (const itemType in state.averageSizes) {
6003
+ const averageSize = state.averageSizes[itemType];
6004
+ if (averageSize) {
6005
+ averageItemSizes[itemType || DEFAULT_AVERAGE_ITEM_SIZE_TYPE] = {
6006
+ average: averageSize.avg,
6007
+ count: averageSize.num
6008
+ };
6009
+ }
6010
+ }
6011
+ return averageItemSizes;
6012
+ }
5614
6013
  function createImperativeHandle(ctx) {
5615
6014
  const state = ctx.state;
5616
6015
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
5617
6016
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
5618
6017
  let imperativeScrollToken = 0;
5619
6018
  const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
6019
+ const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
6020
+ var _a3;
6021
+ const props = state.props;
6022
+ const dataLength = props.data.length;
6023
+ const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
6024
+ if (targetIndex < 0) {
6025
+ return allowEmpty;
6026
+ }
6027
+ if (targetIndex >= dataLength) {
6028
+ return false;
6029
+ }
6030
+ if (anchorIndex === void 0 || anchorIndex < 0 || anchorIndex >= dataLength || targetIndex < anchorIndex || props.getFixedItemSize) {
6031
+ return true;
6032
+ }
6033
+ for (let index = anchorIndex; index < dataLength; index++) {
6034
+ if (!state.sizesKnown.has(getId(state, index))) {
6035
+ return false;
6036
+ }
6037
+ }
6038
+ return true;
6039
+ };
5620
6040
  const runWhenReady = (token, run, isReady) => {
5621
6041
  const startedAt = Date.now();
5622
6042
  let stableFrames = 0;
@@ -5638,11 +6058,10 @@ function createImperativeHandle(ctx) {
5638
6058
  };
5639
6059
  requestAnimationFrame(check);
5640
6060
  };
5641
- const runScrollWithPromise = (run, options) => new Promise((resolve) => {
5642
- var _a3, _b;
6061
+ const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
6062
+ var _a3;
5643
6063
  const token = ++imperativeScrollToken;
5644
- const isReady = (_a3 = options == null ? void 0 : options.isReady) != null ? _a3 : (() => true);
5645
- (_b = state.pendingScrollResolve) == null ? void 0 : _b.call(state);
6064
+ (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
5646
6065
  state.pendingScrollResolve = resolve;
5647
6066
  const runNow = () => {
5648
6067
  if (token !== imperativeScrollToken) {
@@ -5717,6 +6136,7 @@ function createImperativeHandle(ctx) {
5717
6136
  },
5718
6137
  end: state.endNoBuffer,
5719
6138
  endBuffered: state.endBuffered,
6139
+ getAverageItemSizes: () => getAverageItemSizes(state),
5720
6140
  isAtEnd: peek$(ctx, "isAtEnd"),
5721
6141
  isAtStart: peek$(ctx, "isAtStart"),
5722
6142
  isEndReached: state.isEndReached,
@@ -5759,40 +6179,34 @@ function createImperativeHandle(ctx) {
5759
6179
  }
5760
6180
  return false;
5761
6181
  }),
5762
- scrollToEnd: (options) => runScrollWithPromise(() => {
5763
- const data = state.props.data;
5764
- const stylePaddingBottom = state.props.stylePaddingBottom;
5765
- const index = data.length - 1;
5766
- if (index !== -1) {
5767
- const paddingBottom = stylePaddingBottom || 0;
5768
- const footerSize = peek$(ctx, "footerSize") || 0;
5769
- scrollToIndex(ctx, {
5770
- ...options,
5771
- index,
5772
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5773
- viewPosition: 1
5774
- });
5775
- return true;
5776
- }
5777
- return false;
5778
- }),
5779
- scrollToIndex: (params) => {
5780
- const shouldWaitForOutOfRangeTarget = params.index >= 0 && params.index >= state.props.data.length;
5781
- const options = shouldWaitForOutOfRangeTarget ? {
5782
- isReady: () => {
5783
- var _a3;
5784
- const props = state.props;
5785
- const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5786
- const lastIndex = props.data.length - 1;
5787
- const isInRange = params.index < props.data.length;
5788
- const shouldWaitForAnchorSize = isInRange && anchorIndex !== void 0 && anchorIndex >= 0 && params.index >= anchorIndex && !props.getFixedItemSize && !state.sizesKnown.has(getId(state, lastIndex));
5789
- return isInRange && !shouldWaitForAnchorSize;
6182
+ scrollToEnd: (options) => runScrollWithPromise(
6183
+ () => {
6184
+ const data = state.props.data;
6185
+ const stylePaddingBottom = state.props.stylePaddingBottom;
6186
+ const index = data.length - 1;
6187
+ if (index !== -1) {
6188
+ const paddingBottom = stylePaddingBottom || 0;
6189
+ const footerSize = peek$(ctx, "footerSize") || 0;
6190
+ scrollToIndex(ctx, {
6191
+ ...options,
6192
+ index,
6193
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
6194
+ viewPosition: 1
6195
+ });
6196
+ return true;
5790
6197
  }
5791
- } : void 0;
5792
- return runScrollWithPromise(() => {
5793
- scrollToIndex(ctx, params);
5794
- return true;
5795
- }, options);
6198
+ return false;
6199
+ },
6200
+ () => isScrollToIndexReady(state.props.data.length - 1, true)
6201
+ ),
6202
+ scrollToIndex: (params) => {
6203
+ return runScrollWithPromise(
6204
+ () => {
6205
+ scrollToIndex(ctx, params);
6206
+ return true;
6207
+ },
6208
+ params.index >= 0 ? () => isScrollToIndexReady(params.index) : void 0
6209
+ );
5796
6210
  },
5797
6211
  scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
5798
6212
  const data = state.props.data;
@@ -6056,7 +6470,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6056
6470
  getFixedItemSize,
6057
6471
  getItemType,
6058
6472
  horizontal,
6059
- initialContainerPoolRatio = 2,
6473
+ rtl,
6474
+ initialContainerPoolRatio = 3,
6475
+ estimatedHeaderSize,
6060
6476
  initialScrollAtEnd = false,
6061
6477
  initialScrollIndex: initialScrollIndexProp,
6062
6478
  initialScrollOffset: initialScrollOffsetProp,
@@ -6097,7 +6513,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6097
6513
  stickyIndices: stickyIndicesDeprecated,
6098
6514
  // TODOV3: Remove from v3 release
6099
6515
  style: styleProp,
6100
- suggestEstimatedItemSize,
6101
6516
  useWindowScroll = false,
6102
6517
  viewabilityConfig,
6103
6518
  viewabilityConfigCallbackPairs,
@@ -6125,13 +6540,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6125
6540
  const style = { ...StyleSheet.flatten(styleProp) };
6126
6541
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
6127
6542
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
6543
+ const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
6544
+ const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
6128
6545
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
6129
6546
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
6130
6547
  maintainVisibleContentPositionProp
6131
6548
  );
6132
6549
  const hasInitialScrollIndex = initialScrollIndexProp !== void 0 && initialScrollIndexProp !== null;
6133
6550
  const hasInitialScrollOffset = initialScrollOffsetProp !== void 0 && initialScrollOffsetProp !== null;
6134
- const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && hasInitialScrollOffset;
6551
+ const shouldInitializeHorizontalRTL = !initialScrollAtEnd && !hasInitialScrollIndex && !hasInitialScrollOffset && isHorizontalRTLProps({ horizontal, rtl });
6552
+ const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && (hasInitialScrollOffset || shouldInitializeHorizontalRTL);
6135
6553
  const usesBootstrapInitialScroll = initialScrollAtEnd || hasInitialScrollIndex;
6136
6554
  const initialScrollProp = initialScrollAtEnd ? {
6137
6555
  index: Math.max(0, dataProp.length - 1),
@@ -6238,7 +6656,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6238
6656
  startReachedSnapshotDataChangeEpoch: void 0,
6239
6657
  stickyContainerPool: /* @__PURE__ */ new Set(),
6240
6658
  stickyContainers: /* @__PURE__ */ new Map(),
6241
- timeoutSizeMessage: 0,
6242
6659
  timeouts: /* @__PURE__ */ new Set(),
6243
6660
  totalSize: 0,
6244
6661
  viewabilityConfigCallbackPairs: void 0
@@ -6248,6 +6665,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6248
6665
  internalState.reprocessCurrentScroll = () => updateScroll(ctx, internalState.scroll, true);
6249
6666
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
6250
6667
  set$(ctx, "extraData", extraData);
6668
+ if (estimatedHeaderSize !== void 0) {
6669
+ set$(ctx, "headerSize", estimatedHeaderSize);
6670
+ }
6251
6671
  }
6252
6672
  refState.current = ctx.state;
6253
6673
  }
@@ -6258,7 +6678,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6258
6678
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
6259
6679
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
6260
6680
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
6261
- if (didDataChangeLocal && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6681
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6262
6682
  clearPreservedInitialScrollTarget(state);
6263
6683
  }
6264
6684
  if (didDataChangeLocal) {
@@ -6307,13 +6727,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6307
6727
  positionComponentInternal,
6308
6728
  recycleItems: !!recycleItems,
6309
6729
  renderItem,
6730
+ rtl,
6310
6731
  snapToIndices,
6311
6732
  stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
6312
6733
  stickyIndicesSet: useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
6313
6734
  stickyPositionComponentInternal,
6314
6735
  stylePaddingBottom: stylePaddingBottomState,
6736
+ stylePaddingLeft: stylePaddingLeftState,
6737
+ stylePaddingRight: stylePaddingRightState,
6315
6738
  stylePaddingTop: stylePaddingTopState,
6316
- suggestEstimatedItemSize: !!suggestEstimatedItemSize,
6317
6739
  useWindowScroll: useWindowScrollResolved
6318
6740
  };
6319
6741
  state.refScroller = refScroller;
@@ -6335,6 +6757,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6335
6757
  };
6336
6758
  if (isFirstLocal) {
6337
6759
  initializeStateVars(false);
6760
+ resetLayoutCachesForDataChange(state);
6338
6761
  updateItemPositions(
6339
6762
  ctx,
6340
6763
  /*dataChanged*/
@@ -6352,6 +6775,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6352
6775
  }, [usesBootstrapInitialScroll]);
6353
6776
  useLayoutEffect(() => {
6354
6777
  initializeInitialScrollOnMount(ctx, {
6778
+ alwaysDispatchInitialScroll: shouldInitializeHorizontalRTL,
6355
6779
  dataLength: dataProp.length,
6356
6780
  hasFooterComponent: !!ListFooterComponent,
6357
6781
  initialContentOffset,