@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.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
  });
@@ -664,12 +799,6 @@ function toLayout(rect) {
664
799
  };
665
800
  }
666
801
 
667
- // src/platform/Platform.ts
668
- var Platform = {
669
- // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
670
- OS: "web"
671
- };
672
-
673
802
  // src/utils/hasActiveMVCPAnchorLock.ts
674
803
  function hasActiveMVCPAnchorLock(state) {
675
804
  const lock = state.mvcpAnchorLock;
@@ -693,6 +822,7 @@ function getContainerPositionStyle({
693
822
  columnWrapperStyle,
694
823
  horizontal,
695
824
  hasItemSeparator,
825
+ isHorizontalRTLList,
696
826
  numColumns,
697
827
  otherAxisPos,
698
828
  otherAxisSize
@@ -716,6 +846,7 @@ function getContainerPositionStyle({
716
846
  }
717
847
  return horizontal ? {
718
848
  boxSizing: paddingStyles ? "border-box" : void 0,
849
+ direction: isHorizontalRTLList && Platform.OS === "web" ? "ltr" : void 0,
719
850
  flexDirection: hasItemSeparator ? "row" : void 0,
720
851
  height: otherAxisSize,
721
852
  left: 0,
@@ -734,6 +865,7 @@ function getContainerPositionStyle({
734
865
  }
735
866
  var Container = typedMemo(function Container2({
736
867
  id,
868
+ itemKey,
737
869
  recycleItems,
738
870
  horizontal,
739
871
  getRenderedItem: getRenderedItem2,
@@ -743,13 +875,13 @@ var Container = typedMemo(function Container2({
743
875
  }) {
744
876
  const ctx = useStateContext();
745
877
  const { columnWrapperStyle, animatedScrollY } = ctx;
878
+ const isHorizontalRTLList = isHorizontalRTL(ctx.state);
746
879
  const positionComponentInternal = ctx.state.props.positionComponentInternal;
747
880
  const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
748
- const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
881
+ const [column = 0, span = 1, data, numColumns = 1, extraData, isSticky] = useArr$([
749
882
  `containerColumn${id}`,
750
883
  `containerSpan${id}`,
751
884
  `containerItemData${id}`,
752
- `containerItemKey${id}`,
753
885
  "numColumns",
754
886
  "extraData",
755
887
  `containerSticky${id}`
@@ -775,11 +907,20 @@ var Container = typedMemo(function Container2({
775
907
  columnWrapperStyle,
776
908
  hasItemSeparator: !!ItemSeparatorComponent,
777
909
  horizontal,
910
+ isHorizontalRTLList,
778
911
  numColumns,
779
912
  otherAxisPos,
780
913
  otherAxisSize
781
914
  }),
782
- [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns, ItemSeparatorComponent]
915
+ [
916
+ horizontal,
917
+ isHorizontalRTLList,
918
+ otherAxisPos,
919
+ otherAxisSize,
920
+ columnWrapperStyle,
921
+ numColumns,
922
+ ItemSeparatorComponent
923
+ ]
783
924
  );
784
925
  const renderedItemInfo = React3.useMemo(
785
926
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
@@ -867,6 +1008,39 @@ var Container = typedMemo(function Container2({
867
1008
  );
868
1009
  });
869
1010
 
1011
+ // src/components/ContainerSlot.tsx
1012
+ function ContainerSlotBase({
1013
+ id,
1014
+ horizontal,
1015
+ recycleItems,
1016
+ ItemSeparatorComponent,
1017
+ updateItemSize: updateItemSize2,
1018
+ getRenderedItem: getRenderedItem2,
1019
+ stickyHeaderConfig,
1020
+ ContainerComponent = Container
1021
+ }) {
1022
+ const [itemKey] = useArr$([`containerItemKey${id}`]);
1023
+ if (itemKey === void 0) {
1024
+ return null;
1025
+ }
1026
+ return /* @__PURE__ */ React3__namespace.createElement(
1027
+ ContainerComponent,
1028
+ {
1029
+ getRenderedItem: getRenderedItem2,
1030
+ horizontal,
1031
+ ItemSeparatorComponent,
1032
+ id,
1033
+ itemKey,
1034
+ recycleItems,
1035
+ stickyHeaderConfig,
1036
+ updateItemSize: updateItemSize2
1037
+ }
1038
+ );
1039
+ }
1040
+ var ContainerSlot = typedMemo(function ContainerSlot2(props) {
1041
+ return /* @__PURE__ */ React3__namespace.createElement(ContainerSlotBase, { ...props });
1042
+ });
1043
+
870
1044
  // src/utils/reordering.ts
871
1045
  var mapFn = (element) => {
872
1046
  const indexStr = element.getAttribute("data-index");
@@ -986,9 +1160,19 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
986
1160
  const ref = React3.useRef(null);
987
1161
  const ctx = useStateContext();
988
1162
  const columnWrapperStyle = ctx.columnWrapperStyle;
989
- const [otherAxisSize, totalSize] = useArr$(["otherAxisSize", "totalSize"]);
1163
+ const isHorizontalRTLList = isHorizontalRTL(ctx.state);
1164
+ const [otherAxisSize, readyToRender, totalSize] = useArr$(["otherAxisSize", "readyToRender", "totalSize"]);
990
1165
  useDOMOrder(ref);
991
- const style = horizontal ? { minHeight: otherAxisSize, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, position: "relative" };
1166
+ const style = horizontal ? {
1167
+ direction: isHorizontalRTLList ? "ltr" : void 0,
1168
+ minHeight: otherAxisSize,
1169
+ opacity: readyToRender ? 1 : 0,
1170
+ position: "relative",
1171
+ width: totalSize
1172
+ } : { height: totalSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative" };
1173
+ if (!readyToRender) {
1174
+ style.pointerEvents = "none";
1175
+ }
992
1176
  if (columnWrapperStyle && numColumns > 1) {
993
1177
  const { columnGap, rowGap, gap } = columnWrapperStyle;
994
1178
  const gapX = columnGap || gap || 0;
@@ -1016,12 +1200,12 @@ var Containers = typedMemo(function Containers2({
1016
1200
  getRenderedItem: getRenderedItem2,
1017
1201
  stickyHeaderConfig
1018
1202
  }) {
1019
- const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
1203
+ const [numContainersPooled, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
1020
1204
  const containers = [];
1021
- for (let i = 0; i < numContainers; i++) {
1205
+ for (let i = 0; i < numContainersPooled; i++) {
1022
1206
  containers.push(
1023
1207
  /* @__PURE__ */ React3__namespace.createElement(
1024
- Container,
1208
+ ContainerSlot,
1025
1209
  {
1026
1210
  getRenderedItem: getRenderedItem2,
1027
1211
  horizontal,
@@ -1093,6 +1277,8 @@ function useRafCoalescer(callback) {
1093
1277
 
1094
1278
  // src/components/webConstants.ts
1095
1279
  var LEGEND_LIST_CONTENT_CONTAINER_CLASS = "legend-list-content-container";
1280
+ var LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS = "legend-list-scrollbar-x-hidden";
1281
+ var LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS = "legend-list-scrollbar-y-hidden";
1096
1282
 
1097
1283
  // src/components/webScrollUtils.ts
1098
1284
  function getDocumentScrollerNode() {
@@ -1178,11 +1364,47 @@ function resolveWindowScrollTarget({ clampedOffset, horizontal, listPos, scroll
1178
1364
  }
1179
1365
 
1180
1366
  // src/components/ListComponentScrollView.tsx
1367
+ var SCROLLBAR_HIDDEN_STYLE_ID = "legend-list-scrollbar-axis-hidden-style";
1368
+ 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;}`;
1369
+ function ensureScrollbarHiddenStyle() {
1370
+ if (typeof document === "undefined" || document.getElementById(SCROLLBAR_HIDDEN_STYLE_ID)) {
1371
+ return;
1372
+ }
1373
+ const styleElement = document.createElement("style");
1374
+ styleElement.id = SCROLLBAR_HIDDEN_STYLE_ID;
1375
+ styleElement.textContent = SCROLLBAR_HIDDEN_STYLE;
1376
+ document.head.appendChild(styleElement);
1377
+ }
1181
1378
  function getContentInsetEndAdjustmentEnd2(ctx) {
1182
1379
  var _a3, _b;
1183
1380
  const adjustment = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.contentInsetEndAdjustment;
1184
1381
  return Math.max(0, adjustment != null ? adjustment : 0);
1185
1382
  }
1383
+ function getFiniteSnapOffsets(snapToOffsets) {
1384
+ if (!(snapToOffsets == null ? void 0 : snapToOffsets.length)) {
1385
+ return [];
1386
+ }
1387
+ const snapOffsets = [];
1388
+ const seen = /* @__PURE__ */ new Set();
1389
+ for (const offset of snapToOffsets) {
1390
+ if (Number.isFinite(offset) && !seen.has(offset)) {
1391
+ seen.add(offset);
1392
+ snapOffsets.push(offset);
1393
+ }
1394
+ }
1395
+ return snapOffsets;
1396
+ }
1397
+ function getSnapAnchorStyle(offset, horizontal) {
1398
+ return {
1399
+ height: horizontal ? "100%" : 1,
1400
+ left: horizontal ? offset : 0,
1401
+ pointerEvents: "none",
1402
+ position: "absolute",
1403
+ scrollSnapAlign: "start",
1404
+ top: horizontal ? 0 : offset,
1405
+ width: horizontal ? 1 : "100%"
1406
+ };
1407
+ }
1186
1408
  var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView2({
1187
1409
  children,
1188
1410
  style,
@@ -1200,7 +1422,7 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1200
1422
  onLayout,
1201
1423
  ...props
1202
1424
  }, ref) {
1203
- var _a3, _b, _c;
1425
+ var _a3, _b, _c, _d;
1204
1426
  const ctx = useStateContext();
1205
1427
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
1206
1428
  const scrollRef = React3.useRef(null);
@@ -1382,6 +1604,12 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1382
1604
  }
1383
1605
  };
1384
1606
  }, [isWindowScroll, onLayout]);
1607
+ const hiddenScrollIndicatorClassName = !isWindowScroll && (horizontal ? !showsHorizontalScrollIndicator && LEGEND_LIST_SCROLLBAR_X_HIDDEN_CLASS : !showsVerticalScrollIndicator && LEGEND_LIST_SCROLLBAR_Y_HIDDEN_CLASS);
1608
+ React3.useLayoutEffect(() => {
1609
+ if (hiddenScrollIndicatorClassName) {
1610
+ ensureScrollbarHiddenStyle();
1611
+ }
1612
+ }, [hiddenScrollIndicatorClassName]);
1385
1613
  const scrollViewStyle = {
1386
1614
  ...isWindowScroll ? {} : {
1387
1615
  overflow: "auto",
@@ -1409,11 +1637,59 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1409
1637
  contentInset: _contentInset,
1410
1638
  scrollEventThrottle: _scrollEventThrottle,
1411
1639
  ScrollComponent: _ScrollComponent,
1640
+ snapToOffsets,
1412
1641
  useWindowScroll: _useWindowScroll,
1642
+ className: scrollViewClassNameProp,
1413
1643
  ...webProps
1414
1644
  } = props;
1415
- 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));
1645
+ const snapOffsets = !isWindowScroll ? getFiniteSnapOffsets(snapToOffsets) : [];
1646
+ if (snapOffsets.length > 0) {
1647
+ scrollViewStyle.scrollSnapType = horizontal ? "x mandatory" : "y mandatory";
1648
+ contentStyle.position = (_d = contentStyle.position) != null ? _d : "relative";
1649
+ }
1650
+ const scrollViewClassName = hiddenScrollIndicatorClassName ? scrollViewClassNameProp ? `${scrollViewClassNameProp} ${hiddenScrollIndicatorClassName}` : hiddenScrollIndicatorClassName : scrollViewClassNameProp;
1651
+ if (IS_DEV) {
1652
+ if (/(?:^|\s)(?:[a-z0-9_-]+:)*gap(?:-[xy])?-(?:\[[^\]]+\]|[^\s]+)/.test(
1653
+ `${contentContainerClassName != null ? contentContainerClassName : ""} ${scrollViewClassNameProp != null ? scrollViewClassNameProp : ""}`
1654
+ )) {
1655
+ warnDevOnce(
1656
+ "className-gap",
1657
+ "className/contentContainerClassName gap classes are not supported in LegendList because it needs to use exact values internally. Use contentContainerStyle={{ gap: ... }} or columnWrapperStyle instead."
1658
+ );
1659
+ }
1660
+ }
1661
+ return /* @__PURE__ */ React3__namespace.createElement(
1662
+ "div",
1663
+ {
1664
+ className: scrollViewClassName,
1665
+ ref: scrollRef,
1666
+ ...webProps,
1667
+ style: scrollViewStyle
1668
+ },
1669
+ refreshControl,
1670
+ /* @__PURE__ */ React3__namespace.createElement("div", { className, ref: contentRef, style: contentStyle }, snapOffsets.map((offset) => /* @__PURE__ */ React3__namespace.createElement(
1671
+ "div",
1672
+ {
1673
+ "aria-hidden": true,
1674
+ "data-legend-list-snap-anchor": offset,
1675
+ key: `snap-${offset}`,
1676
+ style: getSnapAnchorStyle(offset, horizontal)
1677
+ }
1678
+ )), children, contentInsetEndAdjustmentSpacerStyle ? /* @__PURE__ */ React3__namespace.createElement("div", { "aria-hidden": true, style: contentInsetEndAdjustmentSpacerStyle }) : null)
1679
+ );
1416
1680
  });
1681
+
1682
+ // src/components/listComponentStyles.ts
1683
+ function getAutoOtherAxisStyle({
1684
+ horizontal,
1685
+ needsOtherAxisSize,
1686
+ otherAxisSize
1687
+ }) {
1688
+ if (!needsOtherAxisSize || !otherAxisSize || otherAxisSize <= 0) {
1689
+ return void 0;
1690
+ }
1691
+ return horizontal ? { height: otherAxisSize } : { width: otherAxisSize };
1692
+ }
1417
1693
  function useValueListener$(key, callback) {
1418
1694
  const ctx = useStateContext();
1419
1695
  React3.useLayoutEffect(() => {
@@ -1440,11 +1716,18 @@ function getScrollAdjustAxis(horizontal) {
1440
1716
  y: 1
1441
1717
  };
1442
1718
  }
1443
- function resolveScrollAdjustContentNode(el, contentNode) {
1444
- if ((contentNode == null ? void 0 : contentNode.isConnected) && contentNode.parentElement === el) {
1445
- return contentNode;
1719
+ function getScrollAdjustTarget(ctx, contentNode) {
1720
+ var _a3, _b, _c;
1721
+ const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1722
+ const scrollElement = (_c = (_b = scrollView == null ? void 0 : scrollView.getScrollableNode) == null ? void 0 : _b.call(scrollView)) != null ? _c : null;
1723
+ let resolvedContentNode = null;
1724
+ if (scrollElement) {
1725
+ resolvedContentNode = (contentNode == null ? void 0 : contentNode.isConnected) && contentNode.parentElement === scrollElement ? contentNode : scrollElement.querySelector(`:scope > .${LEGEND_LIST_CONTENT_CONTAINER_CLASS}`);
1446
1726
  }
1447
- return el.querySelector(`:scope > .${LEGEND_LIST_CONTENT_CONTAINER_CLASS}`);
1727
+ return scrollElement ? { contentNode: resolvedContentNode, scrollElement } : null;
1728
+ }
1729
+ function scrollAdjustBy(el, left, top) {
1730
+ el.scrollBy({ behavior: "auto", left, top });
1448
1731
  }
1449
1732
  function ScrollAdjust() {
1450
1733
  const ctx = useStateContext();
@@ -1453,43 +1736,43 @@ function ScrollAdjust() {
1453
1736
  const resetPaddingBaselineRef = React3__namespace.useRef(void 0);
1454
1737
  const contentNodeRef = React3__namespace.useRef(null);
1455
1738
  const callback = React3__namespace.useCallback(() => {
1456
- var _a3, _b;
1739
+ var _a3;
1457
1740
  const scrollAdjust = peek$(ctx, "scrollAdjust");
1458
1741
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
1459
1742
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
1460
- const scrollView = (_a3 = ctx.state) == null ? void 0 : _a3.refScroller.current;
1461
- if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1462
- const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1463
- if (scrollDelta !== 0) {
1464
- const axis = getScrollAdjustAxis(!!ctx.state.props.horizontal);
1465
- const prevScroll = scrollView.getCurrentScrollOffset();
1466
- const el = scrollView.getScrollableNode();
1467
- const contentNode = resolveScrollAdjustContentNode(el, contentNodeRef.current);
1743
+ const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1744
+ if (scrollDelta !== 0) {
1745
+ const target = getScrollAdjustTarget(ctx, contentNodeRef.current);
1746
+ if (target) {
1747
+ const horizontal = !!ctx.state.props.horizontal;
1748
+ const axis = getScrollAdjustAxis(horizontal);
1749
+ const { contentNode, scrollElement: el } = target;
1750
+ const scrollBy = () => scrollAdjustBy(el, axis.x * scrollDelta, axis.y * scrollDelta);
1468
1751
  contentNodeRef.current = contentNode;
1469
- const scrollBy = () => scrollView.scrollBy(axis.x * scrollDelta, axis.y * scrollDelta);
1470
- if (!contentNode) {
1471
- scrollBy();
1472
- lastScrollOffsetRef.current = scrollOffset;
1473
- return;
1474
- }
1475
- const totalSize = contentNode[axis.contentSizeKey];
1476
- const viewportSize = el[axis.viewportSizeKey];
1477
- const nextScroll = prevScroll + scrollDelta;
1478
- if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize) {
1479
- const previousPaddingEnd = (_b = resetPaddingBaselineRef.current) != null ? _b : contentNode.style[axis.paddingEndProp];
1480
- resetPaddingBaselineRef.current = previousPaddingEnd;
1481
- const pad = (nextScroll + viewportSize - totalSize) * 2;
1482
- contentNode.style[axis.paddingEndProp] = `${pad}px`;
1483
- void contentNode.offsetHeight;
1484
- scrollBy();
1485
- if (resetPaddingRafRef.current !== void 0) {
1486
- cancelAnimationFrame(resetPaddingRafRef.current);
1752
+ if (contentNode) {
1753
+ const prevScroll = horizontal ? el.scrollLeft : el.scrollTop;
1754
+ const totalSize = contentNode[axis.contentSizeKey];
1755
+ const viewportSize = el[axis.viewportSizeKey];
1756
+ const nextScroll = prevScroll + scrollDelta;
1757
+ const needsTemporaryPadding = scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize;
1758
+ if (needsTemporaryPadding) {
1759
+ const previousPaddingEnd = (_a3 = resetPaddingBaselineRef.current) != null ? _a3 : contentNode.style[axis.paddingEndProp];
1760
+ resetPaddingBaselineRef.current = previousPaddingEnd;
1761
+ const pad = (nextScroll + viewportSize - totalSize) * 2;
1762
+ contentNode.style[axis.paddingEndProp] = `${pad}px`;
1763
+ void contentNode.offsetHeight;
1764
+ scrollBy();
1765
+ if (resetPaddingRafRef.current !== void 0) {
1766
+ cancelAnimationFrame(resetPaddingRafRef.current);
1767
+ }
1768
+ resetPaddingRafRef.current = requestAnimationFrame(() => {
1769
+ resetPaddingRafRef.current = void 0;
1770
+ resetPaddingBaselineRef.current = void 0;
1771
+ contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1772
+ });
1773
+ } else {
1774
+ scrollBy();
1487
1775
  }
1488
- resetPaddingRafRef.current = requestAnimationFrame(() => {
1489
- resetPaddingRafRef.current = void 0;
1490
- resetPaddingBaselineRef.current = void 0;
1491
- contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
1492
- });
1493
1776
  } else {
1494
1777
  scrollBy();
1495
1778
  }
@@ -1501,10 +1784,10 @@ function ScrollAdjust() {
1501
1784
  useValueListener$("scrollAdjustUserOffset", callback);
1502
1785
  return null;
1503
1786
  }
1504
- function SnapWrapper({ ScrollComponent, ...props }) {
1787
+ var SnapWrapper = React3__namespace.forwardRef(function SnapWrapperInner({ ScrollComponent, ...props }, ref) {
1505
1788
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
1506
- return /* @__PURE__ */ React3__namespace.createElement(ScrollComponent, { ...props, snapToOffsets });
1507
- }
1789
+ return /* @__PURE__ */ React3__namespace.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
1790
+ });
1508
1791
  function WebAnchoredEndSpace({ horizontal }) {
1509
1792
  const ctx = useStateContext();
1510
1793
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
@@ -1521,15 +1804,6 @@ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1521
1804
  useOnLayoutSync({ onLayoutChange, ref });
1522
1805
  return /* @__PURE__ */ React3__namespace.createElement("div", { ...rest, ref }, children);
1523
1806
  };
1524
- var getComponent = (Component) => {
1525
- if (React3__namespace.isValidElement(Component)) {
1526
- return Component;
1527
- }
1528
- if (Component) {
1529
- return /* @__PURE__ */ React3__namespace.createElement(Component, null);
1530
- }
1531
- return null;
1532
- };
1533
1807
 
1534
1808
  // src/components/ListComponent.tsx
1535
1809
  var ListComponent = typedMemo(function ListComponent2({
@@ -1562,6 +1836,12 @@ var ListComponent = typedMemo(function ListComponent2({
1562
1836
  }) {
1563
1837
  const ctx = useStateContext();
1564
1838
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1839
+ const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
1840
+ const autoOtherAxisStyle = getAutoOtherAxisStyle({
1841
+ horizontal,
1842
+ needsOtherAxisSize: ctx.state.needsOtherAxisSize,
1843
+ otherAxisSize
1844
+ });
1565
1845
  const ScrollComponent = React3.useMemo(() => {
1566
1846
  if (!renderScrollComponent) {
1567
1847
  return ListComponentScrollView;
@@ -1600,10 +1880,10 @@ var ListComponent = typedMemo(function ListComponent2({
1600
1880
  ...rest,
1601
1881
  ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1602
1882
  contentContainerStyle: [
1603
- contentContainerStyle,
1604
1883
  horizontal ? {
1605
1884
  height: "100%"
1606
- } : {}
1885
+ } : {},
1886
+ contentContainerStyle
1607
1887
  ],
1608
1888
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1609
1889
  horizontal,
@@ -1612,7 +1892,7 @@ var ListComponent = typedMemo(function ListComponent2({
1612
1892
  onScroll: onScroll2,
1613
1893
  ref: refScrollView,
1614
1894
  ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1615
- style
1895
+ style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
1616
1896
  },
1617
1897
  /* @__PURE__ */ React3__namespace.createElement(ScrollAdjust, null),
1618
1898
  ListHeaderComponent && /* @__PURE__ */ React3__namespace.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
@@ -1800,10 +2080,9 @@ var initialScrollWatchdog = {
1800
2080
  clear(state) {
1801
2081
  initialScrollWatchdog.set(state, void 0);
1802
2082
  },
1803
- didObserveProgress(newScroll, watchdog) {
1804
- const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
2083
+ didReachTarget(newScroll, watchdog) {
1805
2084
  const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
1806
- return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET || nextDistance + INITIAL_SCROLL_MIN_TARGET_OFFSET < previousDistance;
2085
+ return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET;
1807
2086
  },
1808
2087
  get(state) {
1809
2088
  var _a3, _b;
@@ -1828,19 +2107,19 @@ var initialScrollWatchdog = {
1828
2107
  }
1829
2108
  };
1830
2109
  function setInitialScrollSession(state, options = {}) {
1831
- var _a3, _b, _c;
2110
+ var _a3, _b, _c, _d;
1832
2111
  const existingSession = state.initialScrollSession;
1833
2112
  const kind = (_a3 = options.kind) != null ? _a3 : existingSession == null ? void 0 : existingSession.kind;
1834
2113
  const completion = existingSession == null ? void 0 : existingSession.completion;
1835
- const hasBootstrapOverride = Object.hasOwn(options, "bootstrap");
1836
- const bootstrap = kind === "bootstrap" ? hasBootstrapOverride ? options.bootstrap : (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0 : void 0;
2114
+ const existingBootstrap = (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0;
2115
+ const bootstrap = kind === "bootstrap" ? options.bootstrap === null ? void 0 : (_b = options.bootstrap) != null ? _b : existingBootstrap : void 0;
1837
2116
  if (!kind) {
1838
2117
  return clearInitialScrollSession(state);
1839
2118
  }
1840
2119
  if (!state.initialScroll && !bootstrap && !hasInitialScrollSessionCompletion(completion)) {
1841
2120
  return clearInitialScrollSession(state);
1842
2121
  }
1843
- const previousDataLength = (_c = (_b = options.previousDataLength) != null ? _b : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _c : 0;
2122
+ const previousDataLength = (_d = (_c = options.previousDataLength) != null ? _c : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _d : 0;
1844
2123
  state.initialScrollSession = createInitialScrollSession({
1845
2124
  bootstrap,
1846
2125
  completion,
@@ -2330,7 +2609,8 @@ function doScrollTo(ctx, params) {
2330
2609
  }
2331
2610
  const isAnimated = !!animated;
2332
2611
  const isHorizontal = !!horizontal;
2333
- const left = isHorizontal ? offset : 0;
2612
+ const contentSize = isHorizontal ? getContentSize(ctx) : void 0;
2613
+ const left = isHorizontal ? toNativeHorizontalOffset(state, offset, contentSize) : 0;
2334
2614
  const top = isHorizontal ? 0 : offset;
2335
2615
  scroller.scrollTo({ animated: isAnimated, x: left, y: top });
2336
2616
  if (isAnimated) {
@@ -2592,7 +2872,7 @@ function advanceMeasuredInitialScroll(ctx, options) {
2592
2872
  const activeInitialTargetOffset = scrollingTo ? (_a3 = scrollingTo.targetOffset) != null ? _a3 : scrollingTo.offset : void 0;
2593
2873
  const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - resolvedOffset) > 1;
2594
2874
  const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - resolvedOffset) > 1;
2595
- const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - activeInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - activeInitialTargetOffset) <= 1;
2875
+ const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - resolvedOffset) <= 1 && Math.abs(state.scrollPending - resolvedOffset) <= 1;
2596
2876
  if (!(options == null ? void 0 : options.forceScroll) && !didOffsetChange && isInitialScrollInProgress && !didActiveInitialTargetChange) {
2597
2877
  return false;
2598
2878
  }
@@ -2664,6 +2944,30 @@ function checkAllSizesKnown(state, indices) {
2664
2944
  });
2665
2945
  }
2666
2946
 
2947
+ // src/utils/requestAdjust.ts
2948
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2949
+ const state = ctx.state;
2950
+ if (Math.abs(positionDiff) > 0.1) {
2951
+ const doit = () => {
2952
+ {
2953
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
2954
+ if (state.adjustingFromInitialMount) {
2955
+ state.adjustingFromInitialMount--;
2956
+ }
2957
+ }
2958
+ };
2959
+ state.scroll += positionDiff;
2960
+ state.scrollForNextCalculateItemsInView = void 0;
2961
+ const readyToRender = peek$(ctx, "readyToRender");
2962
+ if (readyToRender) {
2963
+ doit();
2964
+ } else {
2965
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2966
+ requestAnimationFrame(doit);
2967
+ }
2968
+ }
2969
+ }
2970
+
2667
2971
  // src/core/bootstrapInitialScroll.ts
2668
2972
  var DEFAULT_BOOTSTRAP_REVEAL_EPSILON = 1;
2669
2973
  var DEFAULT_BOOTSTRAP_REVEAL_MAX_FRAMES = 8;
@@ -2757,7 +3061,7 @@ function clearBootstrapInitialScrollSession(state) {
2757
3061
  bootstrapInitialScroll.frameHandle = void 0;
2758
3062
  }
2759
3063
  setInitialScrollSession(state, {
2760
- bootstrap: void 0,
3064
+ bootstrap: null,
2761
3065
  kind: (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind
2762
3066
  });
2763
3067
  }
@@ -2913,15 +3217,18 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2913
3217
  return;
2914
3218
  }
2915
3219
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2916
- if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2917
- clearPendingInitialScrollFooterLayout(ctx, {
2918
- dataLength: state.props.data.length,
2919
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2920
- target: initialScroll
2921
- });
2922
- return;
3220
+ const shouldKeepEndTargetAlive = isRetargetableBottomAlignedInitialScrollTarget(initialScroll) && peek$(ctx, "isAtEnd");
3221
+ if (!shouldKeepEndTargetAlive) {
3222
+ if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
3223
+ clearPendingInitialScrollFooterLayout(ctx, {
3224
+ dataLength: state.props.data.length,
3225
+ stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
3226
+ target: initialScroll
3227
+ });
3228
+ } else {
3229
+ clearFinishedViewportRetargetableInitialScroll(state);
3230
+ }
2923
3231
  }
2924
- clearFinishedViewportRetargetableInitialScroll(state);
2925
3232
  }
2926
3233
  }
2927
3234
  function startBootstrapInitialScrollOnMount(ctx, options) {
@@ -2960,7 +3267,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2960
3267
  }
2961
3268
  const shouldResetDidFinish = !!(state.didFinishInitialScroll && previousDataLength === 0 && dataLength > 0 && initialScroll.index !== void 0);
2962
3269
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2963
- const shouldClearFinishedResizePreservation = didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
3270
+ const shouldClearFinishedResizePreservation = !initialScrollAtEnd && didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
2964
3271
  if (shouldClearFinishedResizePreservation) {
2965
3272
  clearPreservedInitialScrollTarget(state);
2966
3273
  return;
@@ -3063,27 +3370,46 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
3063
3370
  }
3064
3371
  }
3065
3372
  function handleBootstrapInitialScrollLayoutChange(ctx) {
3373
+ var _a3, _b, _c, _d;
3066
3374
  const state = ctx.state;
3067
3375
  const initialScroll = state.initialScroll;
3068
- if (isOffsetInitialScrollSession(state) || state.props.data.length === 0 || !initialScroll) {
3069
- return;
3070
- }
3071
3376
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
3072
- if (!bootstrapInitialScroll && initialScroll.viewPosition !== 1) {
3073
- return;
3074
- }
3075
- const didFinishInitialScroll = state.didFinishInitialScroll;
3076
- if (didFinishInitialScroll) {
3077
- setInitialScrollTarget(state, initialScroll, {
3078
- resetDidFinish: true
3079
- });
3080
- state.clearPreservedInitialScrollOnNextFinish = true;
3377
+ if (initialScroll && state.props.data.length > 0 && !isOffsetInitialScrollSession(state) && (bootstrapInitialScroll || initialScroll.viewPosition === 1)) {
3378
+ const resolvedOffset = resolveInitialScrollOffset(ctx, initialScroll);
3379
+ const scrollingTo = ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) ? state.scrollingTo : void 0;
3380
+ if (!bootstrapInitialScroll && (scrollingTo || state.didFinishInitialScroll)) {
3381
+ const currentOffset = scrollingTo ? (_b = scrollingTo.targetOffset) != null ? _b : scrollingTo.offset : getObservedBootstrapInitialScrollOffset(state);
3382
+ const offsetDiff = resolvedOffset - currentOffset;
3383
+ if (Math.abs(offsetDiff) > DEFAULT_BOOTSTRAP_REVEAL_EPSILON) {
3384
+ if (scrollingTo) {
3385
+ const existingWatchdog = initialScrollWatchdog.get(state);
3386
+ scrollingTo.offset = resolvedOffset;
3387
+ scrollingTo.targetOffset = resolvedOffset;
3388
+ state.initialScroll = {
3389
+ ...initialScroll,
3390
+ contentOffset: resolvedOffset
3391
+ };
3392
+ state.hasScrolled = false;
3393
+ initialScrollWatchdog.set(state, {
3394
+ startScroll: (_c = existingWatchdog == null ? void 0 : existingWatchdog.startScroll) != null ? _c : state.scroll,
3395
+ targetOffset: resolvedOffset
3396
+ });
3397
+ }
3398
+ requestAdjust(ctx, offsetDiff);
3399
+ if (state.didFinishInitialScroll) {
3400
+ (_d = state.triggerCalculateItemsInView) == null ? void 0 : _d.call(state, { forceFullItemPositions: true });
3401
+ }
3402
+ }
3403
+ if (state.didFinishInitialScroll) {
3404
+ clearFinishedViewportRetargetableInitialScroll(state);
3405
+ }
3406
+ } else {
3407
+ rearmBootstrapInitialScroll(ctx, {
3408
+ scroll: resolvedOffset,
3409
+ targetIndexSeed: initialScroll.index
3410
+ });
3411
+ }
3081
3412
  }
3082
- rearmBootstrapInitialScroll(ctx, {
3083
- scroll: resolveInitialScrollOffset(ctx, initialScroll),
3084
- seedContentOffset: didFinishInitialScroll && !bootstrapInitialScroll ? getObservedBootstrapInitialScrollOffset(state) : void 0,
3085
- targetIndexSeed: initialScroll.index
3086
- });
3087
3413
  }
3088
3414
  function evaluateBootstrapInitialScroll(ctx) {
3089
3415
  var _a3, _b;
@@ -3290,7 +3616,7 @@ function checkFinishedScrollFallback(ctx) {
3290
3616
  state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
3291
3617
  };
3292
3618
  const checkHasScrolled = () => {
3293
- var _c;
3619
+ var _c, _d;
3294
3620
  state.timeoutCheckFinishedScrollFallback = void 0;
3295
3621
  const isStillScrollingTo = state.scrollingTo;
3296
3622
  if (isStillScrollingTo) {
@@ -3303,11 +3629,13 @@ function checkFinishedScrollFallback(ctx) {
3303
3629
  isStillScrollingTo
3304
3630
  );
3305
3631
  const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
3306
- const canFinishAfterSilentNativeDispatch = silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
3307
- if (shouldFinishZeroTarget || state.hasScrolled || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3632
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
3633
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
3634
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
3635
+ if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3308
3636
  finishScrollTo(ctx);
3309
- } else if (isNativeInitialPending && numChecks <= maxChecks) {
3310
- const targetOffset = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : state.scrollPending;
3637
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
3638
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
3311
3639
  scrollToFallbackOffset(ctx, targetOffset);
3312
3640
  scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3313
3641
  } else {
@@ -3343,7 +3671,14 @@ function handleInitialScrollLayoutReady(ctx) {
3343
3671
  }
3344
3672
  function initializeInitialScrollOnMount(ctx, options) {
3345
3673
  var _a3, _b;
3346
- const { dataLength, hasFooterComponent, initialContentOffset, initialScrollAtEnd, useBootstrapInitialScroll } = options;
3674
+ const {
3675
+ alwaysDispatchInitialScroll,
3676
+ dataLength,
3677
+ hasFooterComponent,
3678
+ initialContentOffset,
3679
+ initialScrollAtEnd,
3680
+ useBootstrapInitialScroll
3681
+ } = options;
3347
3682
  const state = ctx.state;
3348
3683
  const initialScroll = state.initialScroll;
3349
3684
  const resolvedInitialContentOffset = initialContentOffset != null ? initialContentOffset : 0;
@@ -3363,7 +3698,7 @@ function initializeInitialScrollOnMount(ctx, options) {
3363
3698
  return;
3364
3699
  }
3365
3700
  const hasPendingDataDependentInitialScroll = !!initialScroll && dataLength === 0 && !(resolvedInitialContentOffset === 0 && !initialScrollAtEnd);
3366
- if (!resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
3701
+ if (!alwaysDispatchInitialScroll && !resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
3367
3702
  if (initialScroll && !initialScrollAtEnd) {
3368
3703
  finishInitialScroll(ctx, {
3369
3704
  resolvedOffset: resolvedInitialContentOffset
@@ -3402,30 +3737,6 @@ function handleInitialScrollDataChange(ctx, options) {
3402
3737
  advanceCurrentInitialScrollSession(ctx);
3403
3738
  }
3404
3739
 
3405
- // src/utils/requestAdjust.ts
3406
- function requestAdjust(ctx, positionDiff, dataChanged) {
3407
- const state = ctx.state;
3408
- if (Math.abs(positionDiff) > 0.1) {
3409
- const doit = () => {
3410
- {
3411
- state.scrollAdjustHandler.requestAdjust(positionDiff);
3412
- if (state.adjustingFromInitialMount) {
3413
- state.adjustingFromInitialMount--;
3414
- }
3415
- }
3416
- };
3417
- state.scroll += positionDiff;
3418
- state.scrollForNextCalculateItemsInView = void 0;
3419
- const readyToRender = peek$(ctx, "readyToRender");
3420
- if (readyToRender) {
3421
- doit();
3422
- } else {
3423
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
3424
- requestAnimationFrame(doit);
3425
- }
3426
- }
3427
- }
3428
-
3429
3740
  // src/core/mvcp.ts
3430
3741
  var MVCP_POSITION_EPSILON = 0.1;
3431
3742
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -3699,15 +4010,27 @@ function prepareMVCP(ctx, dataChanged) {
3699
4010
  return;
3700
4011
  }
3701
4012
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
3702
- requestAdjust(ctx, positionDiff);
4013
+ const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
4014
+ if (!shouldSkipAdjustForMaintainedEnd) {
4015
+ requestAdjust(ctx, positionDiff);
4016
+ }
3703
4017
  }
3704
4018
  };
3705
4019
  }
3706
4020
  }
3707
4021
 
4022
+ // src/core/resetLayoutCachesForDataChange.ts
4023
+ function resetLayoutCachesForDataChange(state) {
4024
+ state.indexByKey.clear();
4025
+ state.idCache.length = 0;
4026
+ state.positions.length = 0;
4027
+ state.columns.length = 0;
4028
+ state.columnSpans.length = 0;
4029
+ }
4030
+
3708
4031
  // src/core/syncMountedContainer.ts
3709
4032
  function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3710
- var _a3, _b, _c, _d, _e, _f, _g, _h;
4033
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
3711
4034
  const state = ctx.state;
3712
4035
  const {
3713
4036
  columns,
@@ -3719,7 +4042,8 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3719
4042
  if (item === void 0) {
3720
4043
  return { didChangePosition: false, didRefreshData: false };
3721
4044
  }
3722
- const updateLayout = (_a3 = options == null ? void 0 : options.updateLayout) != null ? _a3 : true;
4045
+ const itemKey = (_a3 = state.idCache[itemIndex]) != null ? _a3 : getId(state, itemIndex);
4046
+ const updateLayout = (_b = options == null ? void 0 : options.updateLayout) != null ? _b : true;
3723
4047
  let didChangePosition = false;
3724
4048
  let didRefreshData = false;
3725
4049
  if (updateLayout) {
@@ -3728,7 +4052,9 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3728
4052
  set$(ctx, `containerPosition${containerIndex}`, POSITION_OUT_OF_VIEW);
3729
4053
  return { didChangePosition: false, didRefreshData: false };
3730
4054
  }
3731
- const position = (positionValue || 0) - ((_b = options == null ? void 0 : options.scrollAdjustPending) != null ? _b : 0);
4055
+ const logicalPosition = (positionValue || 0) - ((_c = options == null ? void 0 : options.scrollAdjustPending) != null ? _c : 0);
4056
+ const itemSize = (_d = state.sizes.get(itemKey)) != null ? _d : getItemSize(ctx, itemKey, itemIndex, item);
4057
+ const position = toPhysicalHorizontalItemPosition(state, logicalPosition, itemSize, peek$(ctx, "totalSize"));
3732
4058
  const column = columns[itemIndex] || 1;
3733
4059
  const span = columnSpans[itemIndex] || 1;
3734
4060
  const prevPos = peek$(ctx, `containerPosition${containerIndex}`);
@@ -3747,15 +4073,15 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3747
4073
  }
3748
4074
  const prevData = peek$(ctx, `containerItemData${containerIndex}`);
3749
4075
  if (prevData !== item) {
3750
- 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;
3751
- const cachedComparison = (_e = pendingDataComparison == null ? void 0 : pendingDataComparison.byIndex[itemIndex]) != null ? _e : 0;
4076
+ 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;
4077
+ const cachedComparison = (_g = pendingDataComparison == null ? void 0 : pendingDataComparison.byIndex[itemIndex]) != null ? _g : 0;
3752
4078
  if (cachedComparison === 2) {
3753
4079
  set$(ctx, `containerItemData${containerIndex}`, item);
3754
4080
  didRefreshData = true;
3755
4081
  } else if (cachedComparison !== 1) {
3756
- const itemKey = (_g = (_f = peek$(ctx, `containerItemKey${containerIndex}`)) != null ? _f : state.idCache[itemIndex]) != null ? _g : getId(state, itemIndex);
4082
+ const nextItemKey = (_h = peek$(ctx, `containerItemKey${containerIndex}`)) != null ? _h : itemKey;
3757
4083
  const prevKey = keyExtractor == null ? void 0 : keyExtractor(prevData, itemIndex);
3758
- if (prevData === void 0 || !keyExtractor || prevKey !== itemKey) {
4084
+ if (prevData === void 0 || !keyExtractor || prevKey !== nextItemKey) {
3759
4085
  set$(ctx, `containerItemData${containerIndex}`, item);
3760
4086
  didRefreshData = true;
3761
4087
  } else if (!itemsAreEqual) {
@@ -3772,7 +4098,7 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3772
4098
  };
3773
4099
  }
3774
4100
  }
3775
- if ((_h = state.pendingDataComparison) == null ? void 0 : _h.byIndex) {
4101
+ if ((_i = state.pendingDataComparison) == null ? void 0 : _i.byIndex) {
3776
4102
  state.pendingDataComparison.byIndex[itemIndex] = isEqual ? 1 : 2;
3777
4103
  }
3778
4104
  if (!isEqual) {
@@ -3937,11 +4263,13 @@ function updateSnapToOffsets(ctx) {
3937
4263
  const {
3938
4264
  props: { snapToIndices }
3939
4265
  } = state;
4266
+ const contentSize = state.props.horizontal ? getContentSize(ctx) : void 0;
3940
4267
  const snapToOffsets = Array(snapToIndices.length);
3941
4268
  for (let i = 0; i < snapToIndices.length; i++) {
3942
4269
  const idx = snapToIndices[i];
3943
4270
  getId(state, idx);
3944
- snapToOffsets[i] = state.positions[idx];
4271
+ const logicalOffset = state.positions[idx];
4272
+ snapToOffsets[i] = toNativeHorizontalOffset(state, logicalOffset, contentSize);
3945
4273
  }
3946
4274
  set$(ctx, "snapToOffsets", snapToOffsets);
3947
4275
  }
@@ -4318,6 +4646,30 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
4318
4646
  var unstableBatchedUpdates = ReactDOM__namespace.unstable_batchedUpdates;
4319
4647
  var batchedUpdates = typeof unstableBatchedUpdates === "function" ? unstableBatchedUpdates : (fn) => fn();
4320
4648
 
4649
+ // src/utils/containerPool.ts
4650
+ var MIN_INITIAL_CONTAINER_POOL_SIZE = 32;
4651
+ var MAX_INITIAL_SPARE_CONTAINERS = 64;
4652
+ function getInitialContainerPoolSize(dataLength, numContainers, initialContainerPoolRatio) {
4653
+ if (dataLength <= 0 || numContainers <= 0) {
4654
+ return 0;
4655
+ }
4656
+ const ratioPoolSize = Math.ceil(numContainers * initialContainerPoolRatio);
4657
+ const cappedSparePoolSize = numContainers + MAX_INITIAL_SPARE_CONTAINERS;
4658
+ const targetPoolSize = Math.max(
4659
+ numContainers,
4660
+ Math.min(ratioPoolSize, cappedSparePoolSize),
4661
+ Math.min(dataLength, MIN_INITIAL_CONTAINER_POOL_SIZE)
4662
+ );
4663
+ const maxUsefulPoolSize = Math.max(dataLength, numContainers);
4664
+ return Math.min(maxUsefulPoolSize, targetPoolSize);
4665
+ }
4666
+ function getExpandedContainerPoolSize(dataLength, numContainers) {
4667
+ if (dataLength <= 0 || numContainers <= 0) {
4668
+ return 0;
4669
+ }
4670
+ return Math.min(Math.max(dataLength, numContainers), Math.max(numContainers, Math.ceil(numContainers * 1.5)));
4671
+ }
4672
+
4321
4673
  // src/utils/findAvailableContainers.ts
4322
4674
  function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers, protectedKeys) {
4323
4675
  const numContainers = peek$(ctx, "numContainers");
@@ -4523,10 +4875,9 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
4523
4875
  function calculateItemsInView(ctx, params = {}) {
4524
4876
  const state = ctx.state;
4525
4877
  batchedUpdates(() => {
4526
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
4878
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
4527
4879
  const {
4528
4880
  columns,
4529
- columnSpans,
4530
4881
  containerItemKeys,
4531
4882
  enableScrollForNextCalculateItemsInView,
4532
4883
  idCache,
@@ -4570,18 +4921,38 @@ function calculateItemsInView(ctx, params = {}) {
4570
4921
  // current initial-scroll target instead of transient native adjustments.
4571
4922
  resolveInitialScrollOffset(ctx, initialScroll)
4572
4923
  ) : state.scroll;
4573
- const scrollAdjustPending = (_c = peek$(ctx, "scrollAdjustPending")) != null ? _c : 0;
4574
- const scrollAdjustPad = scrollAdjustPending - topPad;
4575
- let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
4576
- if (scroll + scrollLength > totalSize) {
4577
- scroll = Math.max(0, totalSize - scrollLength);
4578
- }
4924
+ let scrollAdjustPending = 0;
4925
+ let scrollAdjustPad = 0;
4926
+ let scroll = 0;
4927
+ let scrollTopBuffered = 0;
4928
+ let scrollBottom = 0;
4929
+ let scrollBottomBuffered = 0;
4930
+ let nativeScrollState = scrollState;
4931
+ const updateScroll2 = (nextScrollState) => {
4932
+ var _a4;
4933
+ nativeScrollState = nextScrollState;
4934
+ scrollAdjustPending = (_a4 = peek$(ctx, "scrollAdjustPending")) != null ? _a4 : 0;
4935
+ scrollAdjustPad = scrollAdjustPending - topPad;
4936
+ scroll = Math.round(nextScrollState + scrollExtra + scrollAdjustPad);
4937
+ if (scroll + scrollLength > totalSize) {
4938
+ scroll = Math.max(0, totalSize - scrollLength);
4939
+ }
4940
+ };
4941
+ updateScroll2(scrollState);
4579
4942
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
4580
4943
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
4581
4944
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
4945
+ const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
4582
4946
  if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
4583
4947
  set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
4584
4948
  }
4949
+ const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyIndicesArr.length > 0 && stickyIndexDidChange;
4950
+ const finishCalculateItemsInView = shouldNotifyStickyHeaderChange ? () => {
4951
+ const item = data[nextActiveStickyIndex];
4952
+ if (item !== void 0) {
4953
+ onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4954
+ }
4955
+ } : void 0;
4585
4956
  let scrollBufferTop = drawDistance;
4586
4957
  let scrollBufferBottom = drawDistance;
4587
4958
  if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
@@ -4591,28 +4962,30 @@ function calculateItemsInView(ctx, params = {}) {
4591
4962
  scrollBufferTop = drawDistance * 1.5;
4592
4963
  scrollBufferBottom = drawDistance * 0.5;
4593
4964
  }
4594
- const scrollTopBuffered = scroll - scrollBufferTop;
4595
- const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
4596
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4965
+ const updateScrollRange = () => {
4966
+ const scrollStart = Math.max(0, scroll);
4967
+ const overscrollBeforeContent = Math.max(0, -nativeScrollState);
4968
+ scrollTopBuffered = scrollStart - scrollBufferTop;
4969
+ scrollBottom = Math.max(scrollStart, scroll + scrollLength + overscrollBeforeContent);
4970
+ scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4971
+ };
4972
+ updateScrollRange();
4597
4973
  if (!suppressInitialScrollSideEffects && !dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
4598
4974
  const { top, bottom } = scrollForNextCalculateItemsInView;
4599
4975
  if (top === null && bottom === null) {
4600
4976
  state.scrollForNextCalculateItemsInView = void 0;
4601
4977
  } else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
4602
4978
  if (!isInMVCPActiveMode(state)) {
4979
+ finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4603
4980
  return;
4604
4981
  }
4605
4982
  }
4606
4983
  }
4607
4984
  const checkMVCP = doMVCP && !suppressInitialScrollSideEffects ? prepareMVCP(ctx, dataChanged) : void 0;
4608
4985
  if (dataChanged) {
4609
- indexByKey.clear();
4610
- idCache.length = 0;
4611
- positions.length = 0;
4612
- columns.length = 0;
4613
- columnSpans.length = 0;
4986
+ resetLayoutCachesForDataChange(state);
4614
4987
  }
4615
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_d = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _d : 0;
4988
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4616
4989
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4617
4990
  updateItemPositions(ctx, dataChanged, {
4618
4991
  doMVCP,
@@ -4637,21 +5010,25 @@ function calculateItemsInView(ctx, params = {}) {
4637
5010
  }
4638
5011
  }
4639
5012
  const scrollBeforeMVCP = state.scroll;
4640
- const scrollAdjustPendingBeforeMVCP = (_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0;
5013
+ const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
4641
5014
  checkMVCP == null ? void 0 : checkMVCP();
4642
- const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0) !== scrollAdjustPendingBeforeMVCP);
5015
+ const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0) !== scrollAdjustPendingBeforeMVCP);
5016
+ if (didMVCPAdjustScroll && initialScroll) {
5017
+ updateScroll2(state.scroll);
5018
+ updateScrollRange();
5019
+ }
4643
5020
  let startNoBuffer = null;
4644
5021
  let startBuffered = null;
4645
5022
  let startBufferedId = null;
4646
5023
  let endNoBuffer = null;
4647
5024
  let endBuffered = null;
4648
- let loopStart = (_g = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _g : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
5025
+ let loopStart = (_f = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _f : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4649
5026
  for (let i = loopStart; i >= 0; i--) {
4650
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
5027
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
4651
5028
  const top = positions[i];
4652
- const size = (_i = sizes.get(id)) != null ? _i : getItemSize(ctx, id, i, data[i]);
5029
+ const size = (_h = sizes.get(id)) != null ? _h : getItemSize(ctx, id, i, data[i]);
4653
5030
  const bottom = top + size;
4654
- if (bottom > scroll - scrollBufferTop) {
5031
+ if (bottom > scrollTopBuffered) {
4655
5032
  loopStart = i;
4656
5033
  } else {
4657
5034
  break;
@@ -4680,8 +5057,8 @@ function calculateItemsInView(ctx, params = {}) {
4680
5057
  let firstFullyOnScreenIndex;
4681
5058
  const dataLength = data.length;
4682
5059
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
4683
- const id = (_j = idCache[i]) != null ? _j : getId(state, i);
4684
- const size = (_k = sizes.get(id)) != null ? _k : getItemSize(ctx, id, i, data[i]);
5060
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
5061
+ const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
4685
5062
  const top = positions[i];
4686
5063
  if (!foundEnd) {
4687
5064
  if (startNoBuffer === null && top + size > scroll) {
@@ -4720,7 +5097,7 @@ function calculateItemsInView(ctx, params = {}) {
4720
5097
  const firstVisibleAnchorIndex = firstFullyOnScreenIndex != null ? firstFullyOnScreenIndex : startNoBuffer;
4721
5098
  if (firstVisibleAnchorIndex !== null && firstVisibleAnchorIndex !== void 0 && endNoBuffer !== null) {
4722
5099
  for (let i = firstVisibleAnchorIndex; i <= endNoBuffer; i++) {
4723
- const id = (_l = idCache[i]) != null ? _l : getId(state, i);
5100
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
4724
5101
  idsInView.push(id);
4725
5102
  }
4726
5103
  }
@@ -4753,7 +5130,7 @@ function calculateItemsInView(ctx, params = {}) {
4753
5130
  const needNewContainers = [];
4754
5131
  const needNewContainersSet = /* @__PURE__ */ new Set();
4755
5132
  for (let i = startBuffered; i <= endBuffered; i++) {
4756
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
5133
+ const id = (_l = idCache[i]) != null ? _l : getId(state, i);
4757
5134
  if (!containerItemKeys.has(id)) {
4758
5135
  needNewContainersSet.add(i);
4759
5136
  needNewContainers.push(i);
@@ -4762,7 +5139,7 @@ function calculateItemsInView(ctx, params = {}) {
4762
5139
  if (alwaysRenderArr.length > 0) {
4763
5140
  for (const index of alwaysRenderArr) {
4764
5141
  if (index < 0 || index >= dataLength) continue;
4765
- const id = (_n = idCache[index]) != null ? _n : getId(state, index);
5142
+ const id = (_m = idCache[index]) != null ? _m : getId(state, index);
4766
5143
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
4767
5144
  needNewContainersSet.add(index);
4768
5145
  needNewContainers.push(index);
@@ -4801,7 +5178,7 @@ function calculateItemsInView(ctx, params = {}) {
4801
5178
  for (let idx = 0; idx < needNewContainers.length; idx++) {
4802
5179
  const i = needNewContainers[idx];
4803
5180
  const containerIndex = availableContainers[idx];
4804
- const id = (_o = idCache[i]) != null ? _o : getId(state, i);
5181
+ const id = (_n = idCache[i]) != null ? _n : getId(state, i);
4805
5182
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
4806
5183
  if (oldKey && oldKey !== id) {
4807
5184
  containerItemKeys.delete(oldKey);
@@ -4812,7 +5189,7 @@ function calculateItemsInView(ctx, params = {}) {
4812
5189
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
4813
5190
  }
4814
5191
  containerItemKeys.set(id, containerIndex);
4815
- (_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.add(id);
5192
+ (_o = state.userScrollAnchorResetKeys) == null ? void 0 : _o.add(id);
4816
5193
  const containerSticky = `containerSticky${containerIndex}`;
4817
5194
  const isSticky = stickyIndicesSet.has(i);
4818
5195
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -4836,17 +5213,17 @@ function calculateItemsInView(ctx, params = {}) {
4836
5213
  if (numContainers !== prevNumContainers) {
4837
5214
  set$(ctx, "numContainers", numContainers);
4838
5215
  if (numContainers > peek$(ctx, "numContainersPooled")) {
4839
- set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
5216
+ set$(ctx, "numContainersPooled", getExpandedContainerPoolSize(dataLength, numContainers));
4840
5217
  }
4841
5218
  }
4842
5219
  }
4843
- if (((_q = state.userScrollAnchorResetKeys) == null ? void 0 : _q.size) === 0) {
5220
+ if (((_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.size) === 0) {
4844
5221
  state.userScrollAnchorResetKeys = void 0;
4845
5222
  }
4846
5223
  if (alwaysRenderArr.length > 0) {
4847
5224
  for (const index of alwaysRenderArr) {
4848
5225
  if (index < 0 || index >= dataLength) continue;
4849
- const id = (_r = idCache[index]) != null ? _r : getId(state, index);
5226
+ const id = (_q = idCache[index]) != null ? _q : getId(state, index);
4850
5227
  const containerIndex = containerItemKeys.get(id);
4851
5228
  if (containerIndex !== void 0) {
4852
5229
  state.stickyContainerPool.add(containerIndex);
@@ -4920,12 +5297,7 @@ function calculateItemsInView(ctx, params = {}) {
4920
5297
  );
4921
5298
  }
4922
5299
  }
4923
- if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
4924
- const item = data[nextActiveStickyIndex];
4925
- if (item !== void 0) {
4926
- onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4927
- }
4928
- }
5300
+ finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4929
5301
  });
4930
5302
  }
4931
5303
 
@@ -4950,21 +5322,36 @@ function doMaintainScrollAtEnd(ctx) {
4950
5322
  if (contentSize < state.scrollLength) {
4951
5323
  state.scroll = 0;
4952
5324
  }
4953
- requestAnimationFrame(() => {
4954
- var _a3;
4955
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
4956
- state.maintainingScrollAtEnd = true;
4957
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
4958
- animated: maintainScrollAtEnd.animated
4959
- });
4960
- setTimeout(
4961
- () => {
4962
- state.maintainingScrollAtEnd = false;
4963
- },
4964
- maintainScrollAtEnd.animated ? 500 : 0
4965
- );
4966
- }
4967
- });
5325
+ if (!state.maintainingScrollAtEnd) {
5326
+ state.maintainingScrollAtEnd = true;
5327
+ requestAnimationFrame(() => {
5328
+ if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
5329
+ const scroller = refScroller.current;
5330
+ if (state.props.horizontal && isHorizontalRTL(state)) {
5331
+ const currentContentSize = getContentSize(ctx);
5332
+ const logicalEndOffset = getLogicalHorizontalMaxOffset(state, currentContentSize);
5333
+ const nativeOffset = toNativeHorizontalOffset(state, logicalEndOffset, currentContentSize);
5334
+ scroller == null ? void 0 : scroller.scrollTo({
5335
+ animated: maintainScrollAtEnd.animated,
5336
+ x: nativeOffset,
5337
+ y: 0
5338
+ });
5339
+ } else {
5340
+ scroller == null ? void 0 : scroller.scrollToEnd({
5341
+ animated: maintainScrollAtEnd.animated
5342
+ });
5343
+ }
5344
+ setTimeout(
5345
+ () => {
5346
+ state.maintainingScrollAtEnd = false;
5347
+ },
5348
+ maintainScrollAtEnd.animated ? 500 : 0
5349
+ );
5350
+ } else {
5351
+ state.maintainingScrollAtEnd = false;
5352
+ }
5353
+ });
5354
+ }
4968
5355
  return true;
4969
5356
  }
4970
5357
  return false;
@@ -5076,14 +5463,21 @@ function doInitialAllocateContainers(ctx) {
5076
5463
  } else {
5077
5464
  averageItemSize = estimatedItemSize;
5078
5465
  }
5079
- const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
5466
+ const numContainers = Math.max(
5467
+ 1,
5468
+ Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns)
5469
+ );
5080
5470
  for (let i = 0; i < numContainers; i++) {
5081
5471
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
5082
5472
  set$(ctx, `containerColumn${i}`, -1);
5083
5473
  set$(ctx, `containerSpan${i}`, 1);
5084
5474
  }
5085
5475
  set$(ctx, "numContainers", numContainers);
5086
- set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
5476
+ set$(
5477
+ ctx,
5478
+ "numContainersPooled",
5479
+ getInitialContainerPoolSize(data.length, numContainers, state.props.initialContainerPoolRatio)
5480
+ );
5087
5481
  if (state.lastLayout) {
5088
5482
  if (state.initialScroll) {
5089
5483
  requestAnimationFrame(() => {
@@ -5146,7 +5540,8 @@ function handleLayout(ctx, layoutParam, setCanRender) {
5146
5540
  }
5147
5541
  checkThresholds(ctx);
5148
5542
  if (state) {
5149
- state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
5543
+ const crossAxisPadding = state.props.horizontal ? (state.props.stylePaddingTop || 0) + (state.props.stylePaddingBottom || 0) : (state.props.stylePaddingLeft || 0) + (state.props.stylePaddingRight || 0);
5544
+ state.needsOtherAxisSize = otherAxisSize - crossAxisPadding < 10;
5150
5545
  }
5151
5546
  if (IS_DEV && measuredLength === 0) {
5152
5547
  warnDevOnce(
@@ -5234,8 +5629,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
5234
5629
  // src/core/onScroll.ts
5235
5630
  function trackInitialScrollNativeProgress(state, newScroll) {
5236
5631
  const initialNativeScrollWatchdog = initialScrollWatchdog.get(state);
5237
- const didInitialScrollProgress = !!initialNativeScrollWatchdog && initialScrollWatchdog.didObserveProgress(newScroll, initialNativeScrollWatchdog);
5238
- if (didInitialScrollProgress) {
5632
+ const didInitialScrollReachTarget = !!initialNativeScrollWatchdog && initialScrollWatchdog.didReachTarget(newScroll, initialNativeScrollWatchdog);
5633
+ if (didInitialScrollReachTarget) {
5239
5634
  initialScrollWatchdog.clear(state);
5240
5635
  return;
5241
5636
  }
@@ -5260,7 +5655,7 @@ function cloneScrollEvent(event) {
5260
5655
  };
5261
5656
  }
5262
5657
  function onScroll(ctx, event) {
5263
- var _a3, _b, _c, _d;
5658
+ var _a3, _b, _c, _d, _e;
5264
5659
  const state = ctx.state;
5265
5660
  const { scrollProcessingEnabled } = state;
5266
5661
  if (scrollProcessingEnabled === false) {
@@ -5279,6 +5674,9 @@ function onScroll(ctx, event) {
5279
5674
  }
5280
5675
  }
5281
5676
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
5677
+ if (state.props.horizontal) {
5678
+ newScroll = toLogicalHorizontalOffset(state, newScroll, (_e = event.nativeEvent.contentSize) == null ? void 0 : _e.width);
5679
+ }
5282
5680
  if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
5283
5681
  const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
5284
5682
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
@@ -5373,16 +5771,20 @@ function maybeUpdateAnchoredEndSpace(ctx) {
5373
5771
  let contentBelowAnchor = 0;
5374
5772
  const footerSize = ctx.values.get("footerSize") || 0;
5375
5773
  const stylePaddingBottom = state.props.stylePaddingBottom || 0;
5774
+ let hasUnknownTailSize = false;
5376
5775
  for (let index = anchorIndex; index < data.length; index++) {
5377
5776
  const itemKey = getId(state, index);
5378
5777
  const size = itemKey ? state.sizesKnown.get(itemKey) : void 0;
5379
5778
  const effectiveSize = index === anchorIndex && anchorMaxSize !== void 0 ? Math.min(size || 0, Math.max(0, anchorMaxSize)) : size;
5779
+ if (size === void 0) {
5780
+ hasUnknownTailSize = true;
5781
+ }
5380
5782
  if (effectiveSize !== null && effectiveSize !== void 0 && effectiveSize > 0) {
5381
5783
  contentBelowAnchor += effectiveSize;
5382
5784
  }
5383
5785
  }
5384
5786
  contentBelowAnchor += footerSize + stylePaddingBottom;
5385
- nextSize = Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5787
+ nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5386
5788
  }
5387
5789
  }
5388
5790
  if (previousSize !== nextSize) {
@@ -5446,6 +5848,16 @@ function runOrScheduleMVCPRecalculate(ctx) {
5446
5848
  });
5447
5849
  }
5448
5850
  }
5851
+ function updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal) {
5852
+ const state = ctx.state;
5853
+ if (state.needsOtherAxisSize) {
5854
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
5855
+ const currentOtherAxisSize = peek$(ctx, "otherAxisSize");
5856
+ if (!currentOtherAxisSize || otherAxisSize > currentOtherAxisSize) {
5857
+ set$(ctx, "otherAxisSize", otherAxisSize);
5858
+ }
5859
+ }
5860
+ }
5449
5861
  function updateItemSize(ctx, itemKey, sizeObj) {
5450
5862
  var _a3;
5451
5863
  const state = ctx.state;
@@ -5454,15 +5866,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5454
5866
  const {
5455
5867
  didContainersLayout,
5456
5868
  sizesKnown,
5457
- props: {
5458
- getFixedItemSize,
5459
- getItemType,
5460
- horizontal,
5461
- suggestEstimatedItemSize,
5462
- onItemSizeChanged,
5463
- data,
5464
- maintainScrollAtEnd
5465
- }
5869
+ props: { getFixedItemSize, getItemType, horizontal, onItemSizeChanged, data, maintainScrollAtEnd }
5466
5870
  } = state;
5467
5871
  if (!data) return;
5468
5872
  const index = state.indexByKey.get(itemKey);
@@ -5477,13 +5881,13 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5477
5881
  const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
5478
5882
  const size2 = getFixedItemSize(itemData, index, type);
5479
5883
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
5884
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5480
5885
  return;
5481
5886
  }
5482
5887
  }
5483
5888
  let needsRecalculate = !didContainersLayout;
5484
5889
  let shouldMaintainScrollAtEnd = false;
5485
5890
  let minIndexSizeChanged;
5486
- let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
5487
5891
  const prevSizeKnown = state.sizesKnown.get(itemKey);
5488
5892
  const diff = updateOneItemSize(ctx, itemKey, sizeObj);
5489
5893
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
@@ -5494,10 +5898,6 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5494
5898
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
5495
5899
  needsRecalculate = true;
5496
5900
  }
5497
- if (state.needsOtherAxisSize) {
5498
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
5499
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
5500
- }
5501
5901
  if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
5502
5902
  shouldMaintainScrollAtEnd = true;
5503
5903
  }
@@ -5513,22 +5913,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5513
5913
  if (minIndexSizeChanged !== void 0) {
5514
5914
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
5515
5915
  }
5516
- if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
5517
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
5518
- state.timeoutSizeMessage = setTimeout(() => {
5519
- var _a4;
5520
- state.timeoutSizeMessage = void 0;
5521
- const num = state.sizesKnown.size;
5522
- const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
5523
- console.warn(
5524
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
5525
- );
5526
- }, 1e3);
5527
- }
5528
- const cur = peek$(ctx, "otherAxisSize");
5529
- if (!cur || maxOtherAxisSize > cur) {
5530
- set$(ctx, "otherAxisSize", maxOtherAxisSize);
5531
- }
5916
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5532
5917
  if (didContainersLayout || checkAllSizesKnown(state, getMountedBufferedIndices(state))) {
5533
5918
  if (needsRecalculate) {
5534
5919
  state.scrollForNextCalculateItemsInView = void 0;
@@ -5629,12 +6014,47 @@ function createColumnWrapperStyle(contentContainerStyle) {
5629
6014
  }
5630
6015
 
5631
6016
  // src/utils/createImperativeHandle.ts
6017
+ var DEFAULT_AVERAGE_ITEM_SIZE_TYPE = "default";
6018
+ function getAverageItemSizes(state) {
6019
+ const averageItemSizes = {};
6020
+ for (const itemType in state.averageSizes) {
6021
+ const averageSize = state.averageSizes[itemType];
6022
+ if (averageSize) {
6023
+ averageItemSizes[itemType || DEFAULT_AVERAGE_ITEM_SIZE_TYPE] = {
6024
+ average: averageSize.avg,
6025
+ count: averageSize.num
6026
+ };
6027
+ }
6028
+ }
6029
+ return averageItemSizes;
6030
+ }
5632
6031
  function createImperativeHandle(ctx) {
5633
6032
  const state = ctx.state;
5634
6033
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
5635
6034
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
5636
6035
  let imperativeScrollToken = 0;
5637
6036
  const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
6037
+ const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
6038
+ var _a3;
6039
+ const props = state.props;
6040
+ const dataLength = props.data.length;
6041
+ const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
6042
+ if (targetIndex < 0) {
6043
+ return allowEmpty;
6044
+ }
6045
+ if (targetIndex >= dataLength) {
6046
+ return false;
6047
+ }
6048
+ if (anchorIndex === void 0 || anchorIndex < 0 || anchorIndex >= dataLength || targetIndex < anchorIndex || props.getFixedItemSize) {
6049
+ return true;
6050
+ }
6051
+ for (let index = anchorIndex; index < dataLength; index++) {
6052
+ if (!state.sizesKnown.has(getId(state, index))) {
6053
+ return false;
6054
+ }
6055
+ }
6056
+ return true;
6057
+ };
5638
6058
  const runWhenReady = (token, run, isReady) => {
5639
6059
  const startedAt = Date.now();
5640
6060
  let stableFrames = 0;
@@ -5656,11 +6076,10 @@ function createImperativeHandle(ctx) {
5656
6076
  };
5657
6077
  requestAnimationFrame(check);
5658
6078
  };
5659
- const runScrollWithPromise = (run, options) => new Promise((resolve) => {
5660
- var _a3, _b;
6079
+ const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
6080
+ var _a3;
5661
6081
  const token = ++imperativeScrollToken;
5662
- const isReady = (_a3 = options == null ? void 0 : options.isReady) != null ? _a3 : (() => true);
5663
- (_b = state.pendingScrollResolve) == null ? void 0 : _b.call(state);
6082
+ (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
5664
6083
  state.pendingScrollResolve = resolve;
5665
6084
  const runNow = () => {
5666
6085
  if (token !== imperativeScrollToken) {
@@ -5735,6 +6154,7 @@ function createImperativeHandle(ctx) {
5735
6154
  },
5736
6155
  end: state.endNoBuffer,
5737
6156
  endBuffered: state.endBuffered,
6157
+ getAverageItemSizes: () => getAverageItemSizes(state),
5738
6158
  isAtEnd: peek$(ctx, "isAtEnd"),
5739
6159
  isAtStart: peek$(ctx, "isAtStart"),
5740
6160
  isEndReached: state.isEndReached,
@@ -5777,40 +6197,34 @@ function createImperativeHandle(ctx) {
5777
6197
  }
5778
6198
  return false;
5779
6199
  }),
5780
- scrollToEnd: (options) => runScrollWithPromise(() => {
5781
- const data = state.props.data;
5782
- const stylePaddingBottom = state.props.stylePaddingBottom;
5783
- const index = data.length - 1;
5784
- if (index !== -1) {
5785
- const paddingBottom = stylePaddingBottom || 0;
5786
- const footerSize = peek$(ctx, "footerSize") || 0;
5787
- scrollToIndex(ctx, {
5788
- ...options,
5789
- index,
5790
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5791
- viewPosition: 1
5792
- });
5793
- return true;
5794
- }
5795
- return false;
5796
- }),
5797
- scrollToIndex: (params) => {
5798
- const shouldWaitForOutOfRangeTarget = params.index >= 0 && params.index >= state.props.data.length;
5799
- const options = shouldWaitForOutOfRangeTarget ? {
5800
- isReady: () => {
5801
- var _a3;
5802
- const props = state.props;
5803
- const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5804
- const lastIndex = props.data.length - 1;
5805
- const isInRange = params.index < props.data.length;
5806
- const shouldWaitForAnchorSize = isInRange && anchorIndex !== void 0 && anchorIndex >= 0 && params.index >= anchorIndex && !props.getFixedItemSize && !state.sizesKnown.has(getId(state, lastIndex));
5807
- return isInRange && !shouldWaitForAnchorSize;
6200
+ scrollToEnd: (options) => runScrollWithPromise(
6201
+ () => {
6202
+ const data = state.props.data;
6203
+ const stylePaddingBottom = state.props.stylePaddingBottom;
6204
+ const index = data.length - 1;
6205
+ if (index !== -1) {
6206
+ const paddingBottom = stylePaddingBottom || 0;
6207
+ const footerSize = peek$(ctx, "footerSize") || 0;
6208
+ scrollToIndex(ctx, {
6209
+ ...options,
6210
+ index,
6211
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
6212
+ viewPosition: 1
6213
+ });
6214
+ return true;
5808
6215
  }
5809
- } : void 0;
5810
- return runScrollWithPromise(() => {
5811
- scrollToIndex(ctx, params);
5812
- return true;
5813
- }, options);
6216
+ return false;
6217
+ },
6218
+ () => isScrollToIndexReady(state.props.data.length - 1, true)
6219
+ ),
6220
+ scrollToIndex: (params) => {
6221
+ return runScrollWithPromise(
6222
+ () => {
6223
+ scrollToIndex(ctx, params);
6224
+ return true;
6225
+ },
6226
+ params.index >= 0 ? () => isScrollToIndexReady(params.index) : void 0
6227
+ );
5814
6228
  },
5815
6229
  scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
5816
6230
  const data = state.props.data;
@@ -6074,7 +6488,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6074
6488
  getFixedItemSize,
6075
6489
  getItemType,
6076
6490
  horizontal,
6077
- initialContainerPoolRatio = 2,
6491
+ rtl,
6492
+ initialContainerPoolRatio = 3,
6493
+ estimatedHeaderSize,
6078
6494
  initialScrollAtEnd = false,
6079
6495
  initialScrollIndex: initialScrollIndexProp,
6080
6496
  initialScrollOffset: initialScrollOffsetProp,
@@ -6115,7 +6531,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6115
6531
  stickyIndices: stickyIndicesDeprecated,
6116
6532
  // TODOV3: Remove from v3 release
6117
6533
  style: styleProp,
6118
- suggestEstimatedItemSize,
6119
6534
  useWindowScroll = false,
6120
6535
  viewabilityConfig,
6121
6536
  viewabilityConfigCallbackPairs,
@@ -6143,13 +6558,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6143
6558
  const style = { ...StyleSheet.flatten(styleProp) };
6144
6559
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
6145
6560
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
6561
+ const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
6562
+ const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
6146
6563
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
6147
6564
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
6148
6565
  maintainVisibleContentPositionProp
6149
6566
  );
6150
6567
  const hasInitialScrollIndex = initialScrollIndexProp !== void 0 && initialScrollIndexProp !== null;
6151
6568
  const hasInitialScrollOffset = initialScrollOffsetProp !== void 0 && initialScrollOffsetProp !== null;
6152
- const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && hasInitialScrollOffset;
6569
+ const shouldInitializeHorizontalRTL = !initialScrollAtEnd && !hasInitialScrollIndex && !hasInitialScrollOffset && isHorizontalRTLProps({ horizontal, rtl });
6570
+ const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && (hasInitialScrollOffset || shouldInitializeHorizontalRTL);
6153
6571
  const usesBootstrapInitialScroll = initialScrollAtEnd || hasInitialScrollIndex;
6154
6572
  const initialScrollProp = initialScrollAtEnd ? {
6155
6573
  index: Math.max(0, dataProp.length - 1),
@@ -6256,7 +6674,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6256
6674
  startReachedSnapshotDataChangeEpoch: void 0,
6257
6675
  stickyContainerPool: /* @__PURE__ */ new Set(),
6258
6676
  stickyContainers: /* @__PURE__ */ new Map(),
6259
- timeoutSizeMessage: 0,
6260
6677
  timeouts: /* @__PURE__ */ new Set(),
6261
6678
  totalSize: 0,
6262
6679
  viewabilityConfigCallbackPairs: void 0
@@ -6266,6 +6683,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6266
6683
  internalState.reprocessCurrentScroll = () => updateScroll(ctx, internalState.scroll, true);
6267
6684
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
6268
6685
  set$(ctx, "extraData", extraData);
6686
+ if (estimatedHeaderSize !== void 0) {
6687
+ set$(ctx, "headerSize", estimatedHeaderSize);
6688
+ }
6269
6689
  }
6270
6690
  refState.current = ctx.state;
6271
6691
  }
@@ -6276,7 +6696,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6276
6696
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
6277
6697
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
6278
6698
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
6279
- if (didDataChangeLocal && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6699
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6280
6700
  clearPreservedInitialScrollTarget(state);
6281
6701
  }
6282
6702
  if (didDataChangeLocal) {
@@ -6325,13 +6745,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6325
6745
  positionComponentInternal,
6326
6746
  recycleItems: !!recycleItems,
6327
6747
  renderItem,
6748
+ rtl,
6328
6749
  snapToIndices,
6329
6750
  stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
6330
6751
  stickyIndicesSet: React3.useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
6331
6752
  stickyPositionComponentInternal,
6332
6753
  stylePaddingBottom: stylePaddingBottomState,
6754
+ stylePaddingLeft: stylePaddingLeftState,
6755
+ stylePaddingRight: stylePaddingRightState,
6333
6756
  stylePaddingTop: stylePaddingTopState,
6334
- suggestEstimatedItemSize: !!suggestEstimatedItemSize,
6335
6757
  useWindowScroll: useWindowScrollResolved
6336
6758
  };
6337
6759
  state.refScroller = refScroller;
@@ -6353,6 +6775,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6353
6775
  };
6354
6776
  if (isFirstLocal) {
6355
6777
  initializeStateVars(false);
6778
+ resetLayoutCachesForDataChange(state);
6356
6779
  updateItemPositions(
6357
6780
  ctx,
6358
6781
  /*dataChanged*/
@@ -6370,6 +6793,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6370
6793
  }, [usesBootstrapInitialScroll]);
6371
6794
  React3.useLayoutEffect(() => {
6372
6795
  initializeInitialScrollOnMount(ctx, {
6796
+ alwaysDispatchInitialScroll: shouldInitializeHorizontalRTL,
6373
6797
  dataLength: dataProp.length,
6374
6798
  hasFooterComponent: !!ListFooterComponent,
6375
6799
  initialContentOffset,