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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/react-native.mjs CHANGED
@@ -701,6 +701,7 @@ function getContainerPositionStyle({
701
701
  }
702
702
  var Container = typedMemo(function Container2({
703
703
  id,
704
+ itemKey,
704
705
  recycleItems,
705
706
  horizontal,
706
707
  getRenderedItem: getRenderedItem2,
@@ -712,11 +713,10 @@ var Container = typedMemo(function Container2({
712
713
  const { columnWrapperStyle, animatedScrollY } = ctx;
713
714
  const positionComponentInternal = ctx.state.props.positionComponentInternal;
714
715
  const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
715
- const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
716
+ const [column = 0, span = 1, data, numColumns = 1, extraData, isSticky] = useArr$([
716
717
  `containerColumn${id}`,
717
718
  `containerSpan${id}`,
718
719
  `containerItemData${id}`,
719
- `containerItemKey${id}`,
720
720
  "numColumns",
721
721
  "extraData",
722
722
  `containerSticky${id}`
@@ -861,6 +861,39 @@ var Container = typedMemo(function Container2({
861
861
  );
862
862
  });
863
863
 
864
+ // src/components/ContainerSlot.tsx
865
+ function ContainerSlotBase({
866
+ id,
867
+ horizontal,
868
+ recycleItems,
869
+ ItemSeparatorComponent,
870
+ updateItemSize: updateItemSize2,
871
+ getRenderedItem: getRenderedItem2,
872
+ stickyHeaderConfig,
873
+ ContainerComponent = Container
874
+ }) {
875
+ const [itemKey] = useArr$([`containerItemKey${id}`]);
876
+ if (itemKey === void 0) {
877
+ return null;
878
+ }
879
+ return /* @__PURE__ */ React2.createElement(
880
+ ContainerComponent,
881
+ {
882
+ getRenderedItem: getRenderedItem2,
883
+ horizontal,
884
+ ItemSeparatorComponent,
885
+ id,
886
+ itemKey,
887
+ recycleItems,
888
+ stickyHeaderConfig,
889
+ updateItemSize: updateItemSize2
890
+ }
891
+ );
892
+ }
893
+ var ContainerSlot = typedMemo(function ContainerSlot2(props) {
894
+ return /* @__PURE__ */ React2.createElement(ContainerSlotBase, { ...props });
895
+ });
896
+
864
897
  // src/components/Containers.native.tsx
865
898
  var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal }) {
866
899
  const ctx = useStateContext();
@@ -899,12 +932,12 @@ var Containers = typedMemo(function Containers2({
899
932
  updateItemSize: updateItemSize2,
900
933
  getRenderedItem: getRenderedItem2
901
934
  }) {
902
- const [numContainers] = useArr$(["numContainersPooled"]);
935
+ const [numContainersPooled] = useArr$(["numContainersPooled"]);
903
936
  const containers = [];
904
- for (let i = 0; i < numContainers; i++) {
937
+ for (let i = 0; i < numContainersPooled; i++) {
905
938
  containers.push(
906
939
  /* @__PURE__ */ React2.createElement(
907
- Container,
940
+ ContainerSlot,
908
941
  {
909
942
  getRenderedItem: getRenderedItem2,
910
943
  horizontal,
@@ -1231,10 +1264,9 @@ var initialScrollWatchdog = {
1231
1264
  clear(state) {
1232
1265
  initialScrollWatchdog.set(state, void 0);
1233
1266
  },
1234
- didObserveProgress(newScroll, watchdog) {
1235
- const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
1267
+ didReachTarget(newScroll, watchdog) {
1236
1268
  const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
1237
- return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET || nextDistance + INITIAL_SCROLL_MIN_TARGET_OFFSET < previousDistance;
1269
+ return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET;
1238
1270
  },
1239
1271
  get(state) {
1240
1272
  var _a3, _b;
@@ -1259,19 +1291,19 @@ var initialScrollWatchdog = {
1259
1291
  }
1260
1292
  };
1261
1293
  function setInitialScrollSession(state, options = {}) {
1262
- var _a3, _b, _c;
1294
+ var _a3, _b, _c, _d;
1263
1295
  const existingSession = state.initialScrollSession;
1264
1296
  const kind = (_a3 = options.kind) != null ? _a3 : existingSession == null ? void 0 : existingSession.kind;
1265
1297
  const completion = existingSession == null ? void 0 : existingSession.completion;
1266
- const hasBootstrapOverride = Object.hasOwn(options, "bootstrap");
1267
- const bootstrap = kind === "bootstrap" ? hasBootstrapOverride ? options.bootstrap : (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0 : void 0;
1298
+ const existingBootstrap = (existingSession == null ? void 0 : existingSession.kind) === "bootstrap" ? existingSession.bootstrap : void 0;
1299
+ const bootstrap = kind === "bootstrap" ? options.bootstrap === null ? void 0 : (_b = options.bootstrap) != null ? _b : existingBootstrap : void 0;
1268
1300
  if (!kind) {
1269
1301
  return clearInitialScrollSession(state);
1270
1302
  }
1271
1303
  if (!state.initialScroll && !bootstrap && !hasInitialScrollSessionCompletion(completion)) {
1272
1304
  return clearInitialScrollSession(state);
1273
1305
  }
1274
- const previousDataLength = (_c = (_b = options.previousDataLength) != null ? _b : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _c : 0;
1306
+ const previousDataLength = (_d = (_c = options.previousDataLength) != null ? _c : existingSession == null ? void 0 : existingSession.previousDataLength) != null ? _d : 0;
1275
1307
  state.initialScrollSession = createInitialScrollSession({
1276
1308
  bootstrap,
1277
1309
  completion,
@@ -1853,7 +1885,7 @@ function checkFinishedScrollFallback(ctx) {
1853
1885
  state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
1854
1886
  };
1855
1887
  const checkHasScrolled = () => {
1856
- var _a3, _b, _c;
1888
+ var _a3, _b, _c, _d;
1857
1889
  state.timeoutCheckFinishedScrollFallback = void 0;
1858
1890
  const isStillScrollingTo = state.scrollingTo;
1859
1891
  if (isStillScrollingTo) {
@@ -1866,8 +1898,10 @@ function checkFinishedScrollFallback(ctx) {
1866
1898
  isStillScrollingTo
1867
1899
  );
1868
1900
  const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
1869
- const canFinishAfterSilentNativeDispatch = silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
1901
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
1870
1902
  const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
1903
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
1904
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1871
1905
  if (shouldRetrySilentInitialNativeScroll) {
1872
1906
  const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
1873
1907
  const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
@@ -1877,10 +1911,10 @@ function checkFinishedScrollFallback(ctx) {
1877
1911
  scrollToFallbackOffset(ctx, targetOffset);
1878
1912
  });
1879
1913
  scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
1880
- } else if (shouldFinishZeroTarget || state.hasScrolled || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
1914
+ } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
1881
1915
  finishScrollTo(ctx);
1882
- } else if (isNativeInitialPending && numChecks <= maxChecks) {
1883
- const targetOffset = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : state.scrollPending;
1916
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
1917
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
1884
1918
  scrollToFallbackOffset(ctx, targetOffset);
1885
1919
  scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1886
1920
  } else {
@@ -2109,7 +2143,7 @@ function advanceMeasuredInitialScroll(ctx, options) {
2109
2143
  const activeInitialTargetOffset = scrollingTo ? (_a3 = scrollingTo.targetOffset) != null ? _a3 : scrollingTo.offset : void 0;
2110
2144
  const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - resolvedOffset) > 1;
2111
2145
  const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - resolvedOffset) > 1;
2112
- const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - activeInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - activeInitialTargetOffset) <= 1;
2146
+ const isAlreadyAtDesiredInitialTarget = activeInitialTargetOffset !== void 0 && Math.abs(state.scroll - resolvedOffset) <= 1 && Math.abs(state.scrollPending - resolvedOffset) <= 1;
2113
2147
  if (!(options == null ? void 0 : options.forceScroll) && !didOffsetChange && isInitialScrollInProgress && !didActiveInitialTargetChange) {
2114
2148
  return false;
2115
2149
  }
@@ -2181,6 +2215,61 @@ function checkAllSizesKnown(state, indices) {
2181
2215
  });
2182
2216
  }
2183
2217
 
2218
+ // src/utils/requestAdjust.ts
2219
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2220
+ const state = ctx.state;
2221
+ if (Math.abs(positionDiff) > 0.1) {
2222
+ const needsScrollWorkaround = Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
2223
+ const doit = () => {
2224
+ if (needsScrollWorkaround) {
2225
+ scrollTo(ctx, {
2226
+ noScrollingTo: true,
2227
+ offset: state.scroll
2228
+ });
2229
+ } else {
2230
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
2231
+ if (state.adjustingFromInitialMount) {
2232
+ state.adjustingFromInitialMount--;
2233
+ }
2234
+ }
2235
+ };
2236
+ state.scroll += positionDiff;
2237
+ state.scrollForNextCalculateItemsInView = void 0;
2238
+ const readyToRender = peek$(ctx, "readyToRender");
2239
+ if (readyToRender) {
2240
+ doit();
2241
+ if (Platform.OS !== "web") {
2242
+ const threshold = state.scroll - positionDiff / 2;
2243
+ if (!state.ignoreScrollFromMVCP) {
2244
+ state.ignoreScrollFromMVCP = {};
2245
+ }
2246
+ if (positionDiff > 0) {
2247
+ state.ignoreScrollFromMVCP.lt = threshold;
2248
+ } else {
2249
+ state.ignoreScrollFromMVCP.gt = threshold;
2250
+ }
2251
+ if (state.ignoreScrollFromMVCPTimeout) {
2252
+ clearTimeout(state.ignoreScrollFromMVCPTimeout);
2253
+ }
2254
+ const delay = needsScrollWorkaround ? 250 : 100;
2255
+ state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
2256
+ var _a3;
2257
+ state.ignoreScrollFromMVCP = void 0;
2258
+ const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
2259
+ if (shouldForceUpdate) {
2260
+ state.ignoreScrollFromMVCPIgnored = false;
2261
+ state.scrollPending = state.scroll;
2262
+ (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
2263
+ }
2264
+ }, delay);
2265
+ }
2266
+ } else {
2267
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2268
+ requestAnimationFrame(doit);
2269
+ }
2270
+ }
2271
+ }
2272
+
2184
2273
  // src/core/bootstrapInitialScroll.ts
2185
2274
  var DEFAULT_BOOTSTRAP_REVEAL_EPSILON = 1;
2186
2275
  var DEFAULT_BOOTSTRAP_REVEAL_MAX_FRAMES = 8;
@@ -2274,7 +2363,7 @@ function clearBootstrapInitialScrollSession(state) {
2274
2363
  bootstrapInitialScroll.frameHandle = void 0;
2275
2364
  }
2276
2365
  setInitialScrollSession(state, {
2277
- bootstrap: void 0,
2366
+ bootstrap: null,
2278
2367
  kind: (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind
2279
2368
  });
2280
2369
  }
@@ -2430,15 +2519,18 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2430
2519
  return;
2431
2520
  }
2432
2521
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2433
- if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2434
- clearPendingInitialScrollFooterLayout(ctx, {
2435
- dataLength: state.props.data.length,
2436
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2437
- target: initialScroll
2438
- });
2439
- return;
2522
+ const shouldKeepEndTargetAlive = isRetargetableBottomAlignedInitialScrollTarget(initialScroll) && peek$(ctx, "isAtEnd");
2523
+ if (!shouldKeepEndTargetAlive) {
2524
+ if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2525
+ clearPendingInitialScrollFooterLayout(ctx, {
2526
+ dataLength: state.props.data.length,
2527
+ stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2528
+ target: initialScroll
2529
+ });
2530
+ } else {
2531
+ clearFinishedViewportRetargetableInitialScroll(state);
2532
+ }
2440
2533
  }
2441
- clearFinishedViewportRetargetableInitialScroll(state);
2442
2534
  }
2443
2535
  }
2444
2536
  function startBootstrapInitialScrollOnMount(ctx, options) {
@@ -2477,7 +2569,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2477
2569
  }
2478
2570
  const shouldResetDidFinish = !!(state.didFinishInitialScroll && previousDataLength === 0 && dataLength > 0 && initialScroll.index !== void 0);
2479
2571
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2480
- const shouldClearFinishedResizePreservation = didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
2572
+ const shouldClearFinishedResizePreservation = !initialScrollAtEnd && didDataChange && dataLength > 0 && state.didFinishInitialScroll && !bootstrapInitialScroll && !shouldResetDidFinish;
2481
2573
  if (shouldClearFinishedResizePreservation) {
2482
2574
  clearPreservedInitialScrollTarget(state);
2483
2575
  return;
@@ -2580,27 +2672,46 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2580
2672
  }
2581
2673
  }
2582
2674
  function handleBootstrapInitialScrollLayoutChange(ctx) {
2675
+ var _a3, _b, _c, _d;
2583
2676
  const state = ctx.state;
2584
2677
  const initialScroll = state.initialScroll;
2585
- if (isOffsetInitialScrollSession(state) || state.props.data.length === 0 || !initialScroll) {
2586
- return;
2587
- }
2588
2678
  const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
2589
- if (!bootstrapInitialScroll && initialScroll.viewPosition !== 1) {
2590
- return;
2591
- }
2592
- const didFinishInitialScroll = state.didFinishInitialScroll;
2593
- if (didFinishInitialScroll) {
2594
- setInitialScrollTarget(state, initialScroll, {
2595
- resetDidFinish: true
2596
- });
2597
- state.clearPreservedInitialScrollOnNextFinish = true;
2679
+ if (initialScroll && state.props.data.length > 0 && !isOffsetInitialScrollSession(state) && (bootstrapInitialScroll || initialScroll.viewPosition === 1)) {
2680
+ const resolvedOffset = resolveInitialScrollOffset(ctx, initialScroll);
2681
+ const scrollingTo = ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) ? state.scrollingTo : void 0;
2682
+ if (!bootstrapInitialScroll && (scrollingTo || state.didFinishInitialScroll)) {
2683
+ const currentOffset = scrollingTo ? (_b = scrollingTo.targetOffset) != null ? _b : scrollingTo.offset : getObservedBootstrapInitialScrollOffset(state);
2684
+ const offsetDiff = resolvedOffset - currentOffset;
2685
+ if (Math.abs(offsetDiff) > DEFAULT_BOOTSTRAP_REVEAL_EPSILON) {
2686
+ if (scrollingTo) {
2687
+ const existingWatchdog = initialScrollWatchdog.get(state);
2688
+ scrollingTo.offset = resolvedOffset;
2689
+ scrollingTo.targetOffset = resolvedOffset;
2690
+ state.initialScroll = {
2691
+ ...initialScroll,
2692
+ contentOffset: resolvedOffset
2693
+ };
2694
+ state.hasScrolled = false;
2695
+ initialScrollWatchdog.set(state, {
2696
+ startScroll: (_c = existingWatchdog == null ? void 0 : existingWatchdog.startScroll) != null ? _c : state.scroll,
2697
+ targetOffset: resolvedOffset
2698
+ });
2699
+ }
2700
+ requestAdjust(ctx, offsetDiff);
2701
+ if (state.didFinishInitialScroll) {
2702
+ (_d = state.triggerCalculateItemsInView) == null ? void 0 : _d.call(state, { forceFullItemPositions: true });
2703
+ }
2704
+ }
2705
+ if (state.didFinishInitialScroll) {
2706
+ clearFinishedViewportRetargetableInitialScroll(state);
2707
+ }
2708
+ } else {
2709
+ rearmBootstrapInitialScroll(ctx, {
2710
+ scroll: resolvedOffset,
2711
+ targetIndexSeed: initialScroll.index
2712
+ });
2713
+ }
2598
2714
  }
2599
- rearmBootstrapInitialScroll(ctx, {
2600
- scroll: resolveInitialScrollOffset(ctx, initialScroll),
2601
- seedContentOffset: didFinishInitialScroll && !bootstrapInitialScroll ? getObservedBootstrapInitialScrollOffset(state) : void 0,
2602
- targetIndexSeed: initialScroll.index
2603
- });
2604
2715
  }
2605
2716
  function evaluateBootstrapInitialScroll(ctx) {
2606
2717
  var _a3, _b;
@@ -2787,61 +2898,6 @@ function handleInitialScrollDataChange(ctx, options) {
2787
2898
  advanceCurrentInitialScrollSession(ctx);
2788
2899
  }
2789
2900
 
2790
- // src/utils/requestAdjust.ts
2791
- function requestAdjust(ctx, positionDiff, dataChanged) {
2792
- const state = ctx.state;
2793
- if (Math.abs(positionDiff) > 0.1) {
2794
- const needsScrollWorkaround = Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
2795
- const doit = () => {
2796
- if (needsScrollWorkaround) {
2797
- scrollTo(ctx, {
2798
- noScrollingTo: true,
2799
- offset: state.scroll
2800
- });
2801
- } else {
2802
- state.scrollAdjustHandler.requestAdjust(positionDiff);
2803
- if (state.adjustingFromInitialMount) {
2804
- state.adjustingFromInitialMount--;
2805
- }
2806
- }
2807
- };
2808
- state.scroll += positionDiff;
2809
- state.scrollForNextCalculateItemsInView = void 0;
2810
- const readyToRender = peek$(ctx, "readyToRender");
2811
- if (readyToRender) {
2812
- doit();
2813
- if (Platform.OS !== "web") {
2814
- const threshold = state.scroll - positionDiff / 2;
2815
- if (!state.ignoreScrollFromMVCP) {
2816
- state.ignoreScrollFromMVCP = {};
2817
- }
2818
- if (positionDiff > 0) {
2819
- state.ignoreScrollFromMVCP.lt = threshold;
2820
- } else {
2821
- state.ignoreScrollFromMVCP.gt = threshold;
2822
- }
2823
- if (state.ignoreScrollFromMVCPTimeout) {
2824
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
2825
- }
2826
- const delay = needsScrollWorkaround ? 250 : 100;
2827
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
2828
- var _a3;
2829
- state.ignoreScrollFromMVCP = void 0;
2830
- const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
2831
- if (shouldForceUpdate) {
2832
- state.ignoreScrollFromMVCPIgnored = false;
2833
- state.scrollPending = state.scroll;
2834
- (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
2835
- }
2836
- }, delay);
2837
- }
2838
- } else {
2839
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2840
- requestAnimationFrame(doit);
2841
- }
2842
- }
2843
- }
2844
-
2845
2901
  // src/core/mvcp.ts
2846
2902
  var MVCP_POSITION_EPSILON = 0.1;
2847
2903
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -3125,7 +3181,10 @@ function prepareMVCP(ctx, dataChanged) {
3125
3181
  return;
3126
3182
  }
3127
3183
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
3128
- requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
3184
+ const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
3185
+ if (!shouldSkipAdjustForMaintainedEnd) {
3186
+ requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
3187
+ }
3129
3188
  }
3130
3189
  };
3131
3190
  }
@@ -3744,6 +3803,30 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
3744
3803
  var unstableBatchedUpdates = ReactNative.unstable_batchedUpdates;
3745
3804
  var batchedUpdates = typeof unstableBatchedUpdates === "function" ? unstableBatchedUpdates : (fn) => fn();
3746
3805
 
3806
+ // src/utils/containerPool.ts
3807
+ var MIN_INITIAL_CONTAINER_POOL_SIZE = 32;
3808
+ var MAX_INITIAL_SPARE_CONTAINERS = 64;
3809
+ function getInitialContainerPoolSize(dataLength, numContainers, initialContainerPoolRatio) {
3810
+ if (dataLength <= 0 || numContainers <= 0) {
3811
+ return 0;
3812
+ }
3813
+ const ratioPoolSize = Math.ceil(numContainers * initialContainerPoolRatio);
3814
+ const cappedSparePoolSize = numContainers + MAX_INITIAL_SPARE_CONTAINERS;
3815
+ const targetPoolSize = Math.max(
3816
+ numContainers,
3817
+ Math.min(ratioPoolSize, cappedSparePoolSize),
3818
+ Math.min(dataLength, MIN_INITIAL_CONTAINER_POOL_SIZE)
3819
+ );
3820
+ const maxUsefulPoolSize = Math.max(dataLength, numContainers);
3821
+ return Math.min(maxUsefulPoolSize, targetPoolSize);
3822
+ }
3823
+ function getExpandedContainerPoolSize(dataLength, numContainers) {
3824
+ if (dataLength <= 0 || numContainers <= 0) {
3825
+ return 0;
3826
+ }
3827
+ return Math.min(Math.max(dataLength, numContainers), Math.max(numContainers, Math.ceil(numContainers * 1.5)));
3828
+ }
3829
+
3747
3830
  // src/utils/findAvailableContainers.ts
3748
3831
  function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers, protectedKeys) {
3749
3832
  const numContainers = peek$(ctx, "numContainers");
@@ -3949,7 +4032,7 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
3949
4032
  function calculateItemsInView(ctx, params = {}) {
3950
4033
  const state = ctx.state;
3951
4034
  batchedUpdates(() => {
3952
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
4035
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
3953
4036
  const {
3954
4037
  columns,
3955
4038
  columnSpans,
@@ -3996,12 +4079,22 @@ function calculateItemsInView(ctx, params = {}) {
3996
4079
  // current initial-scroll target instead of transient native adjustments.
3997
4080
  resolveInitialScrollOffset(ctx, initialScroll)
3998
4081
  ) : state.scroll;
3999
- const scrollAdjustPending = (_c = peek$(ctx, "scrollAdjustPending")) != null ? _c : 0;
4000
- const scrollAdjustPad = scrollAdjustPending - topPad;
4001
- let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
4002
- if (scroll + scrollLength > totalSize) {
4003
- scroll = Math.max(0, totalSize - scrollLength);
4004
- }
4082
+ let scrollAdjustPending = 0;
4083
+ let scrollAdjustPad = 0;
4084
+ let scroll = 0;
4085
+ let scrollTopBuffered = 0;
4086
+ let scrollBottom = 0;
4087
+ let scrollBottomBuffered = 0;
4088
+ const updateScroll2 = (nextScrollState) => {
4089
+ var _a4;
4090
+ scrollAdjustPending = (_a4 = peek$(ctx, "scrollAdjustPending")) != null ? _a4 : 0;
4091
+ scrollAdjustPad = scrollAdjustPending - topPad;
4092
+ scroll = Math.round(nextScrollState + scrollExtra + scrollAdjustPad);
4093
+ if (scroll + scrollLength > totalSize) {
4094
+ scroll = Math.max(0, totalSize - scrollLength);
4095
+ }
4096
+ };
4097
+ updateScroll2(scrollState);
4005
4098
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
4006
4099
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
4007
4100
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
@@ -4017,9 +4110,12 @@ function calculateItemsInView(ctx, params = {}) {
4017
4110
  scrollBufferTop = drawDistance * 1.5;
4018
4111
  scrollBufferBottom = drawDistance * 0.5;
4019
4112
  }
4020
- const scrollTopBuffered = scroll - scrollBufferTop;
4021
- const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
4022
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4113
+ const updateScrollRange = () => {
4114
+ scrollTopBuffered = scroll - scrollBufferTop;
4115
+ scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
4116
+ scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4117
+ };
4118
+ updateScrollRange();
4023
4119
  if (!suppressInitialScrollSideEffects && !dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
4024
4120
  const { top, bottom } = scrollForNextCalculateItemsInView;
4025
4121
  if (top === null && bottom === null) {
@@ -4038,7 +4134,7 @@ function calculateItemsInView(ctx, params = {}) {
4038
4134
  columns.length = 0;
4039
4135
  columnSpans.length = 0;
4040
4136
  }
4041
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_d = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _d : 0;
4137
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4042
4138
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4043
4139
  updateItemPositions(ctx, dataChanged, {
4044
4140
  doMVCP,
@@ -4063,21 +4159,25 @@ function calculateItemsInView(ctx, params = {}) {
4063
4159
  }
4064
4160
  }
4065
4161
  const scrollBeforeMVCP = state.scroll;
4066
- const scrollAdjustPendingBeforeMVCP = (_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0;
4162
+ const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
4067
4163
  checkMVCP == null ? void 0 : checkMVCP();
4068
- const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0) !== scrollAdjustPendingBeforeMVCP);
4164
+ const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0) !== scrollAdjustPendingBeforeMVCP);
4165
+ if (didMVCPAdjustScroll && initialScroll) {
4166
+ updateScroll2(state.scroll);
4167
+ updateScrollRange();
4168
+ }
4069
4169
  let startNoBuffer = null;
4070
4170
  let startBuffered = null;
4071
4171
  let startBufferedId = null;
4072
4172
  let endNoBuffer = null;
4073
4173
  let endBuffered = null;
4074
- let loopStart = (_g = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _g : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4174
+ let loopStart = (_f = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _f : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4075
4175
  for (let i = loopStart; i >= 0; i--) {
4076
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
4176
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
4077
4177
  const top = positions[i];
4078
- const size = (_i = sizes.get(id)) != null ? _i : getItemSize(ctx, id, i, data[i]);
4178
+ const size = (_h = sizes.get(id)) != null ? _h : getItemSize(ctx, id, i, data[i]);
4079
4179
  const bottom = top + size;
4080
- if (bottom > scroll - scrollBufferTop) {
4180
+ if (bottom > scrollTopBuffered) {
4081
4181
  loopStart = i;
4082
4182
  } else {
4083
4183
  break;
@@ -4106,8 +4206,8 @@ function calculateItemsInView(ctx, params = {}) {
4106
4206
  let firstFullyOnScreenIndex;
4107
4207
  const dataLength = data.length;
4108
4208
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
4109
- const id = (_j = idCache[i]) != null ? _j : getId(state, i);
4110
- const size = (_k = sizes.get(id)) != null ? _k : getItemSize(ctx, id, i, data[i]);
4209
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
4210
+ const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
4111
4211
  const top = positions[i];
4112
4212
  if (!foundEnd) {
4113
4213
  if (startNoBuffer === null && top + size > scroll) {
@@ -4146,7 +4246,7 @@ function calculateItemsInView(ctx, params = {}) {
4146
4246
  const firstVisibleAnchorIndex = firstFullyOnScreenIndex != null ? firstFullyOnScreenIndex : startNoBuffer;
4147
4247
  if (firstVisibleAnchorIndex !== null && firstVisibleAnchorIndex !== void 0 && endNoBuffer !== null) {
4148
4248
  for (let i = firstVisibleAnchorIndex; i <= endNoBuffer; i++) {
4149
- const id = (_l = idCache[i]) != null ? _l : getId(state, i);
4249
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
4150
4250
  idsInView.push(id);
4151
4251
  }
4152
4252
  }
@@ -4179,7 +4279,7 @@ function calculateItemsInView(ctx, params = {}) {
4179
4279
  const needNewContainers = [];
4180
4280
  const needNewContainersSet = /* @__PURE__ */ new Set();
4181
4281
  for (let i = startBuffered; i <= endBuffered; i++) {
4182
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
4282
+ const id = (_l = idCache[i]) != null ? _l : getId(state, i);
4183
4283
  if (!containerItemKeys.has(id)) {
4184
4284
  needNewContainersSet.add(i);
4185
4285
  needNewContainers.push(i);
@@ -4188,7 +4288,7 @@ function calculateItemsInView(ctx, params = {}) {
4188
4288
  if (alwaysRenderArr.length > 0) {
4189
4289
  for (const index of alwaysRenderArr) {
4190
4290
  if (index < 0 || index >= dataLength) continue;
4191
- const id = (_n = idCache[index]) != null ? _n : getId(state, index);
4291
+ const id = (_m = idCache[index]) != null ? _m : getId(state, index);
4192
4292
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
4193
4293
  needNewContainersSet.add(index);
4194
4294
  needNewContainers.push(index);
@@ -4227,7 +4327,7 @@ function calculateItemsInView(ctx, params = {}) {
4227
4327
  for (let idx = 0; idx < needNewContainers.length; idx++) {
4228
4328
  const i = needNewContainers[idx];
4229
4329
  const containerIndex = availableContainers[idx];
4230
- const id = (_o = idCache[i]) != null ? _o : getId(state, i);
4330
+ const id = (_n = idCache[i]) != null ? _n : getId(state, i);
4231
4331
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
4232
4332
  if (oldKey && oldKey !== id) {
4233
4333
  containerItemKeys.delete(oldKey);
@@ -4238,7 +4338,7 @@ function calculateItemsInView(ctx, params = {}) {
4238
4338
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
4239
4339
  }
4240
4340
  containerItemKeys.set(id, containerIndex);
4241
- (_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.add(id);
4341
+ (_o = state.userScrollAnchorResetKeys) == null ? void 0 : _o.add(id);
4242
4342
  const containerSticky = `containerSticky${containerIndex}`;
4243
4343
  const isSticky = stickyIndicesSet.has(i);
4244
4344
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -4262,17 +4362,17 @@ function calculateItemsInView(ctx, params = {}) {
4262
4362
  if (numContainers !== prevNumContainers) {
4263
4363
  set$(ctx, "numContainers", numContainers);
4264
4364
  if (numContainers > peek$(ctx, "numContainersPooled")) {
4265
- set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
4365
+ set$(ctx, "numContainersPooled", getExpandedContainerPoolSize(dataLength, numContainers));
4266
4366
  }
4267
4367
  }
4268
4368
  }
4269
- if (((_q = state.userScrollAnchorResetKeys) == null ? void 0 : _q.size) === 0) {
4369
+ if (((_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.size) === 0) {
4270
4370
  state.userScrollAnchorResetKeys = void 0;
4271
4371
  }
4272
4372
  if (alwaysRenderArr.length > 0) {
4273
4373
  for (const index of alwaysRenderArr) {
4274
4374
  if (index < 0 || index >= dataLength) continue;
4275
- const id = (_r = idCache[index]) != null ? _r : getId(state, index);
4375
+ const id = (_q = idCache[index]) != null ? _q : getId(state, index);
4276
4376
  const containerIndex = containerItemKeys.get(id);
4277
4377
  if (containerIndex !== void 0) {
4278
4378
  state.stickyContainerPool.add(containerIndex);
@@ -4376,21 +4476,25 @@ function doMaintainScrollAtEnd(ctx) {
4376
4476
  if (contentSize < state.scrollLength) {
4377
4477
  state.scroll = 0;
4378
4478
  }
4379
- requestAnimationFrame(() => {
4380
- var _a3;
4381
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
4382
- state.maintainingScrollAtEnd = true;
4383
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
4384
- animated: maintainScrollAtEnd.animated
4385
- });
4386
- setTimeout(
4387
- () => {
4388
- state.maintainingScrollAtEnd = false;
4389
- },
4390
- maintainScrollAtEnd.animated ? 500 : 0
4391
- );
4392
- }
4393
- });
4479
+ if (!state.maintainingScrollAtEnd) {
4480
+ state.maintainingScrollAtEnd = true;
4481
+ requestAnimationFrame(() => {
4482
+ var _a3;
4483
+ if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
4484
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
4485
+ animated: maintainScrollAtEnd.animated
4486
+ });
4487
+ setTimeout(
4488
+ () => {
4489
+ state.maintainingScrollAtEnd = false;
4490
+ },
4491
+ maintainScrollAtEnd.animated ? 500 : 0
4492
+ );
4493
+ } else {
4494
+ state.maintainingScrollAtEnd = false;
4495
+ }
4496
+ });
4497
+ }
4394
4498
  return true;
4395
4499
  }
4396
4500
  return false;
@@ -4502,14 +4606,21 @@ function doInitialAllocateContainers(ctx) {
4502
4606
  } else {
4503
4607
  averageItemSize = estimatedItemSize;
4504
4608
  }
4505
- const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
4609
+ const numContainers = Math.max(
4610
+ 1,
4611
+ Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns)
4612
+ );
4506
4613
  for (let i = 0; i < numContainers; i++) {
4507
4614
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
4508
4615
  set$(ctx, `containerColumn${i}`, -1);
4509
4616
  set$(ctx, `containerSpan${i}`, 1);
4510
4617
  }
4511
4618
  set$(ctx, "numContainers", numContainers);
4512
- set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
4619
+ set$(
4620
+ ctx,
4621
+ "numContainersPooled",
4622
+ getInitialContainerPoolSize(data.length, numContainers, state.props.initialContainerPoolRatio)
4623
+ );
4513
4624
  if (!IsNewArchitecture || state.lastLayout) {
4514
4625
  if (state.initialScroll) {
4515
4626
  requestAnimationFrame(() => {
@@ -4661,8 +4772,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
4661
4772
  // src/core/onScroll.ts
4662
4773
  function trackInitialScrollNativeProgress(state, newScroll) {
4663
4774
  const initialNativeScrollWatchdog = initialScrollWatchdog.get(state);
4664
- const didInitialScrollProgress = !!initialNativeScrollWatchdog && initialScrollWatchdog.didObserveProgress(newScroll, initialNativeScrollWatchdog);
4665
- if (didInitialScrollProgress) {
4775
+ const didInitialScrollReachTarget = !!initialNativeScrollWatchdog && initialScrollWatchdog.didReachTarget(newScroll, initialNativeScrollWatchdog);
4776
+ if (didInitialScrollReachTarget) {
4666
4777
  initialScrollWatchdog.clear(state);
4667
4778
  return;
4668
4779
  }
@@ -4800,16 +4911,20 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4800
4911
  let contentBelowAnchor = 0;
4801
4912
  const footerSize = ctx.values.get("footerSize") || 0;
4802
4913
  const stylePaddingBottom = state.props.stylePaddingBottom || 0;
4914
+ let hasUnknownTailSize = false;
4803
4915
  for (let index = anchorIndex; index < data.length; index++) {
4804
4916
  const itemKey = getId(state, index);
4805
4917
  const size = itemKey ? state.sizesKnown.get(itemKey) : void 0;
4806
4918
  const effectiveSize = index === anchorIndex && anchorMaxSize !== void 0 ? Math.min(size || 0, Math.max(0, anchorMaxSize)) : size;
4919
+ if (size === void 0) {
4920
+ hasUnknownTailSize = true;
4921
+ }
4807
4922
  if (effectiveSize !== null && effectiveSize !== void 0 && effectiveSize > 0) {
4808
4923
  contentBelowAnchor += effectiveSize;
4809
4924
  }
4810
4925
  }
4811
4926
  contentBelowAnchor += footerSize + stylePaddingBottom;
4812
- nextSize = Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
4927
+ nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
4813
4928
  }
4814
4929
  }
4815
4930
  if (previousSize !== nextSize) {
@@ -4883,15 +4998,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
4883
4998
  const {
4884
4999
  didContainersLayout,
4885
5000
  sizesKnown,
4886
- props: {
4887
- getFixedItemSize,
4888
- getItemType,
4889
- horizontal,
4890
- suggestEstimatedItemSize,
4891
- onItemSizeChanged,
4892
- data,
4893
- maintainScrollAtEnd
4894
- }
5001
+ props: { getFixedItemSize, getItemType, horizontal, onItemSizeChanged, data, maintainScrollAtEnd }
4895
5002
  } = state;
4896
5003
  if (!data) return;
4897
5004
  const index = state.indexByKey.get(itemKey);
@@ -4942,18 +5049,6 @@ function updateItemSize(ctx, itemKey, sizeObj) {
4942
5049
  if (minIndexSizeChanged !== void 0) {
4943
5050
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
4944
5051
  }
4945
- if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
4946
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
4947
- state.timeoutSizeMessage = setTimeout(() => {
4948
- var _a4;
4949
- state.timeoutSizeMessage = void 0;
4950
- const num = state.sizesKnown.size;
4951
- const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
4952
- console.warn(
4953
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
4954
- );
4955
- }, 1e3);
4956
- }
4957
5052
  const cur = peek$(ctx, "otherAxisSize");
4958
5053
  if (!cur || maxOtherAxisSize > cur) {
4959
5054
  set$(ctx, "otherAxisSize", maxOtherAxisSize);
@@ -5071,12 +5166,47 @@ function createColumnWrapperStyle(contentContainerStyle) {
5071
5166
  }
5072
5167
 
5073
5168
  // src/utils/createImperativeHandle.ts
5169
+ var DEFAULT_AVERAGE_ITEM_SIZE_TYPE = "default";
5170
+ function getAverageItemSizes(state) {
5171
+ const averageItemSizes = {};
5172
+ for (const itemType in state.averageSizes) {
5173
+ const averageSize = state.averageSizes[itemType];
5174
+ if (averageSize) {
5175
+ averageItemSizes[itemType || DEFAULT_AVERAGE_ITEM_SIZE_TYPE] = {
5176
+ average: averageSize.avg,
5177
+ count: averageSize.num
5178
+ };
5179
+ }
5180
+ }
5181
+ return averageItemSizes;
5182
+ }
5074
5183
  function createImperativeHandle(ctx) {
5075
5184
  const state = ctx.state;
5076
5185
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
5077
5186
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
5078
5187
  let imperativeScrollToken = 0;
5079
5188
  const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
5189
+ const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
5190
+ var _a3;
5191
+ const props = state.props;
5192
+ const dataLength = props.data.length;
5193
+ const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5194
+ if (targetIndex < 0) {
5195
+ return allowEmpty;
5196
+ }
5197
+ if (targetIndex >= dataLength) {
5198
+ return false;
5199
+ }
5200
+ if (anchorIndex === void 0 || anchorIndex < 0 || anchorIndex >= dataLength || targetIndex < anchorIndex || props.getFixedItemSize) {
5201
+ return true;
5202
+ }
5203
+ for (let index = anchorIndex; index < dataLength; index++) {
5204
+ if (!state.sizesKnown.has(getId(state, index))) {
5205
+ return false;
5206
+ }
5207
+ }
5208
+ return true;
5209
+ };
5080
5210
  const runWhenReady = (token, run, isReady) => {
5081
5211
  const startedAt = Date.now();
5082
5212
  let stableFrames = 0;
@@ -5098,11 +5228,10 @@ function createImperativeHandle(ctx) {
5098
5228
  };
5099
5229
  requestAnimationFrame(check);
5100
5230
  };
5101
- const runScrollWithPromise = (run, options) => new Promise((resolve) => {
5102
- var _a3, _b;
5231
+ const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
5232
+ var _a3;
5103
5233
  const token = ++imperativeScrollToken;
5104
- const isReady = (_a3 = options == null ? void 0 : options.isReady) != null ? _a3 : (() => true);
5105
- (_b = state.pendingScrollResolve) == null ? void 0 : _b.call(state);
5234
+ (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
5106
5235
  state.pendingScrollResolve = resolve;
5107
5236
  const runNow = () => {
5108
5237
  if (token !== imperativeScrollToken) {
@@ -5177,6 +5306,7 @@ function createImperativeHandle(ctx) {
5177
5306
  },
5178
5307
  end: state.endNoBuffer,
5179
5308
  endBuffered: state.endBuffered,
5309
+ getAverageItemSizes: () => getAverageItemSizes(state),
5180
5310
  isAtEnd: peek$(ctx, "isAtEnd"),
5181
5311
  isAtStart: peek$(ctx, "isAtStart"),
5182
5312
  isEndReached: state.isEndReached,
@@ -5219,40 +5349,34 @@ function createImperativeHandle(ctx) {
5219
5349
  }
5220
5350
  return false;
5221
5351
  }),
5222
- scrollToEnd: (options) => runScrollWithPromise(() => {
5223
- const data = state.props.data;
5224
- const stylePaddingBottom = state.props.stylePaddingBottom;
5225
- const index = data.length - 1;
5226
- if (index !== -1) {
5227
- const paddingBottom = stylePaddingBottom || 0;
5228
- const footerSize = peek$(ctx, "footerSize") || 0;
5229
- scrollToIndex(ctx, {
5230
- ...options,
5231
- index,
5232
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5233
- viewPosition: 1
5234
- });
5235
- return true;
5236
- }
5237
- return false;
5238
- }),
5239
- scrollToIndex: (params) => {
5240
- const shouldWaitForOutOfRangeTarget = params.index >= 0 && params.index >= state.props.data.length;
5241
- const options = shouldWaitForOutOfRangeTarget ? {
5242
- isReady: () => {
5243
- var _a3;
5244
- const props = state.props;
5245
- const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5246
- const lastIndex = props.data.length - 1;
5247
- const isInRange = params.index < props.data.length;
5248
- const shouldWaitForAnchorSize = isInRange && anchorIndex !== void 0 && anchorIndex >= 0 && params.index >= anchorIndex && !props.getFixedItemSize && !state.sizesKnown.has(getId(state, lastIndex));
5249
- return isInRange && !shouldWaitForAnchorSize;
5352
+ scrollToEnd: (options) => runScrollWithPromise(
5353
+ () => {
5354
+ const data = state.props.data;
5355
+ const stylePaddingBottom = state.props.stylePaddingBottom;
5356
+ const index = data.length - 1;
5357
+ if (index !== -1) {
5358
+ const paddingBottom = stylePaddingBottom || 0;
5359
+ const footerSize = peek$(ctx, "footerSize") || 0;
5360
+ scrollToIndex(ctx, {
5361
+ ...options,
5362
+ index,
5363
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5364
+ viewPosition: 1
5365
+ });
5366
+ return true;
5250
5367
  }
5251
- } : void 0;
5252
- return runScrollWithPromise(() => {
5253
- scrollToIndex(ctx, params);
5254
- return true;
5255
- }, options);
5368
+ return false;
5369
+ },
5370
+ () => isScrollToIndexReady(state.props.data.length - 1, true)
5371
+ ),
5372
+ scrollToIndex: (params) => {
5373
+ return runScrollWithPromise(
5374
+ () => {
5375
+ scrollToIndex(ctx, params);
5376
+ return true;
5377
+ },
5378
+ params.index >= 0 ? () => isScrollToIndexReady(params.index) : void 0
5379
+ );
5256
5380
  },
5257
5381
  scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
5258
5382
  const data = state.props.data;
@@ -5516,7 +5640,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5516
5640
  getFixedItemSize,
5517
5641
  getItemType,
5518
5642
  horizontal,
5519
- initialContainerPoolRatio = 2,
5643
+ initialContainerPoolRatio = 3,
5520
5644
  initialScrollAtEnd = false,
5521
5645
  initialScrollIndex: initialScrollIndexProp,
5522
5646
  initialScrollOffset: initialScrollOffsetProp,
@@ -5557,7 +5681,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5557
5681
  stickyIndices: stickyIndicesDeprecated,
5558
5682
  // TODOV3: Remove from v3 release
5559
5683
  style: styleProp,
5560
- suggestEstimatedItemSize,
5561
5684
  useWindowScroll = false,
5562
5685
  viewabilityConfig,
5563
5686
  viewabilityConfigCallbackPairs,
@@ -5698,7 +5821,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5698
5821
  startReachedSnapshotDataChangeEpoch: void 0,
5699
5822
  stickyContainerPool: /* @__PURE__ */ new Set(),
5700
5823
  stickyContainers: /* @__PURE__ */ new Map(),
5701
- timeoutSizeMessage: 0,
5702
5824
  timeouts: /* @__PURE__ */ new Set(),
5703
5825
  totalSize: 0,
5704
5826
  viewabilityConfigCallbackPairs: void 0
@@ -5718,7 +5840,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5718
5840
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
5719
5841
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
5720
5842
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
5721
- if (didDataChangeLocal && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
5843
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
5722
5844
  clearPreservedInitialScrollTarget(state);
5723
5845
  }
5724
5846
  if (didDataChangeLocal) {
@@ -5773,7 +5895,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5773
5895
  stickyPositionComponentInternal,
5774
5896
  stylePaddingBottom: stylePaddingBottomState,
5775
5897
  stylePaddingTop: stylePaddingTopState,
5776
- suggestEstimatedItemSize: !!suggestEstimatedItemSize,
5777
5898
  useWindowScroll: useWindowScrollResolved
5778
5899
  };
5779
5900
  state.refScroller = refScroller;