@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.
package/index.mjs CHANGED
@@ -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
  });
@@ -643,12 +778,6 @@ function toLayout(rect) {
643
778
  };
644
779
  }
645
780
 
646
- // src/platform/Platform.ts
647
- var Platform = {
648
- // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
649
- OS: "web"
650
- };
651
-
652
781
  // src/utils/hasActiveMVCPAnchorLock.ts
653
782
  function hasActiveMVCPAnchorLock(state) {
654
783
  const lock = state.mvcpAnchorLock;
@@ -672,6 +801,7 @@ function getContainerPositionStyle({
672
801
  columnWrapperStyle,
673
802
  horizontal,
674
803
  hasItemSeparator,
804
+ isHorizontalRTLList,
675
805
  numColumns,
676
806
  otherAxisPos,
677
807
  otherAxisSize
@@ -695,6 +825,7 @@ function getContainerPositionStyle({
695
825
  }
696
826
  return horizontal ? {
697
827
  boxSizing: paddingStyles ? "border-box" : void 0,
828
+ direction: isHorizontalRTLList && Platform.OS === "web" ? "ltr" : void 0,
698
829
  flexDirection: hasItemSeparator ? "row" : void 0,
699
830
  height: otherAxisSize,
700
831
  left: 0,
@@ -713,6 +844,7 @@ function getContainerPositionStyle({
713
844
  }
714
845
  var Container = typedMemo(function Container2({
715
846
  id,
847
+ itemKey,
716
848
  recycleItems,
717
849
  horizontal,
718
850
  getRenderedItem: getRenderedItem2,
@@ -722,13 +854,13 @@ var Container = typedMemo(function Container2({
722
854
  }) {
723
855
  const ctx = useStateContext();
724
856
  const { columnWrapperStyle, animatedScrollY } = ctx;
857
+ const isHorizontalRTLList = isHorizontalRTL(ctx.state);
725
858
  const positionComponentInternal = ctx.state.props.positionComponentInternal;
726
859
  const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
727
- const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
860
+ const [column = 0, span = 1, data, numColumns = 1, extraData, isSticky] = useArr$([
728
861
  `containerColumn${id}`,
729
862
  `containerSpan${id}`,
730
863
  `containerItemData${id}`,
731
- `containerItemKey${id}`,
732
864
  "numColumns",
733
865
  "extraData",
734
866
  `containerSticky${id}`
@@ -754,11 +886,20 @@ var Container = typedMemo(function Container2({
754
886
  columnWrapperStyle,
755
887
  hasItemSeparator: !!ItemSeparatorComponent,
756
888
  horizontal,
889
+ isHorizontalRTLList,
757
890
  numColumns,
758
891
  otherAxisPos,
759
892
  otherAxisSize
760
893
  }),
761
- [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns, ItemSeparatorComponent]
894
+ [
895
+ horizontal,
896
+ isHorizontalRTLList,
897
+ otherAxisPos,
898
+ otherAxisSize,
899
+ columnWrapperStyle,
900
+ numColumns,
901
+ ItemSeparatorComponent
902
+ ]
762
903
  );
763
904
  const renderedItemInfo = useMemo(
764
905
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
@@ -846,6 +987,39 @@ var Container = typedMemo(function Container2({
846
987
  );
847
988
  });
848
989
 
990
+ // src/components/ContainerSlot.tsx
991
+ function ContainerSlotBase({
992
+ id,
993
+ horizontal,
994
+ recycleItems,
995
+ ItemSeparatorComponent,
996
+ updateItemSize: updateItemSize2,
997
+ getRenderedItem: getRenderedItem2,
998
+ stickyHeaderConfig,
999
+ ContainerComponent = Container
1000
+ }) {
1001
+ const [itemKey] = useArr$([`containerItemKey${id}`]);
1002
+ if (itemKey === void 0) {
1003
+ return null;
1004
+ }
1005
+ return /* @__PURE__ */ React3.createElement(
1006
+ ContainerComponent,
1007
+ {
1008
+ getRenderedItem: getRenderedItem2,
1009
+ horizontal,
1010
+ ItemSeparatorComponent,
1011
+ id,
1012
+ itemKey,
1013
+ recycleItems,
1014
+ stickyHeaderConfig,
1015
+ updateItemSize: updateItemSize2
1016
+ }
1017
+ );
1018
+ }
1019
+ var ContainerSlot = typedMemo(function ContainerSlot2(props) {
1020
+ return /* @__PURE__ */ React3.createElement(ContainerSlotBase, { ...props });
1021
+ });
1022
+
849
1023
  // src/utils/reordering.ts
850
1024
  var mapFn = (element) => {
851
1025
  const indexStr = element.getAttribute("data-index");
@@ -965,9 +1139,19 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
965
1139
  const ref = useRef(null);
966
1140
  const ctx = useStateContext();
967
1141
  const columnWrapperStyle = ctx.columnWrapperStyle;
968
- const [otherAxisSize, totalSize] = useArr$(["otherAxisSize", "totalSize"]);
1142
+ const isHorizontalRTLList = isHorizontalRTL(ctx.state);
1143
+ const [otherAxisSize, readyToRender, totalSize] = useArr$(["otherAxisSize", "readyToRender", "totalSize"]);
969
1144
  useDOMOrder(ref);
970
- const style = horizontal ? { minHeight: otherAxisSize, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, position: "relative" };
1145
+ const style = horizontal ? {
1146
+ direction: isHorizontalRTLList ? "ltr" : void 0,
1147
+ minHeight: otherAxisSize,
1148
+ opacity: readyToRender ? 1 : 0,
1149
+ position: "relative",
1150
+ width: totalSize
1151
+ } : { height: totalSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative" };
1152
+ if (!readyToRender) {
1153
+ style.pointerEvents = "none";
1154
+ }
971
1155
  if (columnWrapperStyle && numColumns > 1) {
972
1156
  const { columnGap, rowGap, gap } = columnWrapperStyle;
973
1157
  const gapX = columnGap || gap || 0;
@@ -995,12 +1179,12 @@ var Containers = typedMemo(function Containers2({
995
1179
  getRenderedItem: getRenderedItem2,
996
1180
  stickyHeaderConfig
997
1181
  }) {
998
- const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
1182
+ const [numContainersPooled, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
999
1183
  const containers = [];
1000
- for (let i = 0; i < numContainers; i++) {
1184
+ for (let i = 0; i < numContainersPooled; i++) {
1001
1185
  containers.push(
1002
1186
  /* @__PURE__ */ React3.createElement(
1003
- Container,
1187
+ ContainerSlot,
1004
1188
  {
1005
1189
  getRenderedItem: getRenderedItem2,
1006
1190
  horizontal,
@@ -1072,6 +1256,8 @@ function useRafCoalescer(callback) {
1072
1256
 
1073
1257
  // src/components/webConstants.ts
1074
1258
  var LEGEND_LIST_CONTENT_CONTAINER_CLASS = "legend-list-content-container";
1259
+ var LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS = "legend-list-scrollbar-x-hidden";
1260
+ var LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS = "legend-list-scrollbar-y-hidden";
1075
1261
 
1076
1262
  // src/components/webScrollUtils.ts
1077
1263
  function getDocumentScrollerNode() {
@@ -1157,11 +1343,47 @@ function resolveWindowScrollTarget({ clampedOffset, horizontal, listPos, scroll
1157
1343
  }
1158
1344
 
1159
1345
  // src/components/ListComponentScrollView.tsx
1346
+ var SCROLLBAR_HIDDEN_STYLE_ID = "legend-list-scrollbar-axis-hidden-style";
1347
+ 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;}`;
1348
+ function ensureScrollbarHiddenStyle() {
1349
+ if (typeof document === "undefined" || document.getElementById(SCROLLBAR_HIDDEN_STYLE_ID)) {
1350
+ return;
1351
+ }
1352
+ const styleElement = document.createElement("style");
1353
+ styleElement.id = SCROLLBAR_HIDDEN_STYLE_ID;
1354
+ styleElement.textContent = SCROLLBAR_HIDDEN_STYLE;
1355
+ document.head.appendChild(styleElement);
1356
+ }
1160
1357
  function getContentInsetEndAdjustmentEnd2(ctx) {
1161
1358
  var _a3, _b;
1162
1359
  const adjustment = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.contentInsetEndAdjustment;
1163
1360
  return Math.max(0, adjustment != null ? adjustment : 0);
1164
1361
  }
1362
+ function getFiniteSnapOffsets(snapToOffsets) {
1363
+ if (!(snapToOffsets == null ? void 0 : snapToOffsets.length)) {
1364
+ return [];
1365
+ }
1366
+ const snapOffsets = [];
1367
+ const seen = /* @__PURE__ */ new Set();
1368
+ for (const offset of snapToOffsets) {
1369
+ if (Number.isFinite(offset) && !seen.has(offset)) {
1370
+ seen.add(offset);
1371
+ snapOffsets.push(offset);
1372
+ }
1373
+ }
1374
+ return snapOffsets;
1375
+ }
1376
+ function getSnapAnchorStyle(offset, horizontal) {
1377
+ return {
1378
+ height: horizontal ? "100%" : 1,
1379
+ left: horizontal ? offset : 0,
1380
+ pointerEvents: "none",
1381
+ position: "absolute",
1382
+ scrollSnapAlign: "start",
1383
+ top: horizontal ? 0 : offset,
1384
+ width: horizontal ? 1 : "100%"
1385
+ };
1386
+ }
1165
1387
  var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1166
1388
  children,
1167
1389
  style,
@@ -1179,7 +1401,7 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1179
1401
  onLayout,
1180
1402
  ...props
1181
1403
  }, ref) {
1182
- var _a3, _b, _c;
1404
+ var _a3, _b, _c, _d;
1183
1405
  const ctx = useStateContext();
1184
1406
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
1185
1407
  const scrollRef = useRef(null);
@@ -1361,6 +1583,12 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1361
1583
  }
1362
1584
  };
1363
1585
  }, [isWindowScroll, onLayout]);
1586
+ const hiddenScrollIndicatorClassName = !isWindowScroll && (horizontal ? !showsHorizontalScrollIndicator && LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS : !showsVerticalScrollIndicator && LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS);
1587
+ useLayoutEffect(() => {
1588
+ if (hiddenScrollIndicatorClassName) {
1589
+ ensureScrollbarHiddenStyle();
1590
+ }
1591
+ }, [hiddenScrollIndicatorClassName]);
1364
1592
  const scrollViewStyle = {
1365
1593
  ...isWindowScroll ? {} : {
1366
1594
  overflow: "auto",
@@ -1388,11 +1616,59 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1388
1616
  contentInset: _contentInset,
1389
1617
  scrollEventThrottle: _scrollEventThrottle,
1390
1618
  ScrollComponent: _ScrollComponent,
1619
+ snapToOffsets,
1391
1620
  useWindowScroll: _useWindowScroll,
1621
+ className: scrollViewClassNameProp,
1392
1622
  ...webProps
1393
1623
  } = props;
1394
- 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));
1624
+ const snapOffsets = !isWindowScroll ? getFiniteSnapOffsets(snapToOffsets) : [];
1625
+ if (snapOffsets.length > 0) {
1626
+ scrollViewStyle.scrollSnapType = horizontal ? "x mandatory" : "y mandatory";
1627
+ contentStyle.position = (_d = contentStyle.position) != null ? _d : "relative";
1628
+ }
1629
+ const scrollViewClassName = hiddenScrollIndicatorClassName ? scrollViewClassNameProp ? `${scrollViewClassNameProp} ${hiddenScrollIndicatorClassName}` : hiddenScrollIndicatorClassName : scrollViewClassNameProp;
1630
+ if (IS_DEV) {
1631
+ if (/(?:^|\s)(?:[a-z0-9_-]+:)*gap(?:-[xy])?-(?:\[[^\]]+\]|[^\s]+)/.test(
1632
+ `${contentContainerClassName != null ? contentContainerClassName : ""} ${scrollViewClassNameProp != null ? scrollViewClassNameProp : ""}`
1633
+ )) {
1634
+ warnDevOnce(
1635
+ "className-gap",
1636
+ "className/contentContainerClassName gap classes are not supported in LegendList because it needs to use exact values internally. Use contentContainerStyle={{ gap: ... }} or columnWrapperStyle instead."
1637
+ );
1638
+ }
1639
+ }
1640
+ return /* @__PURE__ */ React3.createElement(
1641
+ "div",
1642
+ {
1643
+ className: scrollViewClassName,
1644
+ ref: scrollRef,
1645
+ ...webProps,
1646
+ style: scrollViewStyle
1647
+ },
1648
+ refreshControl,
1649
+ /* @__PURE__ */ React3.createElement("div", { className, ref: contentRef, style: contentStyle }, snapOffsets.map((offset) => /* @__PURE__ */ React3.createElement(
1650
+ "div",
1651
+ {
1652
+ "aria-hidden": true,
1653
+ "data-legend-list-snap-anchor": offset,
1654
+ key: `snap-${offset}`,
1655
+ style: getSnapAnchorStyle(offset, horizontal)
1656
+ }
1657
+ )), children, contentInsetEndAdjustmentSpacerStyle ? /* @__PURE__ */ React3.createElement("div", { "aria-hidden": true, style: contentInsetEndAdjustmentSpacerStyle }) : null)
1658
+ );
1395
1659
  });
1660
+
1661
+ // src/components/listComponentStyles.ts
1662
+ function getAutoOtherAxisStyle({
1663
+ horizontal,
1664
+ needsOtherAxisSize,
1665
+ otherAxisSize
1666
+ }) {
1667
+ if (!needsOtherAxisSize || !otherAxisSize || otherAxisSize <= 0) {
1668
+ return void 0;
1669
+ }
1670
+ return horizontal ? { height: otherAxisSize } : { width: otherAxisSize };
1671
+ }
1396
1672
  function useValueListener$(key, callback) {
1397
1673
  const ctx = useStateContext();
1398
1674
  useLayoutEffect(() => {
@@ -1419,11 +1695,18 @@ function getScrollAdjustAxis(horizontal) {
1419
1695
  y: 1
1420
1696
  };
1421
1697
  }
1422
- function resolveScrollAdjustContentNode(el, contentNode) {
1423
- if ((contentNode == null ? void 0 : contentNode.isConnected) && contentNode.parentElement === el) {
1424
- return contentNode;
1698
+ function getScrollAdjustTarget(ctx, contentNode) {
1699
+ var _a3, _b, _c;
1700
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1701
+ const scrollElement = (_c = (_b = scrollView == null ? void 0 : scrollView.getScrollableNode) == null ? void 0 : _b.call(scrollView)) != null ? _c : null;
1702
+ let resolvedContentNode = null;
1703
+ if (scrollElement) {
1704
+ resolvedContentNode = (contentNode == null ? void 0 : contentNode.isConnected) && contentNode.parentElement === scrollElement ? contentNode : scrollElement.querySelector(`:scope > .${LEGEND_LIST_CONTENT_CONTAINER_CLASS}`);
1425
1705
  }
1426
- return el.querySelector(`:scope > .${LEGEND_LIST_CONTENT_CONTAINER_CLASS}`);
1706
+ return scrollElement ? { contentNode: resolvedContentNode, scrollElement } : null;
1707
+ }
1708
+ function scrollAdjustBy(el, left, top) {
1709
+ el.scrollBy({ behavior: "auto", left, top });
1427
1710
  }
1428
1711
  function ScrollAdjust() {
1429
1712
  const ctx = useStateContext();
@@ -1432,43 +1715,43 @@ function ScrollAdjust() {
1432
1715
  const resetPaddingBaselineRef = React3.useRef(void 0);
1433
1716
  const contentNodeRef = React3.useRef(null);
1434
1717
  const callback = React3.useCallback(() => {
1435
- var _a3, _b;
1718
+ var _a3;
1436
1719
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1437
1720
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1438
1721
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1439
- const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1440
- if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1441
- const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1442
- if (scrollDelta !== 0) {
1443
- const axis = getScrollAdjustAxis(!!ctx.state.props.horizontal);
1444
- const prevScroll = scrollView.getCurrentScrollOffset();
1445
- const el = scrollView.getScrollableNode();
1446
- const contentNode = resolveScrollAdjustContentNode(el, contentNodeRef.current);
1722
+ const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1723
+ if (scrollDelta !== 0) {
1724
+ const target = getScrollAdjustTarget(ctx, contentNodeRef.current);
1725
+ if (target) {
1726
+ const horizontal = !!ctx.state.props.horizontal;
1727
+ const axis = getScrollAdjustAxis(horizontal);
1728
+ const { contentNode, scrollElement: el } = target;
1729
+ const scrollBy = () => scrollAdjustBy(el, axis.x * scrollDelta, axis.y * scrollDelta);
1447
1730
  contentNodeRef.current = contentNode;
1448
- const scrollBy = () => scrollView.scrollBy(axis.x * scrollDelta, axis.y * scrollDelta);
1449
- if (!contentNode) {
1450
- scrollBy();
1451
- lastScrollOffsetRef.current = scrollOffset;
1452
- return;
1453
- }
1454
- const totalSize = contentNode[axis.contentSizeKey];
1455
- const viewportSize = el[axis.viewportSizeKey];
1456
- const nextScroll = prevScroll + scrollDelta;
1457
- if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize) {
1458
- const previousPaddingEnd = (_b = resetPaddingBaselineRef.current) != null ? _b : contentNode.style[axis.paddingEndProp];
1459
- resetPaddingBaselineRef.current = previousPaddingEnd;
1460
- const pad = (nextScroll + viewportSize - totalSize) * 2;
1461
- contentNode.style[axis.paddingEndProp] = `${pad}px`;
1462
- void contentNode.offsetHeight;
1463
- scrollBy();
1464
- if (resetPaddingRafRef.current !== void 0) {
1465
- cancelAnimationFrame(resetPaddingRafRef.current);
1731
+ if (contentNode) {
1732
+ const prevScroll = horizontal ? el.scrollLeft : el.scrollTop;
1733
+ const totalSize = contentNode[axis.contentSizeKey];
1734
+ const viewportSize = el[axis.viewportSizeKey];
1735
+ const nextScroll = prevScroll + scrollDelta;
1736
+ const needsTemporaryPadding = scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize;
1737
+ if (needsTemporaryPadding) {
1738
+ const previousPaddingEnd = (_a3 = resetPaddingBaselineRef.current) != null ? _a3 : contentNode.style[axis.paddingEndProp];
1739
+ resetPaddingBaselineRef.current = previousPaddingEnd;
1740
+ const pad = (nextScroll + viewportSize - totalSize) * 2;
1741
+ contentNode.style[axis.paddingEndProp] = `${pad}px`;
1742
+ void contentNode.offsetHeight;
1743
+ scrollBy();
1744
+ if (resetPaddingRafRef.current !== void 0) {
1745
+ cancelAnimationFrame(resetPaddingRafRef.current);
1746
+ }
1747
+ resetPaddingRafRef.current = requestAnimationFrame(() => {
1748
+ resetPaddingRafRef.current = void 0;
1749
+ resetPaddingBaselineRef.current = void 0;
1750
+ contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1751
+ });
1752
+ } else {
1753
+ scrollBy();
1466
1754
  }
1467
- resetPaddingRafRef.current = requestAnimationFrame(() => {
1468
- resetPaddingRafRef.current = void 0;
1469
- resetPaddingBaselineRef.current = void 0;
1470
- contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1471
- });
1472
1755
  } else {
1473
1756
  scrollBy();
1474
1757
  }
@@ -1480,10 +1763,10 @@ function ScrollAdjust() {
1480
1763
  useValueListener$("scrollAdjustUserOffset", callback);
1481
1764
  return null;
1482
1765
  }
1483
- function SnapWrapper({ ScrollComponent, ...props }) {
1766
+ var SnapWrapper = React3.forwardRef(function SnapWrapperInner({ ScrollComponent, ...props }, ref) {
1484
1767
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
1485
- return /* @__PURE__ */ React3.createElement(ScrollComponent, { ...props, snapToOffsets });
1486
- }
1768
+ return /* @__PURE__ */ React3.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
1769
+ });
1487
1770
  function WebAnchoredEndSpace({ horizontal }) {
1488
1771
  const ctx = useStateContext();
1489
1772
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
@@ -1500,15 +1783,6 @@ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1500
1783
  useOnLayoutSync({ onLayoutChange, ref });
1501
1784
  return /* @__PURE__ */ React3.createElement("div", { ...rest, ref }, children);
1502
1785
  };
1503
- var getComponent = (Component) => {
1504
- if (React3.isValidElement(Component)) {
1505
- return Component;
1506
- }
1507
- if (Component) {
1508
- return /* @__PURE__ */ React3.createElement(Component, null);
1509
- }
1510
- return null;
1511
- };
1512
1786
 
1513
1787
  // src/components/ListComponent.tsx
1514
1788
  var ListComponent = typedMemo(function ListComponent2({
@@ -1541,6 +1815,12 @@ var ListComponent = typedMemo(function ListComponent2({
1541
1815
  }) {
1542
1816
  const ctx = useStateContext();
1543
1817
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1818
+ const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
1819
+ const autoOtherAxisStyle = getAutoOtherAxisStyle({
1820
+ horizontal,
1821
+ needsOtherAxisSize: ctx.state.needsOtherAxisSize,
1822
+ otherAxisSize
1823
+ });
1544
1824
  const ScrollComponent = useMemo(() => {
1545
1825
  if (!renderScrollComponent) {
1546
1826
  return ListComponentScrollView;
@@ -1579,10 +1859,10 @@ var ListComponent = typedMemo(function ListComponent2({
1579
1859
  ...rest,
1580
1860
  ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1581
1861
  contentContainerStyle: [
1582
- contentContainerStyle,
1583
1862
  horizontal ? {
1584
1863
  height: "100%"
1585
- } : {}
1864
+ } : {},
1865
+ contentContainerStyle
1586
1866
  ],
1587
1867
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1588
1868
  horizontal,
@@ -1591,7 +1871,7 @@ var ListComponent = typedMemo(function ListComponent2({
1591
1871
  onScroll: onScroll2,
1592
1872
  ref: refScrollView,
1593
1873
  ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1594
- style
1874
+ style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
1595
1875
  },
1596
1876
  /* @__PURE__ */ React3.createElement(ScrollAdjust, null),
1597
1877
  ListHeaderComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
@@ -1779,10 +2059,9 @@ var initialScrollWatchdog = {
1779
2059
  clear(state) {
1780
2060
  initialScrollWatchdog.set(state, void 0);
1781
2061
  },
1782
- didObserveProgress(newScroll, watchdog) {
1783
- const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
2062
+ didReachTarget(newScroll, watchdog) {
1784
2063
  const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
1785
- return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET || nextDistance + INITIAL_SCROLL_MIN_TARGET_OFFSET < previousDistance;
2064
+ return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET;
1786
2065
  },
1787
2066
  get(state) {
1788
2067
  var _a3, _b;
@@ -1807,19 +2086,19 @@ var initialScrollWatchdog = {
1807
2086
  }
1808
2087
  };
1809
2088
  function setInitialScrollSession(state, options = {}) {
1810
- var _a3, _b, _c;
2089
+ var _a3, _b, _c, _d;
1811
2090
  const existingSession = state.initialScrollSession;
1812
2091
  const kind = (_a3 = options.kind) != null ? _a3 : existingSession == null ? void 0 : existingSession.kind;
1813
2092
  const completion = existingSession == null ? void 0 : existingSession.completion;
1814
- const hasBootstrapOverride = Object.hasOwn(options, "bootstrap");
1815
- const bootstrap = kind === "bootstrap" ? hasBootstrapOverride ? options.bootstrap : (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0 : void 0;
2093
+ const existingBootstrap = (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0;
2094
+ const bootstrap = kind === "bootstrap" ? options.bootstrap === null ? void 0 : (_b = options.bootstrap) != null ? _b : existingBootstrap : void 0;
1816
2095
  if (!kind) {
1817
2096
  return clearInitialScrollSession(state);
1818
2097
  }
1819
2098
  if (!state.initialScroll && !bootstrap && !hasInitialScrollSessionCompletion(completion)) {
1820
2099
  return clearInitialScrollSession(state);
1821
2100
  }
1822
- const previousDataLength = (_c = (_b = options.previousDataLength) != null ? _b : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _c : 0;
2101
+ const previousDataLength = (_d = (_c = options.previousDataLength) != null ? _c : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _d : 0;
1823
2102
  state.initialScrollSession = createInitialScrollSession({
1824
2103
  bootstrap,
1825
2104
  completion,
@@ -2309,7 +2588,8 @@ function doScrollTo(ctx, params) {
2309
2588
  }
2310
2589
  const isAnimated = !!animated;
2311
2590
  const isHorizontal = !!horizontal;
2312
- const left = isHorizontal ? offset : 0;
2591
+ const contentSize = isHorizontal ? getContentSize(ctx) : void 0;
2592
+ const left = isHorizontal ? toNativeHorizontalOffset(state, offset, contentSize) : 0;
2313
2593
  const top = isHorizontal ? 0 : offset;
2314
2594
  scroller.scrollTo({ animated: isAnimated, x: left, y: top });
2315
2595
  if (isAnimated) {
@@ -2571,7 +2851,7 @@ function advanceMeasuredInitialScroll(ctx, options) {
2571
2851
  const activeInitialTargetOffset = scrollingTo ? (_a3 = scrollingTo.targetOffset) != null ? _a3 : scrollingTo.offset : void 0;
2572
2852
  const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - resolvedOffset) > 1;
2573
2853
  const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - resolvedOffset) > 1;
2574
- const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - activeInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - activeInitialTargetOffset) <= 1;
2854
+ const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - resolvedOffset) <= 1 && Math.abs(state.scrollPending - resolvedOffset) <= 1;
2575
2855
  if (!(options == null ? void 0 : options.forceScroll) && !didOffsetChange && isInitialScrollInProgress && !didActiveInitialTargetChange) {
2576
2856
  return false;
2577
2857
  }
@@ -2643,6 +2923,30 @@ function checkAllSizesKnown(state, indices) {
2643
2923
  });
2644
2924
  }
2645
2925
 
2926
+ // src/utils/requestAdjust.ts
2927
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2928
+ const state = ctx.state;
2929
+ if (Math.abs(positionDiff) > 0.1) {
2930
+ const doit = () => {
2931
+ {
2932
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
2933
+ if (state.adjustingFromInitialMount) {
2934
+ state.adjustingFromInitialMount--;
2935
+ }
2936
+ }
2937
+ };
2938
+ state.scroll += positionDiff;
2939
+ state.scrollForNextCalculateItemsInView = void 0;
2940
+ const readyToRender = peek$(ctx, "readyToRender");
2941
+ if (readyToRender) {
2942
+ doit();
2943
+ } else {
2944
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2945
+ requestAnimationFrame(doit);
2946
+ }
2947
+ }
2948
+ }
2949
+
2646
2950
  // src/core/bootstrapInitialScroll.ts
2647
2951
  var DEFAULT_BOOTSTRAP_REVEAL_EPSILON = 1;
2648
2952
  var DEFAULT_BOOTSTRAP_REVEAL_MAX_FRAMES = 8;
@@ -2736,7 +3040,7 @@ function clearBootstrapInitialScrollSession(state) {
2736
3040
  bootstrapInitialScroll.frameHandle = void 0;
2737
3041
  }
2738
3042
  setInitialScrollSession(state, {
2739
- bootstrap: void 0,
3043
+ bootstrap: null,
2740
3044
  kind: (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind
2741
3045
  });
2742
3046
  }
@@ -2892,15 +3196,18 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2892
3196
  return;
2893
3197
  }
2894
3198
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2895
- if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2896
- clearPendingInitialScrollFooterLayout(ctx, {
2897
- dataLength: state.props.data.length,
2898
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2899
- target: initialScroll
2900
- });
2901
- return;
3199
+ const shouldKeepEndTargetAlive = isRetargetableBottomAlignedInitialScrollTarget(initialScroll) && peek$(ctx, "isAtEnd");
3200
+ if (!shouldKeepEndTargetAlive) {
3201
+ if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
3202
+ clearPendingInitialScrollFooterLayout(ctx, {
3203
+ dataLength: state.props.data.length,
3204
+ stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
3205
+ target: initialScroll
3206
+ });
3207
+ } else {
3208
+ clearFinishedViewportRetargetableInitialScroll(state);
3209
+ }
2902
3210
  }
2903
- clearFinishedViewportRetargetableInitialScroll(state);
2904
3211
  }
2905
3212
  }
2906
3213
  function startBootstrapInitialScrollOnMount(ctx, options) {
@@ -2939,7 +3246,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2939
3246
  }
2940
3247
  const shouldResetDidFinish = !!(state.didFinishInitialScroll && previousDataLength === 0 && dataLength > 0 && initialScroll.index !== void 0);
2941
3248
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2942
- const shouldClearFinishedResizePreservation = didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
3249
+ const shouldClearFinishedResizePreservation = !initialScrollAtEnd && didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
2943
3250
  if (shouldClearFinishedResizePreservation) {
2944
3251
  clearPreservedInitialScrollTarget(state);
2945
3252
  return;
@@ -3042,27 +3349,46 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
3042
3349
  }
3043
3350
  }
3044
3351
  function handleBootstrapInitialScrollLayoutChange(ctx) {
3352
+ var _a3, _b, _c, _d;
3045
3353
  const state = ctx.state;
3046
3354
  const initialScroll = state.initialScroll;
3047
- if (isOffsetInitialScrollSession(state) || state.props.data.length === 0 || !initialScroll) {
3048
- return;
3049
- }
3050
3355
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
3051
- if (!bootstrapInitialScroll && initialScroll.viewPosition !== 1) {
3052
- return;
3053
- }
3054
- const didFinishInitialScroll = state.didFinishInitialScroll;
3055
- if (didFinishInitialScroll) {
3056
- setInitialScrollTarget(state, initialScroll, {
3057
- resetDidFinish: true
3058
- });
3059
- state.clearPreservedInitialScrollOnNextFinish = true;
3356
+ if (initialScroll && state.props.data.length > 0 && !isOffsetInitialScrollSession(state) && (bootstrapInitialScroll || initialScroll.viewPosition === 1)) {
3357
+ const resolvedOffset = resolveInitialScrollOffset(ctx, initialScroll);
3358
+ const scrollingTo = ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) ? state.scrollingTo : void 0;
3359
+ if (!bootstrapInitialScroll && (scrollingTo || state.didFinishInitialScroll)) {
3360
+ const currentOffset = scrollingTo ? (_b = scrollingTo.targetOffset) != null ? _b : scrollingTo.offset : getObservedBootstrapInitialScrollOffset(state);
3361
+ const offsetDiff = resolvedOffset - currentOffset;
3362
+ if (Math.abs(offsetDiff) > DEFAULT_BOOTSTRAP_REVEAL_EPSILON) {
3363
+ if (scrollingTo) {
3364
+ const existingWatchdog = initialScrollWatchdog.get(state);
3365
+ scrollingTo.offset = resolvedOffset;
3366
+ scrollingTo.targetOffset = resolvedOffset;
3367
+ state.initialScroll = {
3368
+ ...initialScroll,
3369
+ contentOffset: resolvedOffset
3370
+ };
3371
+ state.hasScrolled = false;
3372
+ initialScrollWatchdog.set(state, {
3373
+ startScroll: (_c = existingWatchdog == null ? void 0 : existingWatchdog.startScroll) != null ? _c : state.scroll,
3374
+ targetOffset: resolvedOffset
3375
+ });
3376
+ }
3377
+ requestAdjust(ctx, offsetDiff);
3378
+ if (state.didFinishInitialScroll) {
3379
+ (_d = state.triggerCalculateItemsInView) == null ? void 0 : _d.call(state, { forceFullItemPositions: true });
3380
+ }
3381
+ }
3382
+ if (state.didFinishInitialScroll) {
3383
+ clearFinishedViewportRetargetableInitialScroll(state);
3384
+ }
3385
+ } else {
3386
+ rearmBootstrapInitialScroll(ctx, {
3387
+ scroll: resolvedOffset,
3388
+ targetIndexSeed: initialScroll.index
3389
+ });
3390
+ }
3060
3391
  }
3061
- rearmBootstrapInitialScroll(ctx, {
3062
- scroll: resolveInitialScrollOffset(ctx, initialScroll),
3063
- seedContentOffset: didFinishInitialScroll && !bootstrapInitialScroll ? getObservedBootstrapInitialScrollOffset(state) : void 0,
3064
- targetIndexSeed: initialScroll.index
3065
- });
3066
3392
  }
3067
3393
  function evaluateBootstrapInitialScroll(ctx) {
3068
3394
  var _a3, _b;
@@ -3269,7 +3595,7 @@ function checkFinishedScrollFallback(ctx) {
3269
3595
  state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
3270
3596
  };
3271
3597
  const checkHasScrolled = () => {
3272
- var _c;
3598
+ var _c, _d;
3273
3599
  state.timeoutCheckFinishedScrollFallback = void 0;
3274
3600
  const isStillScrollingTo = state.scrollingTo;
3275
3601
  if (isStillScrollingTo) {
@@ -3282,11 +3608,13 @@ function checkFinishedScrollFallback(ctx) {
3282
3608
  isStillScrollingTo
3283
3609
  );
3284
3610
  const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
3285
- const canFinishAfterSilentNativeDispatch = silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
3286
- if (shouldFinishZeroTarget || state.hasScrolled || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3611
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
3612
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
3613
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
3614
+ if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3287
3615
  finishScrollTo(ctx);
3288
- } else if (isNativeInitialPending && numChecks <= maxChecks) {
3289
- const targetOffset = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : state.scrollPending;
3616
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
3617
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
3290
3618
  scrollToFallbackOffset(ctx, targetOffset);
3291
3619
  scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3292
3620
  } else {
@@ -3322,7 +3650,14 @@ function handleInitialScrollLayoutReady(ctx) {
3322
3650
  }
3323
3651
  function initializeInitialScrollOnMount(ctx, options) {
3324
3652
  var _a3, _b;
3325
- const { dataLength, hasFooterComponent, initialContentOffset, initialScrollAtEnd, useBootstrapInitialScroll } = options;
3653
+ const {
3654
+ alwaysDispatchInitialScroll,
3655
+ dataLength,
3656
+ hasFooterComponent,
3657
+ initialContentOffset,
3658
+ initialScrollAtEnd,
3659
+ useBootstrapInitialScroll
3660
+ } = options;
3326
3661
  const state = ctx.state;
3327
3662
  const initialScroll = state.initialScroll;
3328
3663
  const resolvedInitialContentOffset = initialContentOffset != null ? initialContentOffset : 0;
@@ -3342,7 +3677,7 @@ function initializeInitialScrollOnMount(ctx, options) {
3342
3677
  return;
3343
3678
  }
3344
3679
  const hasPendingDataDependentInitialScroll = !!initialScroll && dataLength === 0 && !(resolvedInitialContentOffset === 0 && !initialScrollAtEnd);
3345
- if (!resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
3680
+ if (!alwaysDispatchInitialScroll && !resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
3346
3681
  if (initialScroll && !initialScrollAtEnd) {
3347
3682
  finishInitialScroll(ctx, {
3348
3683
  resolvedOffset: resolvedInitialContentOffset
@@ -3381,30 +3716,6 @@ function handleInitialScrollDataChange(ctx, options) {
3381
3716
  advanceCurrentInitialScrollSession(ctx);
3382
3717
  }
3383
3718
 
3384
- // src/utils/requestAdjust.ts
3385
- function requestAdjust(ctx, positionDiff, dataChanged) {
3386
- const state = ctx.state;
3387
- if (Math.abs(positionDiff) > 0.1) {
3388
- const doit = () => {
3389
- {
3390
- state.scrollAdjustHandler.requestAdjust(positionDiff);
3391
- if (state.adjustingFromInitialMount) {
3392
- state.adjustingFromInitialMount--;
3393
- }
3394
- }
3395
- };
3396
- state.scroll += positionDiff;
3397
- state.scrollForNextCalculateItemsInView = void 0;
3398
- const readyToRender = peek$(ctx, "readyToRender");
3399
- if (readyToRender) {
3400
- doit();
3401
- } else {
3402
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
3403
- requestAnimationFrame(doit);
3404
- }
3405
- }
3406
- }
3407
-
3408
3719
  // src/core/mvcp.ts
3409
3720
  var MVCP_POSITION_EPSILON = 0.1;
3410
3721
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -3678,15 +3989,27 @@ function prepareMVCP(ctx, dataChanged) {
3678
3989
  return;
3679
3990
  }
3680
3991
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
3681
- requestAdjust(ctx, positionDiff);
3992
+ const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
3993
+ if (!shouldSkipAdjustForMaintainedEnd) {
3994
+ requestAdjust(ctx, positionDiff);
3995
+ }
3682
3996
  }
3683
3997
  };
3684
3998
  }
3685
3999
  }
3686
4000
 
4001
+ // src/core/resetLayoutCachesForDataChange.ts
4002
+ function resetLayoutCachesForDataChange(state) {
4003
+ state.indexByKey.clear();
4004
+ state.idCache.length = 0;
4005
+ state.positions.length = 0;
4006
+ state.columns.length = 0;
4007
+ state.columnSpans.length = 0;
4008
+ }
4009
+
3687
4010
  // src/core/syncMountedContainer.ts
3688
4011
  function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3689
- var _a3, _b, _c, _d, _e, _f, _g, _h;
4012
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
3690
4013
  const state = ctx.state;
3691
4014
  const {
3692
4015
  columns,
@@ -3698,7 +4021,8 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3698
4021
  if (item === void 0) {
3699
4022
  return { didChangePosition: false, didRefreshData: false };
3700
4023
  }
3701
- const updateLayout = (_a3 = options == null ? void 0 : options.updateLayout) != null ? _a3 : true;
4024
+ const itemKey = (_a3 = state.idCache[itemIndex]) != null ? _a3 : getId(state, itemIndex);
4025
+ const updateLayout = (_b = options == null ? void 0 : options.updateLayout) != null ? _b : true;
3702
4026
  let didChangePosition = false;
3703
4027
  let didRefreshData = false;
3704
4028
  if (updateLayout) {
@@ -3707,7 +4031,9 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3707
4031
  set$(ctx, `containerPosition${containerIndex}`, POSITION_OUT_OF_VIEW);
3708
4032
  return { didChangePosition: false, didRefreshData: false };
3709
4033
  }
3710
- const position = (positionValue || 0) - ((_b = options == null ? void 0 : options.scrollAdjustPending) != null ? _b : 0);
4034
+ const logicalPosition = (positionValue || 0) - ((_c = options == null ? void 0 : options.scrollAdjustPending) != null ? _c : 0);
4035
+ const itemSize = (_d = state.sizes.get(itemKey)) != null ? _d : getItemSize(ctx, itemKey, itemIndex, item);
4036
+ const position = toPhysicalHorizontalItemPosition(state, logicalPosition, itemSize, peek$(ctx, "totalSize"));
3711
4037
  const column = columns[itemIndex] || 1;
3712
4038
  const span = columnSpans[itemIndex] || 1;
3713
4039
  const prevPos = peek$(ctx, `containerPosition${containerIndex}`);
@@ -3726,15 +4052,15 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3726
4052
  }
3727
4053
  const prevData = peek$(ctx, `containerItemData${containerIndex}`);
3728
4054
  if (prevData !== item) {
3729
- 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;
3730
- const cachedComparison = (_e = pendingDataComparison == null ? void 0 : pendingDataComparison.byIndex[itemIndex]) != null ? _e : 0;
4055
+ 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;
4056
+ const cachedComparison = (_g = pendingDataComparison == null ? void 0 : pendingDataComparison.byIndex[itemIndex]) != null ? _g : 0;
3731
4057
  if (cachedComparison === 2) {
3732
4058
  set$(ctx, `containerItemData${containerIndex}`, item);
3733
4059
  didRefreshData = true;
3734
4060
  } else if (cachedComparison !== 1) {
3735
- const itemKey = (_g = (_f = peek$(ctx, `containerItemKey${containerIndex}`)) != null ? _f : state.idCache[itemIndex]) != null ? _g : getId(state, itemIndex);
4061
+ const nextItemKey = (_h = peek$(ctx, `containerItemKey${containerIndex}`)) != null ? _h : itemKey;
3736
4062
  const prevKey = keyExtractor == null ? void 0 : keyExtractor(prevData, itemIndex);
3737
- if (prevData === void 0 || !keyExtractor || prevKey !== itemKey) {
4063
+ if (prevData === void 0 || !keyExtractor || prevKey !== nextItemKey) {
3738
4064
  set$(ctx, `containerItemData${containerIndex}`, item);
3739
4065
  didRefreshData = true;
3740
4066
  } else if (!itemsAreEqual) {
@@ -3751,7 +4077,7 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3751
4077
  };
3752
4078
  }
3753
4079
  }
3754
- if ((_h = state.pendingDataComparison) == null ? void 0 : _h.byIndex) {
4080
+ if ((_i = state.pendingDataComparison) == null ? void 0 : _i.byIndex) {
3755
4081
  state.pendingDataComparison.byIndex[itemIndex] = isEqual ? 1 : 2;
3756
4082
  }
3757
4083
  if (!isEqual) {
@@ -3916,11 +4242,13 @@ function updateSnapToOffsets(ctx) {
3916
4242
  const {
3917
4243
  props: { snapToIndices }
3918
4244
  } = state;
4245
+ const contentSize = state.props.horizontal ? getContentSize(ctx) : void 0;
3919
4246
  const snapToOffsets = Array(snapToIndices.length);
3920
4247
  for (let i = 0; i < snapToIndices.length; i++) {
3921
4248
  const idx = snapToIndices[i];
3922
4249
  getId(state, idx);
3923
- snapToOffsets[i] = state.positions[idx];
4250
+ const logicalOffset = state.positions[idx];
4251
+ snapToOffsets[i] = toNativeHorizontalOffset(state, logicalOffset, contentSize);
3924
4252
  }
3925
4253
  set$(ctx, "snapToOffsets", snapToOffsets);
3926
4254
  }
@@ -4297,6 +4625,30 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
4297
4625
  var unstableBatchedUpdates = ReactDOM.unstable_batchedUpdates;
4298
4626
  var batchedUpdates = typeof unstableBatchedUpdates === "function" ? unstableBatchedUpdates : (fn) => fn();
4299
4627
 
4628
+ // src/utils/containerPool.ts
4629
+ var MIN_INITIAL_CONTAINER_POOL_SIZE = 32;
4630
+ var MAX_INITIAL_SPARE_CONTAINERS = 64;
4631
+ function getInitialContainerPoolSize(dataLength, numContainers, initialContainerPoolRatio) {
4632
+ if (dataLength <= 0 || numContainers <= 0) {
4633
+ return 0;
4634
+ }
4635
+ const ratioPoolSize = Math.ceil(numContainers * initialContainerPoolRatio);
4636
+ const cappedSparePoolSize = numContainers + MAX_INITIAL_SPARE_CONTAINERS;
4637
+ const targetPoolSize = Math.max(
4638
+ numContainers,
4639
+ Math.min(ratioPoolSize, cappedSparePoolSize),
4640
+ Math.min(dataLength, MIN_INITIAL_CONTAINER_POOL_SIZE)
4641
+ );
4642
+ const maxUsefulPoolSize = Math.max(dataLength, numContainers);
4643
+ return Math.min(maxUsefulPoolSize, targetPoolSize);
4644
+ }
4645
+ function getExpandedContainerPoolSize(dataLength, numContainers) {
4646
+ if (dataLength <= 0 || numContainers <= 0) {
4647
+ return 0;
4648
+ }
4649
+ return Math.min(Math.max(dataLength, numContainers), Math.max(numContainers, Math.ceil(numContainers * 1.5)));
4650
+ }
4651
+
4300
4652
  // src/utils/findAvailableContainers.ts
4301
4653
  function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers, protectedKeys) {
4302
4654
  const numContainers = peek$(ctx, "numContainers");
@@ -4502,10 +4854,9 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
4502
4854
  function calculateItemsInView(ctx, params = {}) {
4503
4855
  const state = ctx.state;
4504
4856
  batchedUpdates(() => {
4505
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
4857
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
4506
4858
  const {
4507
4859
  columns,
4508
- columnSpans,
4509
4860
  containerItemKeys,
4510
4861
  enableScrollForNextCalculateItemsInView,
4511
4862
  idCache,
@@ -4549,18 +4900,38 @@ function calculateItemsInView(ctx, params = {}) {
4549
4900
  // current initial-scroll target instead of transient native adjustments.
4550
4901
  resolveInitialScrollOffset(ctx, initialScroll)
4551
4902
  ) : state.scroll;
4552
- const scrollAdjustPending = (_c = peek$(ctx, "scrollAdjustPending")) != null ? _c : 0;
4553
- const scrollAdjustPad = scrollAdjustPending - topPad;
4554
- let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
4555
- if (scroll + scrollLength > totalSize) {
4556
- scroll = Math.max(0, totalSize - scrollLength);
4557
- }
4903
+ let scrollAdjustPending = 0;
4904
+ let scrollAdjustPad = 0;
4905
+ let scroll = 0;
4906
+ let scrollTopBuffered = 0;
4907
+ let scrollBottom = 0;
4908
+ let scrollBottomBuffered = 0;
4909
+ let nativeScrollState = scrollState;
4910
+ const updateScroll2 = (nextScrollState) => {
4911
+ var _a4;
4912
+ nativeScrollState = nextScrollState;
4913
+ scrollAdjustPending = (_a4 = peek$(ctx, "scrollAdjustPending")) != null ? _a4 : 0;
4914
+ scrollAdjustPad = scrollAdjustPending - topPad;
4915
+ scroll = Math.round(nextScrollState + scrollExtra + scrollAdjustPad);
4916
+ if (scroll + scrollLength > totalSize) {
4917
+ scroll = Math.max(0, totalSize - scrollLength);
4918
+ }
4919
+ };
4920
+ updateScroll2(scrollState);
4558
4921
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
4559
4922
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
4560
4923
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
4924
+ const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
4561
4925
  if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
4562
4926
  set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
4563
4927
  }
4928
+ const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyIndicesArr.length > 0 && stickyIndexDidChange;
4929
+ const finishCalculateItemsInView = shouldNotifyStickyHeaderChange ? () => {
4930
+ const item = data[nextActiveStickyIndex];
4931
+ if (item !== void 0) {
4932
+ onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4933
+ }
4934
+ } : void 0;
4564
4935
  let scrollBufferTop = drawDistance;
4565
4936
  let scrollBufferBottom = drawDistance;
4566
4937
  if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
@@ -4570,28 +4941,30 @@ function calculateItemsInView(ctx, params = {}) {
4570
4941
  scrollBufferTop = drawDistance * 1.5;
4571
4942
  scrollBufferBottom = drawDistance * 0.5;
4572
4943
  }
4573
- const scrollTopBuffered = scroll - scrollBufferTop;
4574
- const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
4575
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4944
+ const updateScrollRange = () => {
4945
+ const scrollStart = Math.max(0, scroll);
4946
+ const overscrollBeforeContent = Math.max(0, -nativeScrollState);
4947
+ scrollTopBuffered = scrollStart - scrollBufferTop;
4948
+ scrollBottom = Math.max(scrollStart, scroll + scrollLength + overscrollBeforeContent);
4949
+ scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4950
+ };
4951
+ updateScrollRange();
4576
4952
  if (!suppressInitialScrollSideEffects && !dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
4577
4953
  const { top, bottom } = scrollForNextCalculateItemsInView;
4578
4954
  if (top === null && bottom === null) {
4579
4955
  state.scrollForNextCalculateItemsInView = void 0;
4580
4956
  } else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
4581
4957
  if (!isInMVCPActiveMode(state)) {
4958
+ finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4582
4959
  return;
4583
4960
  }
4584
4961
  }
4585
4962
  }
4586
4963
  const checkMVCP = doMVCP && !suppressInitialScrollSideEffects ? prepareMVCP(ctx, dataChanged) : void 0;
4587
4964
  if (dataChanged) {
4588
- indexByKey.clear();
4589
- idCache.length = 0;
4590
- positions.length = 0;
4591
- columns.length = 0;
4592
- columnSpans.length = 0;
4965
+ resetLayoutCachesForDataChange(state);
4593
4966
  }
4594
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_d = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _d : 0;
4967
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4595
4968
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4596
4969
  updateItemPositions(ctx, dataChanged, {
4597
4970
  doMVCP,
@@ -4616,21 +4989,25 @@ function calculateItemsInView(ctx, params = {}) {
4616
4989
  }
4617
4990
  }
4618
4991
  const scrollBeforeMVCP = state.scroll;
4619
- const scrollAdjustPendingBeforeMVCP = (_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0;
4992
+ const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
4620
4993
  checkMVCP == null ? void 0 : checkMVCP();
4621
- const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0) !== scrollAdjustPendingBeforeMVCP);
4994
+ const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0) !== scrollAdjustPendingBeforeMVCP);
4995
+ if (didMVCPAdjustScroll && initialScroll) {
4996
+ updateScroll2(state.scroll);
4997
+ updateScrollRange();
4998
+ }
4622
4999
  let startNoBuffer = null;
4623
5000
  let startBuffered = null;
4624
5001
  let startBufferedId = null;
4625
5002
  let endNoBuffer = null;
4626
5003
  let endBuffered = null;
4627
- let loopStart = (_g = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _g : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
5004
+ let loopStart = (_f = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _f : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4628
5005
  for (let i = loopStart; i >= 0; i--) {
4629
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
5006
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
4630
5007
  const top = positions[i];
4631
- const size = (_i = sizes.get(id)) != null ? _i : getItemSize(ctx, id, i, data[i]);
5008
+ const size = (_h = sizes.get(id)) != null ? _h : getItemSize(ctx, id, i, data[i]);
4632
5009
  const bottom = top + size;
4633
- if (bottom > scroll - scrollBufferTop) {
5010
+ if (bottom > scrollTopBuffered) {
4634
5011
  loopStart = i;
4635
5012
  } else {
4636
5013
  break;
@@ -4659,8 +5036,8 @@ function calculateItemsInView(ctx, params = {}) {
4659
5036
  let firstFullyOnScreenIndex;
4660
5037
  const dataLength = data.length;
4661
5038
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
4662
- const id = (_j = idCache[i]) != null ? _j : getId(state, i);
4663
- const size = (_k = sizes.get(id)) != null ? _k : getItemSize(ctx, id, i, data[i]);
5039
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
5040
+ const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
4664
5041
  const top = positions[i];
4665
5042
  if (!foundEnd) {
4666
5043
  if (startNoBuffer === null && top + size > scroll) {
@@ -4699,7 +5076,7 @@ function calculateItemsInView(ctx, params = {}) {
4699
5076
  const firstVisibleAnchorIndex = firstFullyOnScreenIndex != null ? firstFullyOnScreenIndex : startNoBuffer;
4700
5077
  if (firstVisibleAnchorIndex !== null && firstVisibleAnchorIndex !== void 0 && endNoBuffer !== null) {
4701
5078
  for (let i = firstVisibleAnchorIndex; i <= endNoBuffer; i++) {
4702
- const id = (_l = idCache[i]) != null ? _l : getId(state, i);
5079
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
4703
5080
  idsInView.push(id);
4704
5081
  }
4705
5082
  }
@@ -4732,7 +5109,7 @@ function calculateItemsInView(ctx, params = {}) {
4732
5109
  const needNewContainers = [];
4733
5110
  const needNewContainersSet = /* @__PURE__ */ new Set();
4734
5111
  for (let i = startBuffered; i <= endBuffered; i++) {
4735
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
5112
+ const id = (_l = idCache[i]) != null ? _l : getId(state, i);
4736
5113
  if (!containerItemKeys.has(id)) {
4737
5114
  needNewContainersSet.add(i);
4738
5115
  needNewContainers.push(i);
@@ -4741,7 +5118,7 @@ function calculateItemsInView(ctx, params = {}) {
4741
5118
  if (alwaysRenderArr.length > 0) {
4742
5119
  for (const index of alwaysRenderArr) {
4743
5120
  if (index < 0 || index >= dataLength) continue;
4744
- const id = (_n = idCache[index]) != null ? _n : getId(state, index);
5121
+ const id = (_m = idCache[index]) != null ? _m : getId(state, index);
4745
5122
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
4746
5123
  needNewContainersSet.add(index);
4747
5124
  needNewContainers.push(index);
@@ -4780,7 +5157,7 @@ function calculateItemsInView(ctx, params = {}) {
4780
5157
  for (let idx = 0; idx < needNewContainers.length; idx++) {
4781
5158
  const i = needNewContainers[idx];
4782
5159
  const containerIndex = availableContainers[idx];
4783
- const id = (_o = idCache[i]) != null ? _o : getId(state, i);
5160
+ const id = (_n = idCache[i]) != null ? _n : getId(state, i);
4784
5161
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
4785
5162
  if (oldKey && oldKey !== id) {
4786
5163
  containerItemKeys.delete(oldKey);
@@ -4791,7 +5168,7 @@ function calculateItemsInView(ctx, params = {}) {
4791
5168
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
4792
5169
  }
4793
5170
  containerItemKeys.set(id, containerIndex);
4794
- (_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.add(id);
5171
+ (_o = state.userScrollAnchorResetKeys) == null ? void 0 : _o.add(id);
4795
5172
  const containerSticky = `containerSticky${containerIndex}`;
4796
5173
  const isSticky = stickyIndicesSet.has(i);
4797
5174
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -4815,17 +5192,17 @@ function calculateItemsInView(ctx, params = {}) {
4815
5192
  if (numContainers !== prevNumContainers) {
4816
5193
  set$(ctx, "numContainers", numContainers);
4817
5194
  if (numContainers > peek$(ctx, "numContainersPooled")) {
4818
- set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
5195
+ set$(ctx, "numContainersPooled", getExpandedContainerPoolSize(dataLength, numContainers));
4819
5196
  }
4820
5197
  }
4821
5198
  }
4822
- if (((_q = state.userScrollAnchorResetKeys) == null ? void 0 : _q.size) === 0) {
5199
+ if (((_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.size) === 0) {
4823
5200
  state.userScrollAnchorResetKeys = void 0;
4824
5201
  }
4825
5202
  if (alwaysRenderArr.length > 0) {
4826
5203
  for (const index of alwaysRenderArr) {
4827
5204
  if (index < 0 || index >= dataLength) continue;
4828
- const id = (_r = idCache[index]) != null ? _r : getId(state, index);
5205
+ const id = (_q = idCache[index]) != null ? _q : getId(state, index);
4829
5206
  const containerIndex = containerItemKeys.get(id);
4830
5207
  if (containerIndex !== void 0) {
4831
5208
  state.stickyContainerPool.add(containerIndex);
@@ -4899,12 +5276,7 @@ function calculateItemsInView(ctx, params = {}) {
4899
5276
  );
4900
5277
  }
4901
5278
  }
4902
- if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
4903
- const item = data[nextActiveStickyIndex];
4904
- if (item !== void 0) {
4905
- onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4906
- }
4907
- }
5279
+ finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4908
5280
  });
4909
5281
  }
4910
5282
 
@@ -4929,21 +5301,36 @@ function doMaintainScrollAtEnd(ctx) {
4929
5301
  if (contentSize < state.scrollLength) {
4930
5302
  state.scroll = 0;
4931
5303
  }
4932
- requestAnimationFrame(() => {
4933
- var _a3;
4934
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
4935
- state.maintainingScrollAtEnd = true;
4936
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
4937
- animated: maintainScrollAtEnd.animated
4938
- });
4939
- setTimeout(
4940
- () => {
4941
- state.maintainingScrollAtEnd = false;
4942
- },
4943
- maintainScrollAtEnd.animated ? 500 : 0
4944
- );
4945
- }
4946
- });
5304
+ if (!state.maintainingScrollAtEnd) {
5305
+ state.maintainingScrollAtEnd = true;
5306
+ requestAnimationFrame(() => {
5307
+ if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
5308
+ const scroller = refScroller.current;
5309
+ if (state.props.horizontal && isHorizontalRTL(state)) {
5310
+ const currentContentSize = getContentSize(ctx);
5311
+ const logicalEndOffset = getLogicalHorizontalMaxOffset(state, currentContentSize);
5312
+ const nativeOffset = toNativeHorizontalOffset(state, logicalEndOffset, currentContentSize);
5313
+ scroller == null ? void 0 : scroller.scrollTo({
5314
+ animated: maintainScrollAtEnd.animated,
5315
+ x: nativeOffset,
5316
+ y: 0
5317
+ });
5318
+ } else {
5319
+ scroller == null ? void 0 : scroller.scrollToEnd({
5320
+ animated: maintainScrollAtEnd.animated
5321
+ });
5322
+ }
5323
+ setTimeout(
5324
+ () => {
5325
+ state.maintainingScrollAtEnd = false;
5326
+ },
5327
+ maintainScrollAtEnd.animated ? 500 : 0
5328
+ );
5329
+ } else {
5330
+ state.maintainingScrollAtEnd = false;
5331
+ }
5332
+ });
5333
+ }
4947
5334
  return true;
4948
5335
  }
4949
5336
  return false;
@@ -5055,14 +5442,21 @@ function doInitialAllocateContainers(ctx) {
5055
5442
  } else {
5056
5443
  averageItemSize = estimatedItemSize;
5057
5444
  }
5058
- const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
5445
+ const numContainers = Math.max(
5446
+ 1,
5447
+ Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns)
5448
+ );
5059
5449
  for (let i = 0; i < numContainers; i++) {
5060
5450
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
5061
5451
  set$(ctx, `containerColumn${i}`, -1);
5062
5452
  set$(ctx, `containerSpan${i}`, 1);
5063
5453
  }
5064
5454
  set$(ctx, "numContainers", numContainers);
5065
- set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
5455
+ set$(
5456
+ ctx,
5457
+ "numContainersPooled",
5458
+ getInitialContainerPoolSize(data.length, numContainers, state.props.initialContainerPoolRatio)
5459
+ );
5066
5460
  if (state.lastLayout) {
5067
5461
  if (state.initialScroll) {
5068
5462
  requestAnimationFrame(() => {
@@ -5125,7 +5519,8 @@ function handleLayout(ctx, layoutParam, setCanRender) {
5125
5519
  }
5126
5520
  checkThresholds(ctx);
5127
5521
  if (state) {
5128
- state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
5522
+ const crossAxisPadding = state.props.horizontal ? (state.props.stylePaddingTop || 0) + (state.props.stylePaddingBottom || 0) : (state.props.stylePaddingLeft || 0) + (state.props.stylePaddingRight || 0);
5523
+ state.needsOtherAxisSize = otherAxisSize - crossAxisPadding < 10;
5129
5524
  }
5130
5525
  if (IS_DEV && measuredLength === 0) {
5131
5526
  warnDevOnce(
@@ -5213,8 +5608,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
5213
5608
  // src/core/onScroll.ts
5214
5609
  function trackInitialScrollNativeProgress(state, newScroll) {
5215
5610
  const initialNativeScrollWatchdog = initialScrollWatchdog.get(state);
5216
- const didInitialScrollProgress = !!initialNativeScrollWatchdog && initialScrollWatchdog.didObserveProgress(newScroll, initialNativeScrollWatchdog);
5217
- if (didInitialScrollProgress) {
5611
+ const didInitialScrollReachTarget = !!initialNativeScrollWatchdog && initialScrollWatchdog.didReachTarget(newScroll, initialNativeScrollWatchdog);
5612
+ if (didInitialScrollReachTarget) {
5218
5613
  initialScrollWatchdog.clear(state);
5219
5614
  return;
5220
5615
  }
@@ -5239,7 +5634,7 @@ function cloneScrollEvent(event) {
5239
5634
  };
5240
5635
  }
5241
5636
  function onScroll(ctx, event) {
5242
- var _a3, _b, _c, _d;
5637
+ var _a3, _b, _c, _d, _e;
5243
5638
  const state = ctx.state;
5244
5639
  const { scrollProcessingEnabled } = state;
5245
5640
  if (scrollProcessingEnabled === false) {
@@ -5258,6 +5653,9 @@ function onScroll(ctx, event) {
5258
5653
  }
5259
5654
  }
5260
5655
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
5656
+ if (state.props.horizontal) {
5657
+ newScroll = toLogicalHorizontalOffset(state, newScroll, (_e = event.nativeEvent.contentSize) == null ? void 0 : _e.width);
5658
+ }
5261
5659
  if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
5262
5660
  const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
5263
5661
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
@@ -5352,16 +5750,20 @@ function maybeUpdateAnchoredEndSpace(ctx) {
5352
5750
  let contentBelowAnchor = 0;
5353
5751
  const footerSize = ctx.values.get("footerSize") || 0;
5354
5752
  const stylePaddingBottom = state.props.stylePaddingBottom || 0;
5753
+ let hasUnknownTailSize = false;
5355
5754
  for (let index = anchorIndex; index < data.length; index++) {
5356
5755
  const itemKey = getId(state, index);
5357
5756
  const size = itemKey ? state.sizesKnown.get(itemKey) : void 0;
5358
5757
  const effectiveSize = index === anchorIndex && anchorMaxSize !== void 0 ? Math.min(size || 0, Math.max(0, anchorMaxSize)) : size;
5758
+ if (size === void 0) {
5759
+ hasUnknownTailSize = true;
5760
+ }
5359
5761
  if (effectiveSize !== null && effectiveSize !== void 0 && effectiveSize > 0) {
5360
5762
  contentBelowAnchor += effectiveSize;
5361
5763
  }
5362
5764
  }
5363
5765
  contentBelowAnchor += footerSize + stylePaddingBottom;
5364
- nextSize = Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5766
+ nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5365
5767
  }
5366
5768
  }
5367
5769
  if (previousSize !== nextSize) {
@@ -5425,6 +5827,16 @@ function runOrScheduleMVCPRecalculate(ctx) {
5425
5827
  });
5426
5828
  }
5427
5829
  }
5830
+ function updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal) {
5831
+ const state = ctx.state;
5832
+ if (state.needsOtherAxisSize) {
5833
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
5834
+ const currentOtherAxisSize = peek$(ctx, "otherAxisSize");
5835
+ if (!currentOtherAxisSize || otherAxisSize > currentOtherAxisSize) {
5836
+ set$(ctx, "otherAxisSize", otherAxisSize);
5837
+ }
5838
+ }
5839
+ }
5428
5840
  function updateItemSize(ctx, itemKey, sizeObj) {
5429
5841
  var _a3;
5430
5842
  const state = ctx.state;
@@ -5433,15 +5845,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5433
5845
  const {
5434
5846
  didContainersLayout,
5435
5847
  sizesKnown,
5436
- props: {
5437
- getFixedItemSize,
5438
- getItemType,
5439
- horizontal,
5440
- suggestEstimatedItemSize,
5441
- onItemSizeChanged,
5442
- data,
5443
- maintainScrollAtEnd
5444
- }
5848
+ props: { getFixedItemSize, getItemType, horizontal, onItemSizeChanged, data, maintainScrollAtEnd }
5445
5849
  } = state;
5446
5850
  if (!data) return;
5447
5851
  const index = state.indexByKey.get(itemKey);
@@ -5456,13 +5860,13 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5456
5860
  const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
5457
5861
  const size2 = getFixedItemSize(itemData, index, type);
5458
5862
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
5863
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5459
5864
  return;
5460
5865
  }
5461
5866
  }
5462
5867
  let needsRecalculate = !didContainersLayout;
5463
5868
  let shouldMaintainScrollAtEnd = false;
5464
5869
  let minIndexSizeChanged;
5465
- let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
5466
5870
  const prevSizeKnown = state.sizesKnown.get(itemKey);
5467
5871
  const diff = updateOneItemSize(ctx, itemKey, sizeObj);
5468
5872
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
@@ -5473,10 +5877,6 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5473
5877
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
5474
5878
  needsRecalculate = true;
5475
5879
  }
5476
- if (state.needsOtherAxisSize) {
5477
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
5478
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
5479
- }
5480
5880
  if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
5481
5881
  shouldMaintainScrollAtEnd = true;
5482
5882
  }
@@ -5492,22 +5892,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5492
5892
  if (minIndexSizeChanged !== void 0) {
5493
5893
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
5494
5894
  }
5495
- if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
5496
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
5497
- state.timeoutSizeMessage = setTimeout(() => {
5498
- var _a4;
5499
- state.timeoutSizeMessage = void 0;
5500
- const num = state.sizesKnown.size;
5501
- const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
5502
- console.warn(
5503
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
5504
- );
5505
- }, 1e3);
5506
- }
5507
- const cur = peek$(ctx, "otherAxisSize");
5508
- if (!cur || maxOtherAxisSize > cur) {
5509
- set$(ctx, "otherAxisSize", maxOtherAxisSize);
5510
- }
5895
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5511
5896
  if (didContainersLayout || checkAllSizesKnown(state, getMountedBufferedIndices(state))) {
5512
5897
  if (needsRecalculate) {
5513
5898
  state.scrollForNextCalculateItemsInView = void 0;
@@ -5608,12 +5993,47 @@ function createColumnWrapperStyle(contentContainerStyle) {
5608
5993
  }
5609
5994
 
5610
5995
  // src/utils/createImperativeHandle.ts
5996
+ var DEFAULT_AVERAGE_ITEM_SIZE_TYPE = "default";
5997
+ function getAverageItemSizes(state) {
5998
+ const averageItemSizes = {};
5999
+ for (const itemType in state.averageSizes) {
6000
+ const averageSize = state.averageSizes[itemType];
6001
+ if (averageSize) {
6002
+ averageItemSizes[itemType || DEFAULT_AVERAGE_ITEM_SIZE_TYPE] = {
6003
+ average: averageSize.avg,
6004
+ count: averageSize.num
6005
+ };
6006
+ }
6007
+ }
6008
+ return averageItemSizes;
6009
+ }
5611
6010
  function createImperativeHandle(ctx) {
5612
6011
  const state = ctx.state;
5613
6012
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
5614
6013
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
5615
6014
  let imperativeScrollToken = 0;
5616
6015
  const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
6016
+ const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
6017
+ var _a3;
6018
+ const props = state.props;
6019
+ const dataLength = props.data.length;
6020
+ const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
6021
+ if (targetIndex < 0) {
6022
+ return allowEmpty;
6023
+ }
6024
+ if (targetIndex >= dataLength) {
6025
+ return false;
6026
+ }
6027
+ if (anchorIndex === void 0 || anchorIndex < 0 || anchorIndex >= dataLength || targetIndex < anchorIndex || props.getFixedItemSize) {
6028
+ return true;
6029
+ }
6030
+ for (let index = anchorIndex; index < dataLength; index++) {
6031
+ if (!state.sizesKnown.has(getId(state, index))) {
6032
+ return false;
6033
+ }
6034
+ }
6035
+ return true;
6036
+ };
5617
6037
  const runWhenReady = (token, run, isReady) => {
5618
6038
  const startedAt = Date.now();
5619
6039
  let stableFrames = 0;
@@ -5635,11 +6055,10 @@ function createImperativeHandle(ctx) {
5635
6055
  };
5636
6056
  requestAnimationFrame(check);
5637
6057
  };
5638
- const runScrollWithPromise = (run, options) => new Promise((resolve) => {
5639
- var _a3, _b;
6058
+ const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
6059
+ var _a3;
5640
6060
  const token = ++imperativeScrollToken;
5641
- const isReady = (_a3 = options == null ? void 0 : options.isReady) != null ? _a3 : (() => true);
5642
- (_b = state.pendingScrollResolve) == null ? void 0 : _b.call(state);
6061
+ (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
5643
6062
  state.pendingScrollResolve = resolve;
5644
6063
  const runNow = () => {
5645
6064
  if (token !== imperativeScrollToken) {
@@ -5714,6 +6133,7 @@ function createImperativeHandle(ctx) {
5714
6133
  },
5715
6134
  end: state.endNoBuffer,
5716
6135
  endBuffered: state.endBuffered,
6136
+ getAverageItemSizes: () => getAverageItemSizes(state),
5717
6137
  isAtEnd: peek$(ctx, "isAtEnd"),
5718
6138
  isAtStart: peek$(ctx, "isAtStart"),
5719
6139
  isEndReached: state.isEndReached,
@@ -5756,40 +6176,34 @@ function createImperativeHandle(ctx) {
5756
6176
  }
5757
6177
  return false;
5758
6178
  }),
5759
- scrollToEnd: (options) => runScrollWithPromise(() => {
5760
- const data = state.props.data;
5761
- const stylePaddingBottom = state.props.stylePaddingBottom;
5762
- const index = data.length - 1;
5763
- if (index !== -1) {
5764
- const paddingBottom = stylePaddingBottom || 0;
5765
- const footerSize = peek$(ctx, "footerSize") || 0;
5766
- scrollToIndex(ctx, {
5767
- ...options,
5768
- index,
5769
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5770
- viewPosition: 1
5771
- });
5772
- return true;
5773
- }
5774
- return false;
5775
- }),
5776
- scrollToIndex: (params) => {
5777
- const shouldWaitForOutOfRangeTarget = params.index >= 0 && params.index >= state.props.data.length;
5778
- const options = shouldWaitForOutOfRangeTarget ? {
5779
- isReady: () => {
5780
- var _a3;
5781
- const props = state.props;
5782
- const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5783
- const lastIndex = props.data.length - 1;
5784
- const isInRange = params.index < props.data.length;
5785
- const shouldWaitForAnchorSize = isInRange && anchorIndex !== void 0 && anchorIndex >= 0 && params.index >= anchorIndex && !props.getFixedItemSize && !state.sizesKnown.has(getId(state, lastIndex));
5786
- return isInRange && !shouldWaitForAnchorSize;
6179
+ scrollToEnd: (options) => runScrollWithPromise(
6180
+ () => {
6181
+ const data = state.props.data;
6182
+ const stylePaddingBottom = state.props.stylePaddingBottom;
6183
+ const index = data.length - 1;
6184
+ if (index !== -1) {
6185
+ const paddingBottom = stylePaddingBottom || 0;
6186
+ const footerSize = peek$(ctx, "footerSize") || 0;
6187
+ scrollToIndex(ctx, {
6188
+ ...options,
6189
+ index,
6190
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
6191
+ viewPosition: 1
6192
+ });
6193
+ return true;
5787
6194
  }
5788
- } : void 0;
5789
- return runScrollWithPromise(() => {
5790
- scrollToIndex(ctx, params);
5791
- return true;
5792
- }, options);
6195
+ return false;
6196
+ },
6197
+ () => isScrollToIndexReady(state.props.data.length - 1, true)
6198
+ ),
6199
+ scrollToIndex: (params) => {
6200
+ return runScrollWithPromise(
6201
+ () => {
6202
+ scrollToIndex(ctx, params);
6203
+ return true;
6204
+ },
6205
+ params.index >= 0 ? () => isScrollToIndexReady(params.index) : void 0
6206
+ );
5793
6207
  },
5794
6208
  scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
5795
6209
  const data = state.props.data;
@@ -6053,7 +6467,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6053
6467
  getFixedItemSize,
6054
6468
  getItemType,
6055
6469
  horizontal,
6056
- initialContainerPoolRatio = 2,
6470
+ rtl,
6471
+ initialContainerPoolRatio = 3,
6472
+ estimatedHeaderSize,
6057
6473
  initialScrollAtEnd = false,
6058
6474
  initialScrollIndex: initialScrollIndexProp,
6059
6475
  initialScrollOffset: initialScrollOffsetProp,
@@ -6094,7 +6510,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6094
6510
  stickyIndices: stickyIndicesDeprecated,
6095
6511
  // TODOV3: Remove from v3 release
6096
6512
  style: styleProp,
6097
- suggestEstimatedItemSize,
6098
6513
  useWindowScroll = false,
6099
6514
  viewabilityConfig,
6100
6515
  viewabilityConfigCallbackPairs,
@@ -6122,13 +6537,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6122
6537
  const style = { ...StyleSheet.flatten(styleProp) };
6123
6538
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
6124
6539
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
6540
+ const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
6541
+ const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
6125
6542
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
6126
6543
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
6127
6544
  maintainVisibleContentPositionProp
6128
6545
  );
6129
6546
  const hasInitialScrollIndex = initialScrollIndexProp !== void 0 && initialScrollIndexProp !== null;
6130
6547
  const hasInitialScrollOffset = initialScrollOffsetProp !== void 0 && initialScrollOffsetProp !== null;
6131
- const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && hasInitialScrollOffset;
6548
+ const shouldInitializeHorizontalRTL = !initialScrollAtEnd && !hasInitialScrollIndex && !hasInitialScrollOffset && isHorizontalRTLProps({ horizontal, rtl });
6549
+ const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && (hasInitialScrollOffset || shouldInitializeHorizontalRTL);
6132
6550
  const usesBootstrapInitialScroll = initialScrollAtEnd || hasInitialScrollIndex;
6133
6551
  const initialScrollProp = initialScrollAtEnd ? {
6134
6552
  index: Math.max(0, dataProp.length - 1),
@@ -6235,7 +6653,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6235
6653
  startReachedSnapshotDataChangeEpoch: void 0,
6236
6654
  stickyContainerPool: /* @__PURE__ */ new Set(),
6237
6655
  stickyContainers: /* @__PURE__ */ new Map(),
6238
- timeoutSizeMessage: 0,
6239
6656
  timeouts: /* @__PURE__ */ new Set(),
6240
6657
  totalSize: 0,
6241
6658
  viewabilityConfigCallbackPairs: void 0
@@ -6245,6 +6662,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6245
6662
  internalState.reprocessCurrentScroll = () => updateScroll(ctx, internalState.scroll, true);
6246
6663
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
6247
6664
  set$(ctx, "extraData", extraData);
6665
+ if (estimatedHeaderSize !== void 0) {
6666
+ set$(ctx, "headerSize", estimatedHeaderSize);
6667
+ }
6248
6668
  }
6249
6669
  refState.current = ctx.state;
6250
6670
  }
@@ -6255,7 +6675,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6255
6675
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
6256
6676
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
6257
6677
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
6258
- if (didDataChangeLocal && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6678
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6259
6679
  clearPreservedInitialScrollTarget(state);
6260
6680
  }
6261
6681
  if (didDataChangeLocal) {
@@ -6304,13 +6724,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6304
6724
  positionComponentInternal,
6305
6725
  recycleItems: !!recycleItems,
6306
6726
  renderItem,
6727
+ rtl,
6307
6728
  snapToIndices,
6308
6729
  stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
6309
6730
  stickyIndicesSet: useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
6310
6731
  stickyPositionComponentInternal,
6311
6732
  stylePaddingBottom: stylePaddingBottomState,
6733
+ stylePaddingLeft: stylePaddingLeftState,
6734
+ stylePaddingRight: stylePaddingRightState,
6312
6735
  stylePaddingTop: stylePaddingTopState,
6313
- suggestEstimatedItemSize: !!suggestEstimatedItemSize,
6314
6736
  useWindowScroll: useWindowScrollResolved
6315
6737
  };
6316
6738
  state.refScroller = refScroller;
@@ -6332,6 +6754,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6332
6754
  };
6333
6755
  if (isFirstLocal) {
6334
6756
  initializeStateVars(false);
6757
+ resetLayoutCachesForDataChange(state);
6335
6758
  updateItemPositions(
6336
6759
  ctx,
6337
6760
  /*dataChanged*/
@@ -6349,6 +6772,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6349
6772
  }, [usesBootstrapInitialScroll]);
6350
6773
  useLayoutEffect(() => {
6351
6774
  initializeInitialScrollOnMount(ctx, {
6775
+ alwaysDispatchInitialScroll: shouldInitializeHorizontalRTL,
6352
6776
  dataLength: dataProp.length,
6353
6777
  hasFooterComponent: !!ListFooterComponent,
6354
6778
  initialContentOffset,