@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/react.js CHANGED
@@ -34,6 +34,115 @@ var View = React3.forwardRef(function View2(props, ref) {
34
34
  });
35
35
  var Text = View;
36
36
 
37
+ // src/platform/Platform.ts
38
+ var Platform = {
39
+ // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
40
+ OS: "web"
41
+ };
42
+
43
+ // src/utils/rtl.ts
44
+ function clampHorizontalOffset(offset, maxOffset) {
45
+ if (maxOffset === void 0) {
46
+ return offset;
47
+ }
48
+ return Math.max(0, Math.min(maxOffset, offset));
49
+ }
50
+ function getHorizontalMaxOffset(state, contentWidth) {
51
+ if (contentWidth === void 0 || !Number.isFinite(contentWidth) || !Number.isFinite(state.scrollLength) || contentWidth <= state.scrollLength) {
52
+ return contentWidth !== void 0 && Number.isFinite(contentWidth) && Number.isFinite(state.scrollLength) ? 0 : void 0;
53
+ }
54
+ return Math.max(0, contentWidth - state.scrollLength);
55
+ }
56
+ function getDefaultHorizontalRTLScrollType() {
57
+ return "normal" ;
58
+ }
59
+ function getNativeHorizontalRTLScrollType(state) {
60
+ var _a3;
61
+ return (_a3 = state == null ? void 0 : state.horizontalRTLScrollType) != null ? _a3 : getDefaultHorizontalRTLScrollType();
62
+ }
63
+ function isRTLProps(props) {
64
+ var _a3;
65
+ return (_a3 = props == null ? void 0 : props.rtl) != null ? _a3 : false;
66
+ }
67
+ function isHorizontalRTL(state) {
68
+ return isHorizontalRTLProps(state == null ? void 0 : state.props);
69
+ }
70
+ function isHorizontalRTLProps(props) {
71
+ return !!(props == null ? void 0 : props.horizontal) && isRTLProps(props);
72
+ }
73
+ function getLogicalHorizontalMaxOffset(state, contentWidth) {
74
+ var _a3;
75
+ return (_a3 = getHorizontalMaxOffset(state, contentWidth)) != null ? _a3 : 0;
76
+ }
77
+ function getHorizontalInsetEnd(state, inset) {
78
+ if (!inset) {
79
+ return 0;
80
+ }
81
+ return (isHorizontalRTL(state) ? inset.left : inset.right) || 0;
82
+ }
83
+ function toPhysicalHorizontalItemPosition(state, logicalPosition, itemSize, listSize) {
84
+ if (!isHorizontalRTL(state) || listSize === void 0 || !Number.isFinite(listSize)) {
85
+ return logicalPosition;
86
+ }
87
+ return Math.max(0, listSize - logicalPosition - itemSize);
88
+ }
89
+ function toNativeHorizontalOffset(state, logicalOffset, contentWidth) {
90
+ if (!state || !isHorizontalRTL(state)) {
91
+ return logicalOffset;
92
+ }
93
+ const maxOffset = getHorizontalMaxOffset(state, contentWidth);
94
+ const clampedLogicalOffset = clampHorizontalOffset(logicalOffset, maxOffset);
95
+ const mode = getNativeHorizontalRTLScrollType(state);
96
+ if (mode === "negative") {
97
+ return clampedLogicalOffset === 0 ? 0 : -clampedLogicalOffset;
98
+ }
99
+ if (mode === "inverted") {
100
+ if (maxOffset === void 0) {
101
+ return clampedLogicalOffset;
102
+ }
103
+ return clampHorizontalOffset(maxOffset - clampedLogicalOffset, maxOffset);
104
+ }
105
+ return clampedLogicalOffset;
106
+ }
107
+ function toLogicalHorizontalOffset(state, rawOffset, contentWidth) {
108
+ if (!isHorizontalRTL(state)) {
109
+ state.horizontalRTLScrollType = void 0;
110
+ return rawOffset;
111
+ }
112
+ const maxOffset = getHorizontalMaxOffset(state, contentWidth);
113
+ if (rawOffset < 0) {
114
+ state.horizontalRTLScrollType = "negative";
115
+ return clampHorizontalOffset(-rawOffset, maxOffset);
116
+ }
117
+ if (maxOffset === void 0) {
118
+ return rawOffset;
119
+ }
120
+ const normalOffset = rawOffset;
121
+ const invertedOffset = maxOffset - rawOffset;
122
+ if (!Number.isFinite(invertedOffset)) {
123
+ state.horizontalRTLScrollType = "normal";
124
+ return normalOffset;
125
+ }
126
+ const previousMode = state.horizontalRTLScrollType;
127
+ if (previousMode === "inverted") {
128
+ return clampHorizontalOffset(invertedOffset, maxOffset);
129
+ }
130
+ if (previousMode === "normal") {
131
+ return clampHorizontalOffset(normalOffset, maxOffset);
132
+ }
133
+ if (!state.hasScrolled) {
134
+ const defaultMode = getDefaultHorizontalRTLScrollType();
135
+ state.horizontalRTLScrollType = defaultMode;
136
+ return clampHorizontalOffset(normalOffset, maxOffset);
137
+ }
138
+ const referenceScroll = state.scroll;
139
+ const distanceNormal = Math.abs(normalOffset - referenceScroll);
140
+ const distanceInverted = Math.abs(invertedOffset - referenceScroll);
141
+ const useInverted = distanceInverted + 0.5 < distanceNormal;
142
+ state.horizontalRTLScrollType = useInverted ? "inverted" : "normal";
143
+ return clampHorizontalOffset(useInverted ? invertedOffset : normalOffset, maxOffset);
144
+ }
145
+
37
146
  // src/platform/Animated.tsx
38
147
  var createAnimatedValue = (value) => value;
39
148
 
@@ -176,7 +285,7 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
176
285
  const horizontal = props.horizontal;
177
286
  const contentInset = props.contentInset;
178
287
  const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
179
- const baseEndInset = (horizontal ? baseInset == null ? void 0 : baseInset.right : baseInset == null ? void 0 : baseInset.bottom) || 0;
288
+ const baseEndInset = (horizontal ? getHorizontalInsetEnd(state, baseInset) : baseInset == null ? void 0 : baseInset.bottom) || 0;
180
289
  const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd(
181
290
  contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
182
291
  );
@@ -185,9 +294,9 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
185
294
  const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
186
295
  const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
187
296
  if (overrideInset) {
188
- const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
297
+ const mergedInset = { bottom: 0, left: 0, right: 0, ...baseInset, ...overrideInset };
189
298
  return Math.max(
190
- ((horizontal ? mergedInset.right : mergedInset.bottom) || 0) + contentInsetEndAdjustment,
299
+ ((horizontal ? getHorizontalInsetEnd(state, mergedInset) : mergedInset.bottom) || 0) + contentInsetEndAdjustment,
191
300
  anchoredEndInset
192
301
  );
193
302
  }
@@ -281,6 +390,15 @@ var ENABLE_DEVMODE = IS_DEV && false;
281
390
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
282
391
  var typedForwardRef = React3__namespace.forwardRef;
283
392
  var typedMemo = React3__namespace.memo;
393
+ var getComponent = (Component) => {
394
+ if (React3__namespace.isValidElement(Component)) {
395
+ return Component;
396
+ }
397
+ if (Component) {
398
+ return /* @__PURE__ */ React3__namespace.createElement(Component, null);
399
+ }
400
+ return null;
401
+ };
284
402
 
285
403
  // src/utils/helpers.ts
286
404
  function isFunction(obj) {
@@ -307,7 +425,8 @@ function comparatorDefault(a, b) {
307
425
  }
308
426
  function getPadding(s, type) {
309
427
  var _a3, _b, _c;
310
- return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
428
+ const axisPadding = type === "Left" || type === "Right" ? s.paddingHorizontal : s.paddingVertical;
429
+ return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : axisPadding) != null ? _b : s.padding) != null ? _c : 0;
311
430
  }
312
431
  function extractPadding(style, contentContainerStyle, type) {
313
432
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
@@ -329,6 +448,14 @@ function findContainerId(ctx, key) {
329
448
  }
330
449
 
331
450
  // src/components/PositionView.tsx
451
+ var isRNWeb = typeof document !== "undefined" && !!document.getElementById("react-native-stylesheet");
452
+ var baseCss = {
453
+ contain: "paint layout style",
454
+ ...isRNWeb ? {
455
+ display: "flex",
456
+ flexDirection: "column"
457
+ } : {}
458
+ };
332
459
  var PositionViewState = typedMemo(function PositionViewState2({
333
460
  id,
334
461
  horizontal,
@@ -337,11 +464,8 @@ var PositionViewState = typedMemo(function PositionViewState2({
337
464
  ...props
338
465
  }) {
339
466
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
340
- const base = {
341
- contain: "paint layout style"
342
- };
343
467
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
344
- const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
468
+ const combinedStyle = horizontal ? { ...baseCss, ...composed, left: position } : { ...baseCss, ...composed, top: position };
345
469
  const {
346
470
  animatedScrollY: _animatedScrollY,
347
471
  index,
@@ -369,9 +493,6 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
369
493
  `containerPosition${id}`,
370
494
  "activeStickyIndex"
371
495
  ]);
372
- const base = {
373
- contain: "paint layout style"
374
- };
375
496
  const composed = React3__namespace.useMemo(
376
497
  () => {
377
498
  var _a3;
@@ -381,10 +502,9 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
381
502
  );
382
503
  const viewStyle = React3__namespace.useMemo(() => {
383
504
  var _a3;
384
- const styleBase = { ...base, ...composed };
505
+ const styleBase = { ...baseCss, ...composed };
385
506
  delete styleBase.transform;
386
- const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
387
- const offset = stickyConfigOffset != null ? stickyConfigOffset : 0;
507
+ const offset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
388
508
  const isActive = activeStickyIndex === index;
389
509
  styleBase.position = isActive ? "sticky" : "absolute";
390
510
  styleBase.zIndex = index + 1e3;
@@ -395,6 +515,20 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
395
515
  }
396
516
  return styleBase;
397
517
  }, [composed, horizontal, position, index, activeStickyIndex, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
518
+ const renderStickyHeaderBackdrop = React3__namespace.useMemo(
519
+ () => (stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent) ? /* @__PURE__ */ React3__namespace.createElement(
520
+ "div",
521
+ {
522
+ style: {
523
+ inset: 0,
524
+ pointerEvents: "none",
525
+ position: "absolute"
526
+ }
527
+ },
528
+ getComponent(stickyHeaderConfig.backdropComponent)
529
+ ) : null,
530
+ [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]
531
+ );
398
532
  return /* @__PURE__ */ React3__namespace.createElement(
399
533
  "div",
400
534
  {
@@ -403,6 +537,7 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
403
537
  style: viewStyle,
404
538
  ...webProps
405
539
  },
540
+ renderStickyHeaderBackdrop,
406
541
  children
407
542
  );
408
543
  });
@@ -667,12 +802,6 @@ function toLayout(rect) {
667
802
  };
668
803
  }
669
804
 
670
- // src/platform/Platform.ts
671
- var Platform = {
672
- // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
673
- OS: "web"
674
- };
675
-
676
805
  // src/utils/hasActiveMVCPAnchorLock.ts
677
806
  function hasActiveMVCPAnchorLock(state) {
678
807
  const lock = state.mvcpAnchorLock;
@@ -696,6 +825,7 @@ function getContainerPositionStyle({
696
825
  columnWrapperStyle,
697
826
  horizontal,
698
827
  hasItemSeparator,
828
+ isHorizontalRTLList,
699
829
  numColumns,
700
830
  otherAxisPos,
701
831
  otherAxisSize
@@ -719,6 +849,7 @@ function getContainerPositionStyle({
719
849
  }
720
850
  return horizontal ? {
721
851
  boxSizing: paddingStyles ? "border-box" : void 0,
852
+ direction: isHorizontalRTLList && Platform.OS === "web" ? "ltr" : void 0,
722
853
  flexDirection: hasItemSeparator ? "row" : void 0,
723
854
  height: otherAxisSize,
724
855
  left: 0,
@@ -737,6 +868,7 @@ function getContainerPositionStyle({
737
868
  }
738
869
  var Container = typedMemo(function Container2({
739
870
  id,
871
+ itemKey,
740
872
  recycleItems,
741
873
  horizontal,
742
874
  getRenderedItem: getRenderedItem2,
@@ -746,13 +878,13 @@ var Container = typedMemo(function Container2({
746
878
  }) {
747
879
  const ctx = useStateContext();
748
880
  const { columnWrapperStyle, animatedScrollY } = ctx;
881
+ const isHorizontalRTLList = isHorizontalRTL(ctx.state);
749
882
  const positionComponentInternal = ctx.state.props.positionComponentInternal;
750
883
  const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
751
- const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
884
+ const [column = 0, span = 1, data, numColumns = 1, extraData, isSticky] = useArr$([
752
885
  `containerColumn${id}`,
753
886
  `containerSpan${id}`,
754
887
  `containerItemData${id}`,
755
- `containerItemKey${id}`,
756
888
  "numColumns",
757
889
  "extraData",
758
890
  `containerSticky${id}`
@@ -778,11 +910,20 @@ var Container = typedMemo(function Container2({
778
910
  columnWrapperStyle,
779
911
  hasItemSeparator: !!ItemSeparatorComponent,
780
912
  horizontal,
913
+ isHorizontalRTLList,
781
914
  numColumns,
782
915
  otherAxisPos,
783
916
  otherAxisSize
784
917
  }),
785
- [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns, ItemSeparatorComponent]
918
+ [
919
+ horizontal,
920
+ isHorizontalRTLList,
921
+ otherAxisPos,
922
+ otherAxisSize,
923
+ columnWrapperStyle,
924
+ numColumns,
925
+ ItemSeparatorComponent
926
+ ]
786
927
  );
787
928
  const renderedItemInfo = React3.useMemo(
788
929
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
@@ -870,6 +1011,39 @@ var Container = typedMemo(function Container2({
870
1011
  );
871
1012
  });
872
1013
 
1014
+ // src/components/ContainerSlot.tsx
1015
+ function ContainerSlotBase({
1016
+ id,
1017
+ horizontal,
1018
+ recycleItems,
1019
+ ItemSeparatorComponent,
1020
+ updateItemSize: updateItemSize2,
1021
+ getRenderedItem: getRenderedItem2,
1022
+ stickyHeaderConfig,
1023
+ ContainerComponent = Container
1024
+ }) {
1025
+ const [itemKey] = useArr$([`containerItemKey${id}`]);
1026
+ if (itemKey === void 0) {
1027
+ return null;
1028
+ }
1029
+ return /* @__PURE__ */ React3__namespace.createElement(
1030
+ ContainerComponent,
1031
+ {
1032
+ getRenderedItem: getRenderedItem2,
1033
+ horizontal,
1034
+ ItemSeparatorComponent,
1035
+ id,
1036
+ itemKey,
1037
+ recycleItems,
1038
+ stickyHeaderConfig,
1039
+ updateItemSize: updateItemSize2
1040
+ }
1041
+ );
1042
+ }
1043
+ var ContainerSlot = typedMemo(function ContainerSlot2(props) {
1044
+ return /* @__PURE__ */ React3__namespace.createElement(ContainerSlotBase, { ...props });
1045
+ });
1046
+
873
1047
  // src/utils/reordering.ts
874
1048
  var mapFn = (element) => {
875
1049
  const indexStr = element.getAttribute("data-index");
@@ -989,9 +1163,19 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
989
1163
  const ref = React3.useRef(null);
990
1164
  const ctx = useStateContext();
991
1165
  const columnWrapperStyle = ctx.columnWrapperStyle;
992
- const [otherAxisSize, totalSize] = useArr$(["otherAxisSize", "totalSize"]);
1166
+ const isHorizontalRTLList = isHorizontalRTL(ctx.state);
1167
+ const [otherAxisSize, readyToRender, totalSize] = useArr$(["otherAxisSize", "readyToRender", "totalSize"]);
993
1168
  useDOMOrder(ref);
994
- const style = horizontal ? { minHeight: otherAxisSize, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, position: "relative" };
1169
+ const style = horizontal ? {
1170
+ direction: isHorizontalRTLList ? "ltr" : void 0,
1171
+ minHeight: otherAxisSize,
1172
+ opacity: readyToRender ? 1 : 0,
1173
+ position: "relative",
1174
+ width: totalSize
1175
+ } : { height: totalSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative" };
1176
+ if (!readyToRender) {
1177
+ style.pointerEvents = "none";
1178
+ }
995
1179
  if (columnWrapperStyle && numColumns > 1) {
996
1180
  const { columnGap, rowGap, gap } = columnWrapperStyle;
997
1181
  const gapX = columnGap || gap || 0;
@@ -1019,12 +1203,12 @@ var Containers = typedMemo(function Containers2({
1019
1203
  getRenderedItem: getRenderedItem2,
1020
1204
  stickyHeaderConfig
1021
1205
  }) {
1022
- const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
1206
+ const [numContainersPooled, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
1023
1207
  const containers = [];
1024
- for (let i = 0; i < numContainers; i++) {
1208
+ for (let i = 0; i < numContainersPooled; i++) {
1025
1209
  containers.push(
1026
1210
  /* @__PURE__ */ React3__namespace.createElement(
1027
- Container,
1211
+ ContainerSlot,
1028
1212
  {
1029
1213
  getRenderedItem: getRenderedItem2,
1030
1214
  horizontal,
@@ -1096,6 +1280,8 @@ function useRafCoalescer(callback) {
1096
1280
 
1097
1281
  // src/components/webConstants.ts
1098
1282
  var LEGEND_LIST_CONTENT_CONTAINER_CLASS = "legend-list-content-container";
1283
+ var LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS = "legend-list-scrollbar-x-hidden";
1284
+ var LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS = "legend-list-scrollbar-y-hidden";
1099
1285
 
1100
1286
  // src/components/webScrollUtils.ts
1101
1287
  function getDocumentScrollerNode() {
@@ -1181,11 +1367,47 @@ function resolveWindowScrollTarget({ clampedOffset, horizontal, listPos, scroll
1181
1367
  }
1182
1368
 
1183
1369
  // src/components/ListComponentScrollView.tsx
1370
+ var SCROLLBAR_HIDDEN_STYLE_ID = "legend-list-scrollbar-axis-hidden-style";
1371
+ 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;}`;
1372
+ function ensureScrollbarHiddenStyle() {
1373
+ if (typeof document === "undefined" || document.getElementById(SCROLLBAR_HIDDEN_STYLE_ID)) {
1374
+ return;
1375
+ }
1376
+ const styleElement = document.createElement("style");
1377
+ styleElement.id = SCROLLBAR_HIDDEN_STYLE_ID;
1378
+ styleElement.textContent = SCROLLBAR_HIDDEN_STYLE;
1379
+ document.head.appendChild(styleElement);
1380
+ }
1184
1381
  function getContentInsetEndAdjustmentEnd2(ctx) {
1185
1382
  var _a3, _b;
1186
1383
  const adjustment = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.contentInsetEndAdjustment;
1187
1384
  return Math.max(0, adjustment != null ? adjustment : 0);
1188
1385
  }
1386
+ function getFiniteSnapOffsets(snapToOffsets) {
1387
+ if (!(snapToOffsets == null ? void 0 : snapToOffsets.length)) {
1388
+ return [];
1389
+ }
1390
+ const snapOffsets = [];
1391
+ const seen = /* @__PURE__ */ new Set();
1392
+ for (const offset of snapToOffsets) {
1393
+ if (Number.isFinite(offset) && !seen.has(offset)) {
1394
+ seen.add(offset);
1395
+ snapOffsets.push(offset);
1396
+ }
1397
+ }
1398
+ return snapOffsets;
1399
+ }
1400
+ function getSnapAnchorStyle(offset, horizontal) {
1401
+ return {
1402
+ height: horizontal ? "100%" : 1,
1403
+ left: horizontal ? offset : 0,
1404
+ pointerEvents: "none",
1405
+ position: "absolute",
1406
+ scrollSnapAlign: "start",
1407
+ top: horizontal ? 0 : offset,
1408
+ width: horizontal ? 1 : "100%"
1409
+ };
1410
+ }
1189
1411
  var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView2({
1190
1412
  children,
1191
1413
  style,
@@ -1203,7 +1425,7 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1203
1425
  onLayout,
1204
1426
  ...props
1205
1427
  }, ref) {
1206
- var _a3, _b, _c;
1428
+ var _a3, _b, _c, _d;
1207
1429
  const ctx = useStateContext();
1208
1430
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
1209
1431
  const scrollRef = React3.useRef(null);
@@ -1385,6 +1607,12 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1385
1607
  }
1386
1608
  };
1387
1609
  }, [isWindowScroll, onLayout]);
1610
+ const hiddenScrollIndicatorClassName = !isWindowScroll && (horizontal ? !showsHorizontalScrollIndicator && LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS : !showsVerticalScrollIndicator && LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS);
1611
+ React3.useLayoutEffect(() => {
1612
+ if (hiddenScrollIndicatorClassName) {
1613
+ ensureScrollbarHiddenStyle();
1614
+ }
1615
+ }, [hiddenScrollIndicatorClassName]);
1388
1616
  const scrollViewStyle = {
1389
1617
  ...isWindowScroll ? {} : {
1390
1618
  overflow: "auto",
@@ -1412,11 +1640,59 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1412
1640
  contentInset: _contentInset,
1413
1641
  scrollEventThrottle: _scrollEventThrottle,
1414
1642
  ScrollComponent: _ScrollComponent,
1643
+ snapToOffsets,
1415
1644
  useWindowScroll: _useWindowScroll,
1645
+ className: scrollViewClassNameProp,
1416
1646
  ...webProps
1417
1647
  } = props;
1418
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3__namespace.createElement("div", { className, ref: contentRef, style: contentStyle }, children, contentInsetEndAdjustmentSpacerStyle ? /* @__PURE__ */ React3__namespace.createElement("div", { "aria-hidden": true, style: contentInsetEndAdjustmentSpacerStyle }) : null));
1648
+ const snapOffsets = !isWindowScroll ? getFiniteSnapOffsets(snapToOffsets) : [];
1649
+ if (snapOffsets.length > 0) {
1650
+ scrollViewStyle.scrollSnapType = horizontal ? "x mandatory" : "y mandatory";
1651
+ contentStyle.position = (_d = contentStyle.position) != null ? _d : "relative";
1652
+ }
1653
+ const scrollViewClassName = hiddenScrollIndicatorClassName ? scrollViewClassNameProp ? `${scrollViewClassNameProp} ${hiddenScrollIndicatorClassName}` : hiddenScrollIndicatorClassName : scrollViewClassNameProp;
1654
+ if (IS_DEV) {
1655
+ if (/(?:^|\s)(?:[a-z0-9_-]+:)*gap(?:-[xy])?-(?:\[[^\]]+\]|[^\s]+)/.test(
1656
+ `${contentContainerClassName != null ? contentContainerClassName : ""} ${scrollViewClassNameProp != null ? scrollViewClassNameProp : ""}`
1657
+ )) {
1658
+ warnDevOnce(
1659
+ "className-gap",
1660
+ "className/contentContainerClassName gap classes are not supported in LegendList because it needs to use exact values internally. Use contentContainerStyle={{ gap: ... }} or columnWrapperStyle instead."
1661
+ );
1662
+ }
1663
+ }
1664
+ return /* @__PURE__ */ React3__namespace.createElement(
1665
+ "div",
1666
+ {
1667
+ className: scrollViewClassName,
1668
+ ref: scrollRef,
1669
+ ...webProps,
1670
+ style: scrollViewStyle
1671
+ },
1672
+ refreshControl,
1673
+ /* @__PURE__ */ React3__namespace.createElement("div", { className, ref: contentRef, style: contentStyle }, snapOffsets.map((offset) => /* @__PURE__ */ React3__namespace.createElement(
1674
+ "div",
1675
+ {
1676
+ "aria-hidden": true,
1677
+ "data-legend-list-snap-anchor": offset,
1678
+ key: `snap-${offset}`,
1679
+ style: getSnapAnchorStyle(offset, horizontal)
1680
+ }
1681
+ )), children, contentInsetEndAdjustmentSpacerStyle ? /* @__PURE__ */ React3__namespace.createElement("div", { "aria-hidden": true, style: contentInsetEndAdjustmentSpacerStyle }) : null)
1682
+ );
1419
1683
  });
1684
+
1685
+ // src/components/listComponentStyles.ts
1686
+ function getAutoOtherAxisStyle({
1687
+ horizontal,
1688
+ needsOtherAxisSize,
1689
+ otherAxisSize
1690
+ }) {
1691
+ if (!needsOtherAxisSize || !otherAxisSize || otherAxisSize <= 0) {
1692
+ return void 0;
1693
+ }
1694
+ return horizontal ? { height: otherAxisSize } : { width: otherAxisSize };
1695
+ }
1420
1696
  function useValueListener$(key, callback) {
1421
1697
  const ctx = useStateContext();
1422
1698
  React3.useLayoutEffect(() => {
@@ -1443,11 +1719,18 @@ function getScrollAdjustAxis(horizontal) {
1443
1719
  y: 1
1444
1720
  };
1445
1721
  }
1446
- function resolveScrollAdjustContentNode(el, contentNode) {
1447
- if ((contentNode == null ? void 0 : contentNode.isConnected) && contentNode.parentElement === el) {
1448
- return contentNode;
1722
+ function getScrollAdjustTarget(ctx, contentNode) {
1723
+ var _a3, _b, _c;
1724
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1725
+ const scrollElement = (_c = (_b = scrollView == null ? void 0 : scrollView.getScrollableNode) == null ? void 0 : _b.call(scrollView)) != null ? _c : null;
1726
+ let resolvedContentNode = null;
1727
+ if (scrollElement) {
1728
+ resolvedContentNode = (contentNode == null ? void 0 : contentNode.isConnected) && contentNode.parentElement === scrollElement ? contentNode : scrollElement.querySelector(`:scope > .${LEGEND_LIST_CONTENT_CONTAINER_CLASS}`);
1449
1729
  }
1450
- return el.querySelector(`:scope > .${LEGEND_LIST_CONTENT_CONTAINER_CLASS}`);
1730
+ return scrollElement ? { contentNode: resolvedContentNode, scrollElement } : null;
1731
+ }
1732
+ function scrollAdjustBy(el, left, top) {
1733
+ el.scrollBy({ behavior: "auto", left, top });
1451
1734
  }
1452
1735
  function ScrollAdjust() {
1453
1736
  const ctx = useStateContext();
@@ -1456,43 +1739,43 @@ function ScrollAdjust() {
1456
1739
  const resetPaddingBaselineRef = React3__namespace.useRef(void 0);
1457
1740
  const contentNodeRef = React3__namespace.useRef(null);
1458
1741
  const callback = React3__namespace.useCallback(() => {
1459
- var _a3, _b;
1742
+ var _a3;
1460
1743
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1461
1744
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1462
1745
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1463
- const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1464
- if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1465
- const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1466
- if (scrollDelta !== 0) {
1467
- const axis = getScrollAdjustAxis(!!ctx.state.props.horizontal);
1468
- const prevScroll = scrollView.getCurrentScrollOffset();
1469
- const el = scrollView.getScrollableNode();
1470
- const contentNode = resolveScrollAdjustContentNode(el, contentNodeRef.current);
1746
+ const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1747
+ if (scrollDelta !== 0) {
1748
+ const target = getScrollAdjustTarget(ctx, contentNodeRef.current);
1749
+ if (target) {
1750
+ const horizontal = !!ctx.state.props.horizontal;
1751
+ const axis = getScrollAdjustAxis(horizontal);
1752
+ const { contentNode, scrollElement: el } = target;
1753
+ const scrollBy = () => scrollAdjustBy(el, axis.x * scrollDelta, axis.y * scrollDelta);
1471
1754
  contentNodeRef.current = contentNode;
1472
- const scrollBy = () => scrollView.scrollBy(axis.x * scrollDelta, axis.y * scrollDelta);
1473
- if (!contentNode) {
1474
- scrollBy();
1475
- lastScrollOffsetRef.current = scrollOffset;
1476
- return;
1477
- }
1478
- const totalSize = contentNode[axis.contentSizeKey];
1479
- const viewportSize = el[axis.viewportSizeKey];
1480
- const nextScroll = prevScroll + scrollDelta;
1481
- if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize) {
1482
- const previousPaddingEnd = (_b = resetPaddingBaselineRef.current) != null ? _b : contentNode.style[axis.paddingEndProp];
1483
- resetPaddingBaselineRef.current = previousPaddingEnd;
1484
- const pad = (nextScroll + viewportSize - totalSize) * 2;
1485
- contentNode.style[axis.paddingEndProp] = `${pad}px`;
1486
- void contentNode.offsetHeight;
1487
- scrollBy();
1488
- if (resetPaddingRafRef.current !== void 0) {
1489
- cancelAnimationFrame(resetPaddingRafRef.current);
1755
+ if (contentNode) {
1756
+ const prevScroll = horizontal ? el.scrollLeft : el.scrollTop;
1757
+ const totalSize = contentNode[axis.contentSizeKey];
1758
+ const viewportSize = el[axis.viewportSizeKey];
1759
+ const nextScroll = prevScroll + scrollDelta;
1760
+ const needsTemporaryPadding = scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize;
1761
+ if (needsTemporaryPadding) {
1762
+ const previousPaddingEnd = (_a3 = resetPaddingBaselineRef.current) != null ? _a3 : contentNode.style[axis.paddingEndProp];
1763
+ resetPaddingBaselineRef.current = previousPaddingEnd;
1764
+ const pad = (nextScroll + viewportSize - totalSize) * 2;
1765
+ contentNode.style[axis.paddingEndProp] = `${pad}px`;
1766
+ void contentNode.offsetHeight;
1767
+ scrollBy();
1768
+ if (resetPaddingRafRef.current !== void 0) {
1769
+ cancelAnimationFrame(resetPaddingRafRef.current);
1770
+ }
1771
+ resetPaddingRafRef.current = requestAnimationFrame(() => {
1772
+ resetPaddingRafRef.current = void 0;
1773
+ resetPaddingBaselineRef.current = void 0;
1774
+ contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1775
+ });
1776
+ } else {
1777
+ scrollBy();
1490
1778
  }
1491
- resetPaddingRafRef.current = requestAnimationFrame(() => {
1492
- resetPaddingRafRef.current = void 0;
1493
- resetPaddingBaselineRef.current = void 0;
1494
- contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1495
- });
1496
1779
  } else {
1497
1780
  scrollBy();
1498
1781
  }
@@ -1504,10 +1787,10 @@ function ScrollAdjust() {
1504
1787
  useValueListener$("scrollAdjustUserOffset", callback);
1505
1788
  return null;
1506
1789
  }
1507
- function SnapWrapper({ ScrollComponent, ...props }) {
1790
+ var SnapWrapper = React3__namespace.forwardRef(function SnapWrapperInner({ ScrollComponent, ...props }, ref) {
1508
1791
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
1509
- return /* @__PURE__ */ React3__namespace.createElement(ScrollComponent, { ...props, snapToOffsets });
1510
- }
1792
+ return /* @__PURE__ */ React3__namespace.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
1793
+ });
1511
1794
  function WebAnchoredEndSpace({ horizontal }) {
1512
1795
  const ctx = useStateContext();
1513
1796
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
@@ -1524,15 +1807,6 @@ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1524
1807
  useOnLayoutSync({ onLayoutChange, ref });
1525
1808
  return /* @__PURE__ */ React3__namespace.createElement("div", { ...rest, ref }, children);
1526
1809
  };
1527
- var getComponent = (Component) => {
1528
- if (React3__namespace.isValidElement(Component)) {
1529
- return Component;
1530
- }
1531
- if (Component) {
1532
- return /* @__PURE__ */ React3__namespace.createElement(Component, null);
1533
- }
1534
- return null;
1535
- };
1536
1810
 
1537
1811
  // src/components/ListComponent.tsx
1538
1812
  var ListComponent = typedMemo(function ListComponent2({
@@ -1565,6 +1839,12 @@ var ListComponent = typedMemo(function ListComponent2({
1565
1839
  }) {
1566
1840
  const ctx = useStateContext();
1567
1841
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1842
+ const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
1843
+ const autoOtherAxisStyle = getAutoOtherAxisStyle({
1844
+ horizontal,
1845
+ needsOtherAxisSize: ctx.state.needsOtherAxisSize,
1846
+ otherAxisSize
1847
+ });
1568
1848
  const ScrollComponent = React3.useMemo(() => {
1569
1849
  if (!renderScrollComponent) {
1570
1850
  return ListComponentScrollView;
@@ -1603,10 +1883,10 @@ var ListComponent = typedMemo(function ListComponent2({
1603
1883
  ...rest,
1604
1884
  ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1605
1885
  contentContainerStyle: [
1606
- contentContainerStyle,
1607
1886
  horizontal ? {
1608
1887
  height: "100%"
1609
- } : {}
1888
+ } : {},
1889
+ contentContainerStyle
1610
1890
  ],
1611
1891
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1612
1892
  horizontal,
@@ -1615,7 +1895,7 @@ var ListComponent = typedMemo(function ListComponent2({
1615
1895
  onScroll: onScroll2,
1616
1896
  ref: refScrollView,
1617
1897
  ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1618
- style
1898
+ style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
1619
1899
  },
1620
1900
  /* @__PURE__ */ React3__namespace.createElement(ScrollAdjust, null),
1621
1901
  ListHeaderComponent && /* @__PURE__ */ React3__namespace.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
@@ -1803,10 +2083,9 @@ var initialScrollWatchdog = {
1803
2083
  clear(state) {
1804
2084
  initialScrollWatchdog.set(state, void 0);
1805
2085
  },
1806
- didObserveProgress(newScroll, watchdog) {
1807
- const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
2086
+ didReachTarget(newScroll, watchdog) {
1808
2087
  const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
1809
- return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET || nextDistance + INITIAL_SCROLL_MIN_TARGET_OFFSET < previousDistance;
2088
+ return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET;
1810
2089
  },
1811
2090
  get(state) {
1812
2091
  var _a3, _b;
@@ -1831,19 +2110,19 @@ var initialScrollWatchdog = {
1831
2110
  }
1832
2111
  };
1833
2112
  function setInitialScrollSession(state, options = {}) {
1834
- var _a3, _b, _c;
2113
+ var _a3, _b, _c, _d;
1835
2114
  const existingSession = state.initialScrollSession;
1836
2115
  const kind = (_a3 = options.kind) != null ? _a3 : existingSession == null ? void 0 : existingSession.kind;
1837
2116
  const completion = existingSession == null ? void 0 : existingSession.completion;
1838
- const hasBootstrapOverride = Object.hasOwn(options, "bootstrap");
1839
- const bootstrap = kind === "bootstrap" ? hasBootstrapOverride ? options.bootstrap : (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0 : void 0;
2117
+ const existingBootstrap = (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0;
2118
+ const bootstrap = kind === "bootstrap" ? options.bootstrap === null ? void 0 : (_b = options.bootstrap) != null ? _b : existingBootstrap : void 0;
1840
2119
  if (!kind) {
1841
2120
  return clearInitialScrollSession(state);
1842
2121
  }
1843
2122
  if (!state.initialScroll && !bootstrap && !hasInitialScrollSessionCompletion(completion)) {
1844
2123
  return clearInitialScrollSession(state);
1845
2124
  }
1846
- const previousDataLength = (_c = (_b = options.previousDataLength) != null ? _b : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _c : 0;
2125
+ const previousDataLength = (_d = (_c = options.previousDataLength) != null ? _c : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _d : 0;
1847
2126
  state.initialScrollSession = createInitialScrollSession({
1848
2127
  bootstrap,
1849
2128
  completion,
@@ -2333,7 +2612,8 @@ function doScrollTo(ctx, params) {
2333
2612
  }
2334
2613
  const isAnimated = !!animated;
2335
2614
  const isHorizontal = !!horizontal;
2336
- const left = isHorizontal ? offset : 0;
2615
+ const contentSize = isHorizontal ? getContentSize(ctx) : void 0;
2616
+ const left = isHorizontal ? toNativeHorizontalOffset(state, offset, contentSize) : 0;
2337
2617
  const top = isHorizontal ? 0 : offset;
2338
2618
  scroller.scrollTo({ animated: isAnimated, x: left, y: top });
2339
2619
  if (isAnimated) {
@@ -2595,7 +2875,7 @@ function advanceMeasuredInitialScroll(ctx, options) {
2595
2875
  const activeInitialTargetOffset = scrollingTo ? (_a3 = scrollingTo.targetOffset) != null ? _a3 : scrollingTo.offset : void 0;
2596
2876
  const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - resolvedOffset) > 1;
2597
2877
  const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - resolvedOffset) > 1;
2598
- const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - activeInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - activeInitialTargetOffset) <= 1;
2878
+ const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - resolvedOffset) <= 1 && Math.abs(state.scrollPending - resolvedOffset) <= 1;
2599
2879
  if (!(options == null ? void 0 : options.forceScroll) && !didOffsetChange && isInitialScrollInProgress && !didActiveInitialTargetChange) {
2600
2880
  return false;
2601
2881
  }
@@ -2667,6 +2947,30 @@ function checkAllSizesKnown(state, indices) {
2667
2947
  });
2668
2948
  }
2669
2949
 
2950
+ // src/utils/requestAdjust.ts
2951
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2952
+ const state = ctx.state;
2953
+ if (Math.abs(positionDiff) > 0.1) {
2954
+ const doit = () => {
2955
+ {
2956
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
2957
+ if (state.adjustingFromInitialMount) {
2958
+ state.adjustingFromInitialMount--;
2959
+ }
2960
+ }
2961
+ };
2962
+ state.scroll += positionDiff;
2963
+ state.scrollForNextCalculateItemsInView = void 0;
2964
+ const readyToRender = peek$(ctx, "readyToRender");
2965
+ if (readyToRender) {
2966
+ doit();
2967
+ } else {
2968
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2969
+ requestAnimationFrame(doit);
2970
+ }
2971
+ }
2972
+ }
2973
+
2670
2974
  // src/core/bootstrapInitialScroll.ts
2671
2975
  var DEFAULT_BOOTSTRAP_REVEAL_EPSILON = 1;
2672
2976
  var DEFAULT_BOOTSTRAP_REVEAL_MAX_FRAMES = 8;
@@ -2760,7 +3064,7 @@ function clearBootstrapInitialScrollSession(state) {
2760
3064
  bootstrapInitialScroll.frameHandle = void 0;
2761
3065
  }
2762
3066
  setInitialScrollSession(state, {
2763
- bootstrap: void 0,
3067
+ bootstrap: null,
2764
3068
  kind: (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind
2765
3069
  });
2766
3070
  }
@@ -2916,15 +3220,18 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2916
3220
  return;
2917
3221
  }
2918
3222
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2919
- if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2920
- clearPendingInitialScrollFooterLayout(ctx, {
2921
- dataLength: state.props.data.length,
2922
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2923
- target: initialScroll
2924
- });
2925
- return;
3223
+ const shouldKeepEndTargetAlive = isRetargetableBottomAlignedInitialScrollTarget(initialScroll) && peek$(ctx, "isAtEnd");
3224
+ if (!shouldKeepEndTargetAlive) {
3225
+ if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
3226
+ clearPendingInitialScrollFooterLayout(ctx, {
3227
+ dataLength: state.props.data.length,
3228
+ stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
3229
+ target: initialScroll
3230
+ });
3231
+ } else {
3232
+ clearFinishedViewportRetargetableInitialScroll(state);
3233
+ }
2926
3234
  }
2927
- clearFinishedViewportRetargetableInitialScroll(state);
2928
3235
  }
2929
3236
  }
2930
3237
  function startBootstrapInitialScrollOnMount(ctx, options) {
@@ -2963,7 +3270,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2963
3270
  }
2964
3271
  const shouldResetDidFinish = !!(state.didFinishInitialScroll && previousDataLength === 0 && dataLength > 0 && initialScroll.index !== void 0);
2965
3272
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2966
- const shouldClearFinishedResizePreservation = didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
3273
+ const shouldClearFinishedResizePreservation = !initialScrollAtEnd && didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
2967
3274
  if (shouldClearFinishedResizePreservation) {
2968
3275
  clearPreservedInitialScrollTarget(state);
2969
3276
  return;
@@ -3066,27 +3373,46 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
3066
3373
  }
3067
3374
  }
3068
3375
  function handleBootstrapInitialScrollLayoutChange(ctx) {
3376
+ var _a3, _b, _c, _d;
3069
3377
  const state = ctx.state;
3070
3378
  const initialScroll = state.initialScroll;
3071
- if (isOffsetInitialScrollSession(state) || state.props.data.length === 0 || !initialScroll) {
3072
- return;
3073
- }
3074
3379
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
3075
- if (!bootstrapInitialScroll && initialScroll.viewPosition !== 1) {
3076
- return;
3077
- }
3078
- const didFinishInitialScroll = state.didFinishInitialScroll;
3079
- if (didFinishInitialScroll) {
3080
- setInitialScrollTarget(state, initialScroll, {
3081
- resetDidFinish: true
3082
- });
3083
- state.clearPreservedInitialScrollOnNextFinish = true;
3380
+ if (initialScroll && state.props.data.length > 0 && !isOffsetInitialScrollSession(state) && (bootstrapInitialScroll || initialScroll.viewPosition === 1)) {
3381
+ const resolvedOffset = resolveInitialScrollOffset(ctx, initialScroll);
3382
+ const scrollingTo = ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) ? state.scrollingTo : void 0;
3383
+ if (!bootstrapInitialScroll && (scrollingTo || state.didFinishInitialScroll)) {
3384
+ const currentOffset = scrollingTo ? (_b = scrollingTo.targetOffset) != null ? _b : scrollingTo.offset : getObservedBootstrapInitialScrollOffset(state);
3385
+ const offsetDiff = resolvedOffset - currentOffset;
3386
+ if (Math.abs(offsetDiff) > DEFAULT_BOOTSTRAP_REVEAL_EPSILON) {
3387
+ if (scrollingTo) {
3388
+ const existingWatchdog = initialScrollWatchdog.get(state);
3389
+ scrollingTo.offset = resolvedOffset;
3390
+ scrollingTo.targetOffset = resolvedOffset;
3391
+ state.initialScroll = {
3392
+ ...initialScroll,
3393
+ contentOffset: resolvedOffset
3394
+ };
3395
+ state.hasScrolled = false;
3396
+ initialScrollWatchdog.set(state, {
3397
+ startScroll: (_c = existingWatchdog == null ? void 0 : existingWatchdog.startScroll) != null ? _c : state.scroll,
3398
+ targetOffset: resolvedOffset
3399
+ });
3400
+ }
3401
+ requestAdjust(ctx, offsetDiff);
3402
+ if (state.didFinishInitialScroll) {
3403
+ (_d = state.triggerCalculateItemsInView) == null ? void 0 : _d.call(state, { forceFullItemPositions: true });
3404
+ }
3405
+ }
3406
+ if (state.didFinishInitialScroll) {
3407
+ clearFinishedViewportRetargetableInitialScroll(state);
3408
+ }
3409
+ } else {
3410
+ rearmBootstrapInitialScroll(ctx, {
3411
+ scroll: resolvedOffset,
3412
+ targetIndexSeed: initialScroll.index
3413
+ });
3414
+ }
3084
3415
  }
3085
- rearmBootstrapInitialScroll(ctx, {
3086
- scroll: resolveInitialScrollOffset(ctx, initialScroll),
3087
- seedContentOffset: didFinishInitialScroll && !bootstrapInitialScroll ? getObservedBootstrapInitialScrollOffset(state) : void 0,
3088
- targetIndexSeed: initialScroll.index
3089
- });
3090
3416
  }
3091
3417
  function evaluateBootstrapInitialScroll(ctx) {
3092
3418
  var _a3, _b;
@@ -3293,7 +3619,7 @@ function checkFinishedScrollFallback(ctx) {
3293
3619
  state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
3294
3620
  };
3295
3621
  const checkHasScrolled = () => {
3296
- var _c;
3622
+ var _c, _d;
3297
3623
  state.timeoutCheckFinishedScrollFallback = void 0;
3298
3624
  const isStillScrollingTo = state.scrollingTo;
3299
3625
  if (isStillScrollingTo) {
@@ -3306,11 +3632,13 @@ function checkFinishedScrollFallback(ctx) {
3306
3632
  isStillScrollingTo
3307
3633
  );
3308
3634
  const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
3309
- const canFinishAfterSilentNativeDispatch = silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
3310
- if (shouldFinishZeroTarget || state.hasScrolled || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3635
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
3636
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
3637
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
3638
+ if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3311
3639
  finishScrollTo(ctx);
3312
- } else if (isNativeInitialPending && numChecks <= maxChecks) {
3313
- const targetOffset = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : state.scrollPending;
3640
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
3641
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
3314
3642
  scrollToFallbackOffset(ctx, targetOffset);
3315
3643
  scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3316
3644
  } else {
@@ -3346,7 +3674,14 @@ function handleInitialScrollLayoutReady(ctx) {
3346
3674
  }
3347
3675
  function initializeInitialScrollOnMount(ctx, options) {
3348
3676
  var _a3, _b;
3349
- const { dataLength, hasFooterComponent, initialContentOffset, initialScrollAtEnd, useBootstrapInitialScroll } = options;
3677
+ const {
3678
+ alwaysDispatchInitialScroll,
3679
+ dataLength,
3680
+ hasFooterComponent,
3681
+ initialContentOffset,
3682
+ initialScrollAtEnd,
3683
+ useBootstrapInitialScroll
3684
+ } = options;
3350
3685
  const state = ctx.state;
3351
3686
  const initialScroll = state.initialScroll;
3352
3687
  const resolvedInitialContentOffset = initialContentOffset != null ? initialContentOffset : 0;
@@ -3366,7 +3701,7 @@ function initializeInitialScrollOnMount(ctx, options) {
3366
3701
  return;
3367
3702
  }
3368
3703
  const hasPendingDataDependentInitialScroll = !!initialScroll && dataLength === 0 && !(resolvedInitialContentOffset === 0 && !initialScrollAtEnd);
3369
- if (!resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
3704
+ if (!alwaysDispatchInitialScroll && !resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
3370
3705
  if (initialScroll && !initialScrollAtEnd) {
3371
3706
  finishInitialScroll(ctx, {
3372
3707
  resolvedOffset: resolvedInitialContentOffset
@@ -3405,30 +3740,6 @@ function handleInitialScrollDataChange(ctx, options) {
3405
3740
  advanceCurrentInitialScrollSession(ctx);
3406
3741
  }
3407
3742
 
3408
- // src/utils/requestAdjust.ts
3409
- function requestAdjust(ctx, positionDiff, dataChanged) {
3410
- const state = ctx.state;
3411
- if (Math.abs(positionDiff) > 0.1) {
3412
- const doit = () => {
3413
- {
3414
- state.scrollAdjustHandler.requestAdjust(positionDiff);
3415
- if (state.adjustingFromInitialMount) {
3416
- state.adjustingFromInitialMount--;
3417
- }
3418
- }
3419
- };
3420
- state.scroll += positionDiff;
3421
- state.scrollForNextCalculateItemsInView = void 0;
3422
- const readyToRender = peek$(ctx, "readyToRender");
3423
- if (readyToRender) {
3424
- doit();
3425
- } else {
3426
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
3427
- requestAnimationFrame(doit);
3428
- }
3429
- }
3430
- }
3431
-
3432
3743
  // src/core/mvcp.ts
3433
3744
  var MVCP_POSITION_EPSILON = 0.1;
3434
3745
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -3702,15 +4013,27 @@ function prepareMVCP(ctx, dataChanged) {
3702
4013
  return;
3703
4014
  }
3704
4015
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
3705
- requestAdjust(ctx, positionDiff);
4016
+ const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
4017
+ if (!shouldSkipAdjustForMaintainedEnd) {
4018
+ requestAdjust(ctx, positionDiff);
4019
+ }
3706
4020
  }
3707
4021
  };
3708
4022
  }
3709
4023
  }
3710
4024
 
4025
+ // src/core/resetLayoutCachesForDataChange.ts
4026
+ function resetLayoutCachesForDataChange(state) {
4027
+ state.indexByKey.clear();
4028
+ state.idCache.length = 0;
4029
+ state.positions.length = 0;
4030
+ state.columns.length = 0;
4031
+ state.columnSpans.length = 0;
4032
+ }
4033
+
3711
4034
  // src/core/syncMountedContainer.ts
3712
4035
  function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3713
- var _a3, _b, _c, _d, _e, _f, _g, _h;
4036
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
3714
4037
  const state = ctx.state;
3715
4038
  const {
3716
4039
  columns,
@@ -3722,7 +4045,8 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3722
4045
  if (item === void 0) {
3723
4046
  return { didChangePosition: false, didRefreshData: false };
3724
4047
  }
3725
- const updateLayout = (_a3 = options == null ? void 0 : options.updateLayout) != null ? _a3 : true;
4048
+ const itemKey = (_a3 = state.idCache[itemIndex]) != null ? _a3 : getId(state, itemIndex);
4049
+ const updateLayout = (_b = options == null ? void 0 : options.updateLayout) != null ? _b : true;
3726
4050
  let didChangePosition = false;
3727
4051
  let didRefreshData = false;
3728
4052
  if (updateLayout) {
@@ -3731,7 +4055,9 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3731
4055
  set$(ctx, `containerPosition${containerIndex}`, POSITION_OUT_OF_VIEW);
3732
4056
  return { didChangePosition: false, didRefreshData: false };
3733
4057
  }
3734
- const position = (positionValue || 0) - ((_b = options == null ? void 0 : options.scrollAdjustPending) != null ? _b : 0);
4058
+ const logicalPosition = (positionValue || 0) - ((_c = options == null ? void 0 : options.scrollAdjustPending) != null ? _c : 0);
4059
+ const itemSize = (_d = state.sizes.get(itemKey)) != null ? _d : getItemSize(ctx, itemKey, itemIndex, item);
4060
+ const position = toPhysicalHorizontalItemPosition(state, logicalPosition, itemSize, peek$(ctx, "totalSize"));
3735
4061
  const column = columns[itemIndex] || 1;
3736
4062
  const span = columnSpans[itemIndex] || 1;
3737
4063
  const prevPos = peek$(ctx, `containerPosition${containerIndex}`);
@@ -3750,15 +4076,15 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3750
4076
  }
3751
4077
  const prevData = peek$(ctx, `containerItemData${containerIndex}`);
3752
4078
  if (prevData !== item) {
3753
- 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;
3754
- const cachedComparison = (_e = pendingDataComparison == null ? void 0 : pendingDataComparison.byIndex[itemIndex]) != null ? _e : 0;
4079
+ 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;
4080
+ const cachedComparison = (_g = pendingDataComparison == null ? void 0 : pendingDataComparison.byIndex[itemIndex]) != null ? _g : 0;
3755
4081
  if (cachedComparison === 2) {
3756
4082
  set$(ctx, `containerItemData${containerIndex}`, item);
3757
4083
  didRefreshData = true;
3758
4084
  } else if (cachedComparison !== 1) {
3759
- const itemKey = (_g = (_f = peek$(ctx, `containerItemKey${containerIndex}`)) != null ? _f : state.idCache[itemIndex]) != null ? _g : getId(state, itemIndex);
4085
+ const nextItemKey = (_h = peek$(ctx, `containerItemKey${containerIndex}`)) != null ? _h : itemKey;
3760
4086
  const prevKey = keyExtractor == null ? void 0 : keyExtractor(prevData, itemIndex);
3761
- if (prevData === void 0 || !keyExtractor || prevKey !== itemKey) {
4087
+ if (prevData === void 0 || !keyExtractor || prevKey !== nextItemKey) {
3762
4088
  set$(ctx, `containerItemData${containerIndex}`, item);
3763
4089
  didRefreshData = true;
3764
4090
  } else if (!itemsAreEqual) {
@@ -3775,7 +4101,7 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3775
4101
  };
3776
4102
  }
3777
4103
  }
3778
- if ((_h = state.pendingDataComparison) == null ? void 0 : _h.byIndex) {
4104
+ if ((_i = state.pendingDataComparison) == null ? void 0 : _i.byIndex) {
3779
4105
  state.pendingDataComparison.byIndex[itemIndex] = isEqual ? 1 : 2;
3780
4106
  }
3781
4107
  if (!isEqual) {
@@ -3940,11 +4266,13 @@ function updateSnapToOffsets(ctx) {
3940
4266
  const {
3941
4267
  props: { snapToIndices }
3942
4268
  } = state;
4269
+ const contentSize = state.props.horizontal ? getContentSize(ctx) : void 0;
3943
4270
  const snapToOffsets = Array(snapToIndices.length);
3944
4271
  for (let i = 0; i < snapToIndices.length; i++) {
3945
4272
  const idx = snapToIndices[i];
3946
4273
  getId(state, idx);
3947
- snapToOffsets[i] = state.positions[idx];
4274
+ const logicalOffset = state.positions[idx];
4275
+ snapToOffsets[i] = toNativeHorizontalOffset(state, logicalOffset, contentSize);
3948
4276
  }
3949
4277
  set$(ctx, "snapToOffsets", snapToOffsets);
3950
4278
  }
@@ -4321,6 +4649,30 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
4321
4649
  var unstableBatchedUpdates = ReactDOM__namespace.unstable_batchedUpdates;
4322
4650
  var batchedUpdates = typeof unstableBatchedUpdates === "function" ? unstableBatchedUpdates : (fn) => fn();
4323
4651
 
4652
+ // src/utils/containerPool.ts
4653
+ var MIN_INITIAL_CONTAINER_POOL_SIZE = 32;
4654
+ var MAX_INITIAL_SPARE_CONTAINERS = 64;
4655
+ function getInitialContainerPoolSize(dataLength, numContainers, initialContainerPoolRatio) {
4656
+ if (dataLength <= 0 || numContainers <= 0) {
4657
+ return 0;
4658
+ }
4659
+ const ratioPoolSize = Math.ceil(numContainers * initialContainerPoolRatio);
4660
+ const cappedSparePoolSize = numContainers + MAX_INITIAL_SPARE_CONTAINERS;
4661
+ const targetPoolSize = Math.max(
4662
+ numContainers,
4663
+ Math.min(ratioPoolSize, cappedSparePoolSize),
4664
+ Math.min(dataLength, MIN_INITIAL_CONTAINER_POOL_SIZE)
4665
+ );
4666
+ const maxUsefulPoolSize = Math.max(dataLength, numContainers);
4667
+ return Math.min(maxUsefulPoolSize, targetPoolSize);
4668
+ }
4669
+ function getExpandedContainerPoolSize(dataLength, numContainers) {
4670
+ if (dataLength <= 0 || numContainers <= 0) {
4671
+ return 0;
4672
+ }
4673
+ return Math.min(Math.max(dataLength, numContainers), Math.max(numContainers, Math.ceil(numContainers * 1.5)));
4674
+ }
4675
+
4324
4676
  // src/utils/findAvailableContainers.ts
4325
4677
  function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers, protectedKeys) {
4326
4678
  const numContainers = peek$(ctx, "numContainers");
@@ -4526,10 +4878,9 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
4526
4878
  function calculateItemsInView(ctx, params = {}) {
4527
4879
  const state = ctx.state;
4528
4880
  batchedUpdates(() => {
4529
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
4881
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
4530
4882
  const {
4531
4883
  columns,
4532
- columnSpans,
4533
4884
  containerItemKeys,
4534
4885
  enableScrollForNextCalculateItemsInView,
4535
4886
  idCache,
@@ -4573,18 +4924,38 @@ function calculateItemsInView(ctx, params = {}) {
4573
4924
  // current initial-scroll target instead of transient native adjustments.
4574
4925
  resolveInitialScrollOffset(ctx, initialScroll)
4575
4926
  ) : state.scroll;
4576
- const scrollAdjustPending = (_c = peek$(ctx, "scrollAdjustPending")) != null ? _c : 0;
4577
- const scrollAdjustPad = scrollAdjustPending - topPad;
4578
- let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
4579
- if (scroll + scrollLength > totalSize) {
4580
- scroll = Math.max(0, totalSize - scrollLength);
4581
- }
4927
+ let scrollAdjustPending = 0;
4928
+ let scrollAdjustPad = 0;
4929
+ let scroll = 0;
4930
+ let scrollTopBuffered = 0;
4931
+ let scrollBottom = 0;
4932
+ let scrollBottomBuffered = 0;
4933
+ let nativeScrollState = scrollState;
4934
+ const updateScroll2 = (nextScrollState) => {
4935
+ var _a4;
4936
+ nativeScrollState = nextScrollState;
4937
+ scrollAdjustPending = (_a4 = peek$(ctx, "scrollAdjustPending")) != null ? _a4 : 0;
4938
+ scrollAdjustPad = scrollAdjustPending - topPad;
4939
+ scroll = Math.round(nextScrollState + scrollExtra + scrollAdjustPad);
4940
+ if (scroll + scrollLength > totalSize) {
4941
+ scroll = Math.max(0, totalSize - scrollLength);
4942
+ }
4943
+ };
4944
+ updateScroll2(scrollState);
4582
4945
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
4583
4946
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
4584
4947
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
4948
+ const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
4585
4949
  if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
4586
4950
  set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
4587
4951
  }
4952
+ const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyIndicesArr.length > 0 && stickyIndexDidChange;
4953
+ const finishCalculateItemsInView = shouldNotifyStickyHeaderChange ? () => {
4954
+ const item = data[nextActiveStickyIndex];
4955
+ if (item !== void 0) {
4956
+ onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4957
+ }
4958
+ } : void 0;
4588
4959
  let scrollBufferTop = drawDistance;
4589
4960
  let scrollBufferBottom = drawDistance;
4590
4961
  if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
@@ -4594,28 +4965,30 @@ function calculateItemsInView(ctx, params = {}) {
4594
4965
  scrollBufferTop = drawDistance * 1.5;
4595
4966
  scrollBufferBottom = drawDistance * 0.5;
4596
4967
  }
4597
- const scrollTopBuffered = scroll - scrollBufferTop;
4598
- const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
4599
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4968
+ const updateScrollRange = () => {
4969
+ const scrollStart = Math.max(0, scroll);
4970
+ const overscrollBeforeContent = Math.max(0, -nativeScrollState);
4971
+ scrollTopBuffered = scrollStart - scrollBufferTop;
4972
+ scrollBottom = Math.max(scrollStart, scroll + scrollLength + overscrollBeforeContent);
4973
+ scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4974
+ };
4975
+ updateScrollRange();
4600
4976
  if (!suppressInitialScrollSideEffects && !dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
4601
4977
  const { top, bottom } = scrollForNextCalculateItemsInView;
4602
4978
  if (top === null && bottom === null) {
4603
4979
  state.scrollForNextCalculateItemsInView = void 0;
4604
4980
  } else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
4605
4981
  if (!isInMVCPActiveMode(state)) {
4982
+ finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4606
4983
  return;
4607
4984
  }
4608
4985
  }
4609
4986
  }
4610
4987
  const checkMVCP = doMVCP && !suppressInitialScrollSideEffects ? prepareMVCP(ctx, dataChanged) : void 0;
4611
4988
  if (dataChanged) {
4612
- indexByKey.clear();
4613
- idCache.length = 0;
4614
- positions.length = 0;
4615
- columns.length = 0;
4616
- columnSpans.length = 0;
4989
+ resetLayoutCachesForDataChange(state);
4617
4990
  }
4618
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_d = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _d : 0;
4991
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4619
4992
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4620
4993
  updateItemPositions(ctx, dataChanged, {
4621
4994
  doMVCP,
@@ -4640,21 +5013,25 @@ function calculateItemsInView(ctx, params = {}) {
4640
5013
  }
4641
5014
  }
4642
5015
  const scrollBeforeMVCP = state.scroll;
4643
- const scrollAdjustPendingBeforeMVCP = (_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0;
5016
+ const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
4644
5017
  checkMVCP == null ? void 0 : checkMVCP();
4645
- const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0) !== scrollAdjustPendingBeforeMVCP);
5018
+ const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0) !== scrollAdjustPendingBeforeMVCP);
5019
+ if (didMVCPAdjustScroll && initialScroll) {
5020
+ updateScroll2(state.scroll);
5021
+ updateScrollRange();
5022
+ }
4646
5023
  let startNoBuffer = null;
4647
5024
  let startBuffered = null;
4648
5025
  let startBufferedId = null;
4649
5026
  let endNoBuffer = null;
4650
5027
  let endBuffered = null;
4651
- let loopStart = (_g = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _g : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
5028
+ let loopStart = (_f = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _f : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4652
5029
  for (let i = loopStart; i >= 0; i--) {
4653
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
5030
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
4654
5031
  const top = positions[i];
4655
- const size = (_i = sizes.get(id)) != null ? _i : getItemSize(ctx, id, i, data[i]);
5032
+ const size = (_h = sizes.get(id)) != null ? _h : getItemSize(ctx, id, i, data[i]);
4656
5033
  const bottom = top + size;
4657
- if (bottom > scroll - scrollBufferTop) {
5034
+ if (bottom > scrollTopBuffered) {
4658
5035
  loopStart = i;
4659
5036
  } else {
4660
5037
  break;
@@ -4683,8 +5060,8 @@ function calculateItemsInView(ctx, params = {}) {
4683
5060
  let firstFullyOnScreenIndex;
4684
5061
  const dataLength = data.length;
4685
5062
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
4686
- const id = (_j = idCache[i]) != null ? _j : getId(state, i);
4687
- const size = (_k = sizes.get(id)) != null ? _k : getItemSize(ctx, id, i, data[i]);
5063
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
5064
+ const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
4688
5065
  const top = positions[i];
4689
5066
  if (!foundEnd) {
4690
5067
  if (startNoBuffer === null && top + size > scroll) {
@@ -4723,7 +5100,7 @@ function calculateItemsInView(ctx, params = {}) {
4723
5100
  const firstVisibleAnchorIndex = firstFullyOnScreenIndex != null ? firstFullyOnScreenIndex : startNoBuffer;
4724
5101
  if (firstVisibleAnchorIndex !== null && firstVisibleAnchorIndex !== void 0 && endNoBuffer !== null) {
4725
5102
  for (let i = firstVisibleAnchorIndex; i <= endNoBuffer; i++) {
4726
- const id = (_l = idCache[i]) != null ? _l : getId(state, i);
5103
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
4727
5104
  idsInView.push(id);
4728
5105
  }
4729
5106
  }
@@ -4756,7 +5133,7 @@ function calculateItemsInView(ctx, params = {}) {
4756
5133
  const needNewContainers = [];
4757
5134
  const needNewContainersSet = /* @__PURE__ */ new Set();
4758
5135
  for (let i = startBuffered; i <= endBuffered; i++) {
4759
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
5136
+ const id = (_l = idCache[i]) != null ? _l : getId(state, i);
4760
5137
  if (!containerItemKeys.has(id)) {
4761
5138
  needNewContainersSet.add(i);
4762
5139
  needNewContainers.push(i);
@@ -4765,7 +5142,7 @@ function calculateItemsInView(ctx, params = {}) {
4765
5142
  if (alwaysRenderArr.length > 0) {
4766
5143
  for (const index of alwaysRenderArr) {
4767
5144
  if (index < 0 || index >= dataLength) continue;
4768
- const id = (_n = idCache[index]) != null ? _n : getId(state, index);
5145
+ const id = (_m = idCache[index]) != null ? _m : getId(state, index);
4769
5146
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
4770
5147
  needNewContainersSet.add(index);
4771
5148
  needNewContainers.push(index);
@@ -4804,7 +5181,7 @@ function calculateItemsInView(ctx, params = {}) {
4804
5181
  for (let idx = 0; idx < needNewContainers.length; idx++) {
4805
5182
  const i = needNewContainers[idx];
4806
5183
  const containerIndex = availableContainers[idx];
4807
- const id = (_o = idCache[i]) != null ? _o : getId(state, i);
5184
+ const id = (_n = idCache[i]) != null ? _n : getId(state, i);
4808
5185
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
4809
5186
  if (oldKey && oldKey !== id) {
4810
5187
  containerItemKeys.delete(oldKey);
@@ -4815,7 +5192,7 @@ function calculateItemsInView(ctx, params = {}) {
4815
5192
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
4816
5193
  }
4817
5194
  containerItemKeys.set(id, containerIndex);
4818
- (_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.add(id);
5195
+ (_o = state.userScrollAnchorResetKeys) == null ? void 0 : _o.add(id);
4819
5196
  const containerSticky = `containerSticky${containerIndex}`;
4820
5197
  const isSticky = stickyIndicesSet.has(i);
4821
5198
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -4839,17 +5216,17 @@ function calculateItemsInView(ctx, params = {}) {
4839
5216
  if (numContainers !== prevNumContainers) {
4840
5217
  set$(ctx, "numContainers", numContainers);
4841
5218
  if (numContainers > peek$(ctx, "numContainersPooled")) {
4842
- set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
5219
+ set$(ctx, "numContainersPooled", getExpandedContainerPoolSize(dataLength, numContainers));
4843
5220
  }
4844
5221
  }
4845
5222
  }
4846
- if (((_q = state.userScrollAnchorResetKeys) == null ? void 0 : _q.size) === 0) {
5223
+ if (((_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.size) === 0) {
4847
5224
  state.userScrollAnchorResetKeys = void 0;
4848
5225
  }
4849
5226
  if (alwaysRenderArr.length > 0) {
4850
5227
  for (const index of alwaysRenderArr) {
4851
5228
  if (index < 0 || index >= dataLength) continue;
4852
- const id = (_r = idCache[index]) != null ? _r : getId(state, index);
5229
+ const id = (_q = idCache[index]) != null ? _q : getId(state, index);
4853
5230
  const containerIndex = containerItemKeys.get(id);
4854
5231
  if (containerIndex !== void 0) {
4855
5232
  state.stickyContainerPool.add(containerIndex);
@@ -4923,12 +5300,7 @@ function calculateItemsInView(ctx, params = {}) {
4923
5300
  );
4924
5301
  }
4925
5302
  }
4926
- if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
4927
- const item = data[nextActiveStickyIndex];
4928
- if (item !== void 0) {
4929
- onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4930
- }
4931
- }
5303
+ finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4932
5304
  });
4933
5305
  }
4934
5306
 
@@ -4953,21 +5325,36 @@ function doMaintainScrollAtEnd(ctx) {
4953
5325
  if (contentSize < state.scrollLength) {
4954
5326
  state.scroll = 0;
4955
5327
  }
4956
- requestAnimationFrame(() => {
4957
- var _a3;
4958
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
4959
- state.maintainingScrollAtEnd = true;
4960
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
4961
- animated: maintainScrollAtEnd.animated
4962
- });
4963
- setTimeout(
4964
- () => {
4965
- state.maintainingScrollAtEnd = false;
4966
- },
4967
- maintainScrollAtEnd.animated ? 500 : 0
4968
- );
4969
- }
4970
- });
5328
+ if (!state.maintainingScrollAtEnd) {
5329
+ state.maintainingScrollAtEnd = true;
5330
+ requestAnimationFrame(() => {
5331
+ if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
5332
+ const scroller = refScroller.current;
5333
+ if (state.props.horizontal && isHorizontalRTL(state)) {
5334
+ const currentContentSize = getContentSize(ctx);
5335
+ const logicalEndOffset = getLogicalHorizontalMaxOffset(state, currentContentSize);
5336
+ const nativeOffset = toNativeHorizontalOffset(state, logicalEndOffset, currentContentSize);
5337
+ scroller == null ? void 0 : scroller.scrollTo({
5338
+ animated: maintainScrollAtEnd.animated,
5339
+ x: nativeOffset,
5340
+ y: 0
5341
+ });
5342
+ } else {
5343
+ scroller == null ? void 0 : scroller.scrollToEnd({
5344
+ animated: maintainScrollAtEnd.animated
5345
+ });
5346
+ }
5347
+ setTimeout(
5348
+ () => {
5349
+ state.maintainingScrollAtEnd = false;
5350
+ },
5351
+ maintainScrollAtEnd.animated ? 500 : 0
5352
+ );
5353
+ } else {
5354
+ state.maintainingScrollAtEnd = false;
5355
+ }
5356
+ });
5357
+ }
4971
5358
  return true;
4972
5359
  }
4973
5360
  return false;
@@ -5079,14 +5466,21 @@ function doInitialAllocateContainers(ctx) {
5079
5466
  } else {
5080
5467
  averageItemSize = estimatedItemSize;
5081
5468
  }
5082
- const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
5469
+ const numContainers = Math.max(
5470
+ 1,
5471
+ Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns)
5472
+ );
5083
5473
  for (let i = 0; i < numContainers; i++) {
5084
5474
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
5085
5475
  set$(ctx, `containerColumn${i}`, -1);
5086
5476
  set$(ctx, `containerSpan${i}`, 1);
5087
5477
  }
5088
5478
  set$(ctx, "numContainers", numContainers);
5089
- set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
5479
+ set$(
5480
+ ctx,
5481
+ "numContainersPooled",
5482
+ getInitialContainerPoolSize(data.length, numContainers, state.props.initialContainerPoolRatio)
5483
+ );
5090
5484
  if (state.lastLayout) {
5091
5485
  if (state.initialScroll) {
5092
5486
  requestAnimationFrame(() => {
@@ -5149,7 +5543,8 @@ function handleLayout(ctx, layoutParam, setCanRender) {
5149
5543
  }
5150
5544
  checkThresholds(ctx);
5151
5545
  if (state) {
5152
- state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
5546
+ const crossAxisPadding = state.props.horizontal ? (state.props.stylePaddingTop || 0) + (state.props.stylePaddingBottom || 0) : (state.props.stylePaddingLeft || 0) + (state.props.stylePaddingRight || 0);
5547
+ state.needsOtherAxisSize = otherAxisSize - crossAxisPadding < 10;
5153
5548
  }
5154
5549
  if (IS_DEV && measuredLength === 0) {
5155
5550
  warnDevOnce(
@@ -5237,8 +5632,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
5237
5632
  // src/core/onScroll.ts
5238
5633
  function trackInitialScrollNativeProgress(state, newScroll) {
5239
5634
  const initialNativeScrollWatchdog = initialScrollWatchdog.get(state);
5240
- const didInitialScrollProgress = !!initialNativeScrollWatchdog && initialScrollWatchdog.didObserveProgress(newScroll, initialNativeScrollWatchdog);
5241
- if (didInitialScrollProgress) {
5635
+ const didInitialScrollReachTarget = !!initialNativeScrollWatchdog && initialScrollWatchdog.didReachTarget(newScroll, initialNativeScrollWatchdog);
5636
+ if (didInitialScrollReachTarget) {
5242
5637
  initialScrollWatchdog.clear(state);
5243
5638
  return;
5244
5639
  }
@@ -5263,7 +5658,7 @@ function cloneScrollEvent(event) {
5263
5658
  };
5264
5659
  }
5265
5660
  function onScroll(ctx, event) {
5266
- var _a3, _b, _c, _d;
5661
+ var _a3, _b, _c, _d, _e;
5267
5662
  const state = ctx.state;
5268
5663
  const { scrollProcessingEnabled } = state;
5269
5664
  if (scrollProcessingEnabled === false) {
@@ -5282,6 +5677,9 @@ function onScroll(ctx, event) {
5282
5677
  }
5283
5678
  }
5284
5679
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
5680
+ if (state.props.horizontal) {
5681
+ newScroll = toLogicalHorizontalOffset(state, newScroll, (_e = event.nativeEvent.contentSize) == null ? void 0 : _e.width);
5682
+ }
5285
5683
  if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
5286
5684
  const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
5287
5685
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
@@ -5376,16 +5774,20 @@ function maybeUpdateAnchoredEndSpace(ctx) {
5376
5774
  let contentBelowAnchor = 0;
5377
5775
  const footerSize = ctx.values.get("footerSize") || 0;
5378
5776
  const stylePaddingBottom = state.props.stylePaddingBottom || 0;
5777
+ let hasUnknownTailSize = false;
5379
5778
  for (let index = anchorIndex; index < data.length; index++) {
5380
5779
  const itemKey = getId(state, index);
5381
5780
  const size = itemKey ? state.sizesKnown.get(itemKey) : void 0;
5382
5781
  const effectiveSize = index === anchorIndex && anchorMaxSize !== void 0 ? Math.min(size || 0, Math.max(0, anchorMaxSize)) : size;
5782
+ if (size === void 0) {
5783
+ hasUnknownTailSize = true;
5784
+ }
5383
5785
  if (effectiveSize !== null && effectiveSize !== void 0 && effectiveSize > 0) {
5384
5786
  contentBelowAnchor += effectiveSize;
5385
5787
  }
5386
5788
  }
5387
5789
  contentBelowAnchor += footerSize + stylePaddingBottom;
5388
- nextSize = Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5790
+ nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5389
5791
  }
5390
5792
  }
5391
5793
  if (previousSize !== nextSize) {
@@ -5449,6 +5851,16 @@ function runOrScheduleMVCPRecalculate(ctx) {
5449
5851
  });
5450
5852
  }
5451
5853
  }
5854
+ function updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal) {
5855
+ const state = ctx.state;
5856
+ if (state.needsOtherAxisSize) {
5857
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
5858
+ const currentOtherAxisSize = peek$(ctx, "otherAxisSize");
5859
+ if (!currentOtherAxisSize || otherAxisSize > currentOtherAxisSize) {
5860
+ set$(ctx, "otherAxisSize", otherAxisSize);
5861
+ }
5862
+ }
5863
+ }
5452
5864
  function updateItemSize(ctx, itemKey, sizeObj) {
5453
5865
  var _a3;
5454
5866
  const state = ctx.state;
@@ -5457,15 +5869,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5457
5869
  const {
5458
5870
  didContainersLayout,
5459
5871
  sizesKnown,
5460
- props: {
5461
- getFixedItemSize,
5462
- getItemType,
5463
- horizontal,
5464
- suggestEstimatedItemSize,
5465
- onItemSizeChanged,
5466
- data,
5467
- maintainScrollAtEnd
5468
- }
5872
+ props: { getFixedItemSize, getItemType, horizontal, onItemSizeChanged, data, maintainScrollAtEnd }
5469
5873
  } = state;
5470
5874
  if (!data) return;
5471
5875
  const index = state.indexByKey.get(itemKey);
@@ -5480,13 +5884,13 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5480
5884
  const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
5481
5885
  const size2 = getFixedItemSize(itemData, index, type);
5482
5886
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
5887
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5483
5888
  return;
5484
5889
  }
5485
5890
  }
5486
5891
  let needsRecalculate = !didContainersLayout;
5487
5892
  let shouldMaintainScrollAtEnd = false;
5488
5893
  let minIndexSizeChanged;
5489
- let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
5490
5894
  const prevSizeKnown = state.sizesKnown.get(itemKey);
5491
5895
  const diff = updateOneItemSize(ctx, itemKey, sizeObj);
5492
5896
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
@@ -5497,10 +5901,6 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5497
5901
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
5498
5902
  needsRecalculate = true;
5499
5903
  }
5500
- if (state.needsOtherAxisSize) {
5501
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
5502
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
5503
- }
5504
5904
  if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
5505
5905
  shouldMaintainScrollAtEnd = true;
5506
5906
  }
@@ -5516,22 +5916,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5516
5916
  if (minIndexSizeChanged !== void 0) {
5517
5917
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
5518
5918
  }
5519
- if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
5520
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
5521
- state.timeoutSizeMessage = setTimeout(() => {
5522
- var _a4;
5523
- state.timeoutSizeMessage = void 0;
5524
- const num = state.sizesKnown.size;
5525
- const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
5526
- console.warn(
5527
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
5528
- );
5529
- }, 1e3);
5530
- }
5531
- const cur = peek$(ctx, "otherAxisSize");
5532
- if (!cur || maxOtherAxisSize > cur) {
5533
- set$(ctx, "otherAxisSize", maxOtherAxisSize);
5534
- }
5919
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5535
5920
  if (didContainersLayout || checkAllSizesKnown(state, getMountedBufferedIndices(state))) {
5536
5921
  if (needsRecalculate) {
5537
5922
  state.scrollForNextCalculateItemsInView = void 0;
@@ -5632,12 +6017,47 @@ function createColumnWrapperStyle(contentContainerStyle) {
5632
6017
  }
5633
6018
 
5634
6019
  // src/utils/createImperativeHandle.ts
6020
+ var DEFAULT_AVERAGE_ITEM_SIZE_TYPE = "default";
6021
+ function getAverageItemSizes(state) {
6022
+ const averageItemSizes = {};
6023
+ for (const itemType in state.averageSizes) {
6024
+ const averageSize = state.averageSizes[itemType];
6025
+ if (averageSize) {
6026
+ averageItemSizes[itemType || DEFAULT_AVERAGE_ITEM_SIZE_TYPE] = {
6027
+ average: averageSize.avg,
6028
+ count: averageSize.num
6029
+ };
6030
+ }
6031
+ }
6032
+ return averageItemSizes;
6033
+ }
5635
6034
  function createImperativeHandle(ctx) {
5636
6035
  const state = ctx.state;
5637
6036
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
5638
6037
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
5639
6038
  let imperativeScrollToken = 0;
5640
6039
  const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
6040
+ const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
6041
+ var _a3;
6042
+ const props = state.props;
6043
+ const dataLength = props.data.length;
6044
+ const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
6045
+ if (targetIndex < 0) {
6046
+ return allowEmpty;
6047
+ }
6048
+ if (targetIndex >= dataLength) {
6049
+ return false;
6050
+ }
6051
+ if (anchorIndex === void 0 || anchorIndex < 0 || anchorIndex >= dataLength || targetIndex < anchorIndex || props.getFixedItemSize) {
6052
+ return true;
6053
+ }
6054
+ for (let index = anchorIndex; index < dataLength; index++) {
6055
+ if (!state.sizesKnown.has(getId(state, index))) {
6056
+ return false;
6057
+ }
6058
+ }
6059
+ return true;
6060
+ };
5641
6061
  const runWhenReady = (token, run, isReady) => {
5642
6062
  const startedAt = Date.now();
5643
6063
  let stableFrames = 0;
@@ -5659,11 +6079,10 @@ function createImperativeHandle(ctx) {
5659
6079
  };
5660
6080
  requestAnimationFrame(check);
5661
6081
  };
5662
- const runScrollWithPromise = (run, options) => new Promise((resolve) => {
5663
- var _a3, _b;
6082
+ const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
6083
+ var _a3;
5664
6084
  const token = ++imperativeScrollToken;
5665
- const isReady = (_a3 = options == null ? void 0 : options.isReady) != null ? _a3 : (() => true);
5666
- (_b = state.pendingScrollResolve) == null ? void 0 : _b.call(state);
6085
+ (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
5667
6086
  state.pendingScrollResolve = resolve;
5668
6087
  const runNow = () => {
5669
6088
  if (token !== imperativeScrollToken) {
@@ -5738,6 +6157,7 @@ function createImperativeHandle(ctx) {
5738
6157
  },
5739
6158
  end: state.endNoBuffer,
5740
6159
  endBuffered: state.endBuffered,
6160
+ getAverageItemSizes: () => getAverageItemSizes(state),
5741
6161
  isAtEnd: peek$(ctx, "isAtEnd"),
5742
6162
  isAtStart: peek$(ctx, "isAtStart"),
5743
6163
  isEndReached: state.isEndReached,
@@ -5780,40 +6200,34 @@ function createImperativeHandle(ctx) {
5780
6200
  }
5781
6201
  return false;
5782
6202
  }),
5783
- scrollToEnd: (options) => runScrollWithPromise(() => {
5784
- const data = state.props.data;
5785
- const stylePaddingBottom = state.props.stylePaddingBottom;
5786
- const index = data.length - 1;
5787
- if (index !== -1) {
5788
- const paddingBottom = stylePaddingBottom || 0;
5789
- const footerSize = peek$(ctx, "footerSize") || 0;
5790
- scrollToIndex(ctx, {
5791
- ...options,
5792
- index,
5793
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5794
- viewPosition: 1
5795
- });
5796
- return true;
5797
- }
5798
- return false;
5799
- }),
5800
- scrollToIndex: (params) => {
5801
- const shouldWaitForOutOfRangeTarget = params.index >= 0 && params.index >= state.props.data.length;
5802
- const options = shouldWaitForOutOfRangeTarget ? {
5803
- isReady: () => {
5804
- var _a3;
5805
- const props = state.props;
5806
- const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5807
- const lastIndex = props.data.length - 1;
5808
- const isInRange = params.index < props.data.length;
5809
- const shouldWaitForAnchorSize = isInRange && anchorIndex !== void 0 && anchorIndex >= 0 && params.index >= anchorIndex && !props.getFixedItemSize && !state.sizesKnown.has(getId(state, lastIndex));
5810
- return isInRange && !shouldWaitForAnchorSize;
6203
+ scrollToEnd: (options) => runScrollWithPromise(
6204
+ () => {
6205
+ const data = state.props.data;
6206
+ const stylePaddingBottom = state.props.stylePaddingBottom;
6207
+ const index = data.length - 1;
6208
+ if (index !== -1) {
6209
+ const paddingBottom = stylePaddingBottom || 0;
6210
+ const footerSize = peek$(ctx, "footerSize") || 0;
6211
+ scrollToIndex(ctx, {
6212
+ ...options,
6213
+ index,
6214
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
6215
+ viewPosition: 1
6216
+ });
6217
+ return true;
5811
6218
  }
5812
- } : void 0;
5813
- return runScrollWithPromise(() => {
5814
- scrollToIndex(ctx, params);
5815
- return true;
5816
- }, options);
6219
+ return false;
6220
+ },
6221
+ () => isScrollToIndexReady(state.props.data.length - 1, true)
6222
+ ),
6223
+ scrollToIndex: (params) => {
6224
+ return runScrollWithPromise(
6225
+ () => {
6226
+ scrollToIndex(ctx, params);
6227
+ return true;
6228
+ },
6229
+ params.index >= 0 ? () => isScrollToIndexReady(params.index) : void 0
6230
+ );
5817
6231
  },
5818
6232
  scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
5819
6233
  const data = state.props.data;
@@ -6077,7 +6491,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6077
6491
  getFixedItemSize,
6078
6492
  getItemType,
6079
6493
  horizontal,
6080
- initialContainerPoolRatio = 2,
6494
+ rtl,
6495
+ initialContainerPoolRatio = 3,
6496
+ estimatedHeaderSize,
6081
6497
  initialScrollAtEnd = false,
6082
6498
  initialScrollIndex: initialScrollIndexProp,
6083
6499
  initialScrollOffset: initialScrollOffsetProp,
@@ -6118,7 +6534,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6118
6534
  stickyIndices: stickyIndicesDeprecated,
6119
6535
  // TODOV3: Remove from v3 release
6120
6536
  style: styleProp,
6121
- suggestEstimatedItemSize,
6122
6537
  useWindowScroll = false,
6123
6538
  viewabilityConfig,
6124
6539
  viewabilityConfigCallbackPairs,
@@ -6146,13 +6561,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6146
6561
  const style = { ...StyleSheet.flatten(styleProp) };
6147
6562
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
6148
6563
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
6564
+ const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
6565
+ const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
6149
6566
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
6150
6567
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
6151
6568
  maintainVisibleContentPositionProp
6152
6569
  );
6153
6570
  const hasInitialScrollIndex = initialScrollIndexProp !== void 0 && initialScrollIndexProp !== null;
6154
6571
  const hasInitialScrollOffset = initialScrollOffsetProp !== void 0 && initialScrollOffsetProp !== null;
6155
- const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && hasInitialScrollOffset;
6572
+ const shouldInitializeHorizontalRTL = !initialScrollAtEnd && !hasInitialScrollIndex && !hasInitialScrollOffset && isHorizontalRTLProps({ horizontal, rtl });
6573
+ const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && (hasInitialScrollOffset || shouldInitializeHorizontalRTL);
6156
6574
  const usesBootstrapInitialScroll = initialScrollAtEnd || hasInitialScrollIndex;
6157
6575
  const initialScrollProp = initialScrollAtEnd ? {
6158
6576
  index: Math.max(0, dataProp.length - 1),
@@ -6259,7 +6677,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6259
6677
  startReachedSnapshotDataChangeEpoch: void 0,
6260
6678
  stickyContainerPool: /* @__PURE__ */ new Set(),
6261
6679
  stickyContainers: /* @__PURE__ */ new Map(),
6262
- timeoutSizeMessage: 0,
6263
6680
  timeouts: /* @__PURE__ */ new Set(),
6264
6681
  totalSize: 0,
6265
6682
  viewabilityConfigCallbackPairs: void 0
@@ -6269,6 +6686,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6269
6686
  internalState.reprocessCurrentScroll = () => updateScroll(ctx, internalState.scroll, true);
6270
6687
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
6271
6688
  set$(ctx, "extraData", extraData);
6689
+ if (estimatedHeaderSize !== void 0) {
6690
+ set$(ctx, "headerSize", estimatedHeaderSize);
6691
+ }
6272
6692
  }
6273
6693
  refState.current = ctx.state;
6274
6694
  }
@@ -6279,7 +6699,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6279
6699
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
6280
6700
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
6281
6701
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
6282
- if (didDataChangeLocal && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6702
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6283
6703
  clearPreservedInitialScrollTarget(state);
6284
6704
  }
6285
6705
  if (didDataChangeLocal) {
@@ -6328,13 +6748,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6328
6748
  positionComponentInternal,
6329
6749
  recycleItems: !!recycleItems,
6330
6750
  renderItem,
6751
+ rtl,
6331
6752
  snapToIndices,
6332
6753
  stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
6333
6754
  stickyIndicesSet: React3.useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
6334
6755
  stickyPositionComponentInternal,
6335
6756
  stylePaddingBottom: stylePaddingBottomState,
6757
+ stylePaddingLeft: stylePaddingLeftState,
6758
+ stylePaddingRight: stylePaddingRightState,
6336
6759
  stylePaddingTop: stylePaddingTopState,
6337
- suggestEstimatedItemSize: !!suggestEstimatedItemSize,
6338
6760
  useWindowScroll: useWindowScrollResolved
6339
6761
  };
6340
6762
  state.refScroller = refScroller;
@@ -6356,6 +6778,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6356
6778
  };
6357
6779
  if (isFirstLocal) {
6358
6780
  initializeStateVars(false);
6781
+ resetLayoutCachesForDataChange(state);
6359
6782
  updateItemPositions(
6360
6783
  ctx,
6361
6784
  /*dataChanged*/
@@ -6373,6 +6796,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6373
6796
  }, [usesBootstrapInitialScroll]);
6374
6797
  React3.useLayoutEffect(() => {
6375
6798
  initializeInitialScrollOnMount(ctx, {
6799
+ alwaysDispatchInitialScroll: shouldInitializeHorizontalRTL,
6376
6800
  dataLength: dataProp.length,
6377
6801
  hasFooterComponent: !!ListFooterComponent,
6378
6802
  initialContentOffset,