@legendapp/list 3.0.2 → 3.0.4

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
@@ -1,7 +1,7 @@
1
1
  import * as React2 from 'react';
2
2
  import { useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle, useContext } from 'react';
3
3
  import * as ReactNative from 'react-native';
4
- import { Animated, Platform as Platform$1, View as View$1, Text as Text$1, StyleSheet as StyleSheet$1, RefreshControl, Dimensions, I18nManager } from 'react-native';
4
+ import { Animated, Platform as Platform$1, View as View$1, Text as Text$1, PixelRatio as PixelRatio$1, StyleSheet as StyleSheet$1, RefreshControl, Dimensions, I18nManager } from 'react-native';
5
5
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
6
6
 
7
7
  // src/components/LegendList.tsx
@@ -722,6 +722,22 @@ function Separator({ ItemSeparatorComponent, leadingItem }) {
722
722
  const isLastItem = useIsLastItem();
723
723
  return isLastItem ? null : /* @__PURE__ */ React2.createElement(ItemSeparatorComponent, { leadingItem });
724
724
  }
725
+ var PixelRatio = PixelRatio$1;
726
+
727
+ // src/utils/layoutMeasurement.ts
728
+ var FLOATING_POINT_SLACK = 0.01;
729
+ var NATIVE_LAYOUT_MEASUREMENT_EPSILON = 1 / PixelRatio.get() + FLOATING_POINT_SLACK;
730
+ function isWithinEpsilon(delta) {
731
+ return Math.abs(delta) <= NATIVE_LAYOUT_MEASUREMENT_EPSILON;
732
+ }
733
+ function isNativeLayoutNoise(delta) {
734
+ return isWithinEpsilon(delta);
735
+ }
736
+ function isNativeLayoutSizeNoise(heightDelta, widthDelta) {
737
+ return isWithinEpsilon(heightDelta) && isWithinEpsilon(widthDelta);
738
+ }
739
+
740
+ // src/hooks/useOnLayoutSync.native.tsx
725
741
  function useOnLayoutSync({
726
742
  ref,
727
743
  onLayoutProp,
@@ -730,11 +746,21 @@ function useOnLayoutSync({
730
746
  const lastLayoutRef = useRef(null);
731
747
  const onLayout = useCallback(
732
748
  (event) => {
733
- var _a3, _b;
734
749
  const { layout } = event.nativeEvent;
735
- if (layout.height !== ((_a3 = lastLayoutRef.current) == null ? void 0 : _a3.height) || layout.width !== ((_b = lastLayoutRef.current) == null ? void 0 : _b.width)) {
750
+ const lastLayout = lastLayoutRef.current;
751
+ const didLayoutSizeChange = lastLayout && (layout.height !== lastLayout.height || layout.width !== lastLayout.width);
752
+ const isMeasuredLayoutNoise = !!didLayoutSizeChange && !!lastLayout.measuredLayout && isNativeLayoutSizeNoise(
753
+ layout.height - lastLayout.measuredLayout.height,
754
+ layout.width - lastLayout.measuredLayout.width
755
+ );
756
+ if (!lastLayout || didLayoutSizeChange && !isMeasuredLayoutNoise) {
736
757
  onLayoutChange(layout, false);
737
- lastLayoutRef.current = layout;
758
+ }
759
+ if (!lastLayout || didLayoutSizeChange) {
760
+ lastLayoutRef.current = {
761
+ ...layout,
762
+ measuredLayout: isMeasuredLayoutNoise ? lastLayout == null ? void 0 : lastLayout.measuredLayout : void 0
763
+ };
738
764
  }
739
765
  onLayoutProp == null ? void 0 : onLayoutProp(event);
740
766
  },
@@ -745,7 +771,7 @@ function useOnLayoutSync({
745
771
  if (ref.current) {
746
772
  ref.current.measure((x, y, width, height) => {
747
773
  const layout = { height, width, x, y };
748
- lastLayoutRef.current = layout;
774
+ lastLayoutRef.current = { ...layout, measuredLayout: layout };
749
775
  onLayoutChange(layout, true);
750
776
  });
751
777
  }
@@ -1784,17 +1810,42 @@ function setSize(ctx, itemKey, size, notifyTotalSize = true) {
1784
1810
  }
1785
1811
 
1786
1812
  // src/utils/getItemSize.ts
1813
+ function getKnownOrFixedSize(ctx, key, index, data) {
1814
+ var _a3;
1815
+ const state = ctx.state;
1816
+ const { getFixedItemSize, getItemType } = state.props;
1817
+ let size = key ? state.sizesKnown.get(key) : void 0;
1818
+ if (size === void 0 && key && getFixedItemSize) {
1819
+ const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1820
+ size = getFixedItemSize(data, index, itemType);
1821
+ if (size !== void 0) {
1822
+ state.sizesKnown.set(key, size);
1823
+ }
1824
+ }
1825
+ return size;
1826
+ }
1827
+ function getKnownOrFixedItemSize(ctx, index) {
1828
+ const key = getId(ctx.state, index);
1829
+ return getKnownOrFixedSize(ctx, key, index, ctx.state.props.data[index]);
1830
+ }
1831
+ function areKnownOrFixedItemSizesAvailable(ctx, startIndex, endIndex) {
1832
+ for (let index = startIndex; index <= endIndex; index++) {
1833
+ if (getKnownOrFixedItemSize(ctx, index) === void 0) {
1834
+ return false;
1835
+ }
1836
+ }
1837
+ return true;
1838
+ }
1787
1839
  function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, notifyTotalSize) {
1788
1840
  var _a3, _b, _c;
1789
1841
  const state = ctx.state;
1790
1842
  const {
1791
- sizesKnown,
1792
1843
  sizes,
1793
1844
  averageSizes,
1794
- props: { estimatedItemSize, getFixedItemSize, getItemType },
1845
+ props: { estimatedItemSize, getItemType },
1795
1846
  scrollingTo
1796
1847
  } = state;
1797
- const sizeKnown = sizesKnown.get(key);
1848
+ const sizeKnown = state.sizesKnown.get(key);
1798
1849
  if (sizeKnown !== void 0) {
1799
1850
  return sizeKnown;
1800
1851
  }
@@ -1805,14 +1856,13 @@ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, no
1805
1856
  return renderedSize;
1806
1857
  }
1807
1858
  }
1808
- const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1809
- if (getFixedItemSize) {
1810
- size = getFixedItemSize(data, index, itemType);
1811
- if (size !== void 0) {
1812
- sizesKnown.set(key, size);
1813
- }
1859
+ size = getKnownOrFixedSize(ctx, key, index, data);
1860
+ if (size !== void 0) {
1861
+ setSize(ctx, key, size, notifyTotalSize);
1862
+ return size;
1814
1863
  }
1815
- if (size === void 0 && useAverageSize && sizeKnown === void 0 && !scrollingTo) {
1864
+ const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1865
+ if (useAverageSize && !scrollingTo) {
1816
1866
  const averageSizeForType = (_b = averageSizes[itemType]) == null ? void 0 : _b.avg;
1817
1867
  if (averageSizeForType !== void 0) {
1818
1868
  size = roundSize(averageSizeForType);
@@ -1821,7 +1871,7 @@ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, no
1821
1871
  if (size === void 0 && renderedSize !== void 0) {
1822
1872
  return renderedSize;
1823
1873
  }
1824
- if (size === void 0 && useAverageSize && sizeKnown === void 0 && scrollingTo) {
1874
+ if (size === void 0 && useAverageSize && scrollingTo) {
1825
1875
  const averageSizeForType = (_c = scrollingTo.averageSizeSnapshot) == null ? void 0 : _c[itemType];
1826
1876
  if (averageSizeForType !== void 0) {
1827
1877
  size = roundSize(averageSizeForType);
@@ -2574,7 +2624,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2574
2624
  if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength && !state.pendingNativeMVCPAdjust) {
2575
2625
  state.mvcpAnchorLock = void 0;
2576
2626
  state.pendingNativeMVCPAdjust = void 0;
2577
- state.userScrollAnchorResetKeys = /* @__PURE__ */ new Set();
2627
+ state.userScrollAnchorReset = { keys: /* @__PURE__ */ new Set() };
2578
2628
  if (state.queuedMVCPRecalculate !== void 0) {
2579
2629
  cancelAnimationFrame(state.queuedMVCPRecalculate);
2580
2630
  state.queuedMVCPRecalculate = void 0;
@@ -4392,7 +4442,7 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
4392
4442
  function calculateItemsInView(ctx, params = {}) {
4393
4443
  const state = ctx.state;
4394
4444
  batchedUpdates(() => {
4395
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
4445
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
4396
4446
  const {
4397
4447
  columns,
4398
4448
  containerItemKeys,
@@ -4706,7 +4756,7 @@ function calculateItemsInView(ctx, params = {}) {
4706
4756
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
4707
4757
  }
4708
4758
  containerItemKeys.set(id, containerIndex);
4709
- (_o = state.userScrollAnchorResetKeys) == null ? void 0 : _o.add(id);
4759
+ (_o = state.userScrollAnchorReset) == null ? void 0 : _o.keys.add(id);
4710
4760
  const containerSticky = `containerSticky${containerIndex}`;
4711
4761
  const isSticky = stickyHeaderIndicesSet.has(i);
4712
4762
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -4734,13 +4784,17 @@ function calculateItemsInView(ctx, params = {}) {
4734
4784
  }
4735
4785
  }
4736
4786
  }
4737
- if (((_p = state.userScrollAnchorResetKeys) == null ? void 0 : _p.size) === 0) {
4738
- state.userScrollAnchorResetKeys = void 0;
4787
+ if (state.userScrollAnchorReset) {
4788
+ if (state.userScrollAnchorReset.keys.size === 0) {
4789
+ state.userScrollAnchorReset = void 0;
4790
+ } else {
4791
+ state.userScrollAnchorReset.batchSize = state.userScrollAnchorReset.keys.size;
4792
+ }
4739
4793
  }
4740
4794
  if (alwaysRenderArr.length > 0) {
4741
4795
  for (const index of alwaysRenderArr) {
4742
4796
  if (index < 0 || index >= dataLength) continue;
4743
- const id = (_q = idCache[index]) != null ? _q : getId(state, index);
4797
+ const id = (_p = idCache[index]) != null ? _p : getId(state, index);
4744
4798
  const containerIndex = containerItemKeys.get(id);
4745
4799
  if (containerIndex !== void 0) {
4746
4800
  state.stickyContainerPool.add(containerIndex);
@@ -5138,22 +5192,27 @@ var ScrollAdjustHandler = class {
5138
5192
 
5139
5193
  // src/core/updateAnchoredEndSpace.ts
5140
5194
  function maybeUpdateAnchoredEndSpace(ctx) {
5141
- var _a3;
5195
+ var _a3, _b;
5142
5196
  const state = ctx.state;
5143
5197
  const anchoredEndSpace = state.props.anchoredEndSpace;
5144
5198
  const previousSize = peek$(ctx, "anchoredEndSpaceSize");
5199
+ const previousReadyAnchorIndex = state.anchoredEndSpaceReadyAnchorIndex;
5200
+ const previousReadyAnchorKey = state.anchoredEndSpaceReadyAnchorKey;
5201
+ const nextAnchorIndex = anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex;
5202
+ let nextAnchorKey;
5203
+ let isReady = true;
5145
5204
  let nextSize = 0;
5146
5205
  if (anchoredEndSpace) {
5147
5206
  const { anchorIndex, anchorMaxSize, anchorOffset = 0 } = anchoredEndSpace;
5148
5207
  const { data } = state.props;
5149
5208
  if (anchorIndex >= 0 && anchorIndex < data.length && state.scrollLength > 0) {
5209
+ nextAnchorKey = getId(state, anchorIndex);
5150
5210
  let contentBelowAnchor = 0;
5151
5211
  const footerSize = ctx.values.get("footerSize") || 0;
5152
5212
  const stylePaddingBottom = state.props.stylePaddingBottom || 0;
5153
5213
  let hasUnknownTailSize = false;
5154
5214
  for (let index = anchorIndex; index < data.length; index++) {
5155
- const itemKey = getId(state, index);
5156
- const size = itemKey ? state.sizesKnown.get(itemKey) : void 0;
5215
+ const size = getKnownOrFixedItemSize(ctx, index);
5157
5216
  const effectiveSize = index === anchorIndex && anchorMaxSize !== void 0 ? Math.min(size || 0, Math.max(0, anchorMaxSize)) : size;
5158
5217
  if (size === void 0) {
5159
5218
  hasUnknownTailSize = true;
@@ -5163,15 +5222,25 @@ function maybeUpdateAnchoredEndSpace(ctx) {
5163
5222
  }
5164
5223
  }
5165
5224
  contentBelowAnchor += footerSize + stylePaddingBottom;
5225
+ isReady = !hasUnknownTailSize;
5166
5226
  nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5227
+ } else if (anchorIndex >= 0) {
5228
+ isReady = false;
5167
5229
  }
5168
5230
  }
5169
- if (previousSize !== nextSize) {
5170
- set$(ctx, "anchoredEndSpaceSize", nextSize);
5171
- (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
5172
- if (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset) {
5231
+ const didSizeChange = previousSize !== nextSize;
5232
+ const didReadyAnchorChange = previousReadyAnchorIndex !== nextAnchorIndex || previousReadyAnchorKey !== nextAnchorKey;
5233
+ if (isReady && (didSizeChange || didReadyAnchorChange)) {
5234
+ state.anchoredEndSpaceReadyAnchorIndex = nextAnchorIndex;
5235
+ state.anchoredEndSpaceReadyAnchorKey = nextAnchorKey;
5236
+ if (didSizeChange) {
5237
+ set$(ctx, "anchoredEndSpaceSize", nextSize);
5238
+ (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
5239
+ }
5240
+ if (didSizeChange && (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset)) {
5173
5241
  updateScroll(ctx, state.scroll, true);
5174
5242
  }
5243
+ (_b = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onReady) == null ? void 0 : _b.call(anchoredEndSpace, { anchorIndex: nextAnchorIndex, anchorKey: nextAnchorKey, size: nextSize });
5175
5244
  }
5176
5245
  return nextSize;
5177
5246
  }
@@ -5194,37 +5263,42 @@ function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment)
5194
5263
 
5195
5264
  // src/core/updateItemSize.ts
5196
5265
  function runOrScheduleMVCPRecalculate(ctx) {
5266
+ var _a3, _b;
5197
5267
  const state = ctx.state;
5198
- if (state.userScrollAnchorResetKeys !== void 0) {
5199
- if (state.queuedMVCPRecalculate !== void 0) {
5200
- return;
5201
- }
5202
- state.queuedMVCPRecalculate = requestAnimationFrame(() => {
5203
- var _a3;
5204
- state.queuedMVCPRecalculate = void 0;
5268
+ if (state.userScrollAnchorReset !== void 0) {
5269
+ const replacementBatchSize = (_a3 = state.userScrollAnchorReset.batchSize) != null ? _a3 : state.userScrollAnchorReset.keys.size;
5270
+ const replacementMeasurementBatchThreshold = 3;
5271
+ const shouldBatchReplacementMeasurements = replacementBatchSize > replacementMeasurementBatchThreshold;
5272
+ if (shouldBatchReplacementMeasurements) {
5273
+ if (state.queuedMVCPRecalculate === void 0) {
5274
+ state.queuedMVCPRecalculate = requestAnimationFrame(() => {
5275
+ var _a4;
5276
+ state.queuedMVCPRecalculate = void 0;
5277
+ calculateItemsInView(ctx);
5278
+ if (((_a4 = state.userScrollAnchorReset) == null ? void 0 : _a4.keys.size) === 0) {
5279
+ state.userScrollAnchorReset = void 0;
5280
+ }
5281
+ });
5282
+ }
5283
+ } else {
5205
5284
  calculateItemsInView(ctx);
5206
- if (((_a3 = state.userScrollAnchorResetKeys) == null ? void 0 : _a3.size) === 0) {
5207
- state.userScrollAnchorResetKeys = void 0;
5285
+ if (((_b = state.userScrollAnchorReset) == null ? void 0 : _b.keys.size) === 0) {
5286
+ state.userScrollAnchorReset = void 0;
5208
5287
  }
5209
- });
5210
- return;
5211
- }
5212
- if (Platform.OS === "web") {
5288
+ }
5289
+ } else if (Platform.OS === "web") {
5213
5290
  if (!state.mvcpAnchorLock) {
5214
5291
  if (state.queuedMVCPRecalculate !== void 0) {
5215
5292
  cancelAnimationFrame(state.queuedMVCPRecalculate);
5216
5293
  state.queuedMVCPRecalculate = void 0;
5217
5294
  }
5218
5295
  calculateItemsInView(ctx, { doMVCP: true });
5219
- return;
5220
- }
5221
- if (state.queuedMVCPRecalculate !== void 0) {
5222
- return;
5296
+ } else if (state.queuedMVCPRecalculate === void 0) {
5297
+ state.queuedMVCPRecalculate = requestAnimationFrame(() => {
5298
+ state.queuedMVCPRecalculate = void 0;
5299
+ calculateItemsInView(ctx, { doMVCP: true });
5300
+ });
5223
5301
  }
5224
- state.queuedMVCPRecalculate = requestAnimationFrame(() => {
5225
- state.queuedMVCPRecalculate = void 0;
5226
- calculateItemsInView(ctx, { doMVCP: true });
5227
- });
5228
5302
  } else {
5229
5303
  calculateItemsInView(ctx, { doMVCP: true });
5230
5304
  }
@@ -5242,8 +5316,8 @@ function updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal) {
5242
5316
  function updateItemSize(ctx, itemKey, sizeObj) {
5243
5317
  var _a3;
5244
5318
  const state = ctx.state;
5245
- const userScrollAnchorResetKeys = state.userScrollAnchorResetKeys;
5246
- const didMeasureUserScrollAnchorResetItem = !!(userScrollAnchorResetKeys == null ? void 0 : userScrollAnchorResetKeys.delete(itemKey));
5319
+ const userScrollAnchorReset = state.userScrollAnchorReset;
5320
+ const didMeasureUserScrollAnchorResetItem = !!(userScrollAnchorReset == null ? void 0 : userScrollAnchorReset.keys.delete(itemKey));
5247
5321
  const {
5248
5322
  didContainersLayout,
5249
5323
  sizesKnown,
@@ -5299,8 +5373,8 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5299
5373
  if (needsRecalculate) {
5300
5374
  state.scrollForNextCalculateItemsInView = void 0;
5301
5375
  runOrScheduleMVCPRecalculate(ctx);
5302
- } else if (didMeasureUserScrollAnchorResetItem && (userScrollAnchorResetKeys == null ? void 0 : userScrollAnchorResetKeys.size) === 0) {
5303
- state.userScrollAnchorResetKeys = void 0;
5376
+ } else if (didMeasureUserScrollAnchorResetItem && (userScrollAnchorReset == null ? void 0 : userScrollAnchorReset.keys.size) === 0) {
5377
+ state.userScrollAnchorReset = void 0;
5304
5378
  }
5305
5379
  if (shouldMaintainScrollAtEnd) {
5306
5380
  if (maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.onItemLayout) {
@@ -5310,7 +5384,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5310
5384
  }
5311
5385
  }
5312
5386
  function updateOneItemSize(ctx, itemKey, sizeObj) {
5313
- var _a3;
5387
+ var _a3, _b;
5314
5388
  const state = ctx.state;
5315
5389
  const {
5316
5390
  indexByKey,
@@ -5320,13 +5394,23 @@ function updateOneItemSize(ctx, itemKey, sizeObj) {
5320
5394
  } = state;
5321
5395
  if (!data) return 0;
5322
5396
  const index = indexByKey.get(itemKey);
5323
- const prevSize = getItemSize(ctx, itemKey, index, data[index]);
5397
+ const itemData = data[index];
5398
+ let itemType;
5399
+ let fixedItemSize;
5400
+ if (getFixedItemSize) {
5401
+ itemType = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
5402
+ fixedItemSize = getFixedItemSize(itemData, index, itemType);
5403
+ }
5404
+ const prevSize = getItemSize(ctx, itemKey, index, itemData);
5324
5405
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
5325
- const size = Platform.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
5326
5406
  const prevSizeKnown = sizesKnown.get(itemKey);
5407
+ if (Platform.OS !== "web" && prevSizeKnown !== void 0 && isNativeLayoutNoise(rawSize - prevSizeKnown)) {
5408
+ return 0;
5409
+ }
5410
+ const size = Platform.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
5327
5411
  sizesKnown.set(itemKey, size);
5328
- if (!getFixedItemSize && size > 0) {
5329
- const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
5412
+ if (fixedItemSize === void 0 && size > 0) {
5413
+ itemType != null ? itemType : itemType = getItemType ? (_b = getItemType(itemData, index)) != null ? _b : "" : "";
5330
5414
  let averages = averageSizes[itemType];
5331
5415
  if (!averages) {
5332
5416
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
@@ -5407,6 +5491,25 @@ function createColumnWrapperStyle(contentContainerStyle) {
5407
5491
  }
5408
5492
  }
5409
5493
 
5494
+ // src/core/scrollToEnd.ts
5495
+ function scrollToEnd(ctx, options) {
5496
+ const state = ctx.state;
5497
+ const data = state.props.data;
5498
+ const index = data.length - 1;
5499
+ if (index === -1) {
5500
+ return false;
5501
+ }
5502
+ const paddingBottom = state.props.stylePaddingBottom || 0;
5503
+ const footerSize = peek$(ctx, "footerSize") || 0;
5504
+ scrollToIndex(ctx, {
5505
+ ...options,
5506
+ index,
5507
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5508
+ viewPosition: 1
5509
+ });
5510
+ return true;
5511
+ }
5512
+
5410
5513
  // src/utils/createImperativeHandle.ts
5411
5514
  var DEFAULT_AVERAGE_ITEM_SIZE_TYPE = "default";
5412
5515
  function getAverageItemSizes(state) {
@@ -5422,7 +5525,7 @@ function getAverageItemSizes(state) {
5422
5525
  }
5423
5526
  return averageItemSizes;
5424
5527
  }
5425
- function createImperativeHandle(ctx) {
5528
+ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
5426
5529
  const state = ctx.state;
5427
5530
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
5428
5531
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
@@ -5439,15 +5542,10 @@ function createImperativeHandle(ctx) {
5439
5542
  if (targetIndex >= dataLength) {
5440
5543
  return false;
5441
5544
  }
5442
- if (anchorIndex === void 0 || anchorIndex < 0 || anchorIndex >= dataLength || targetIndex < anchorIndex || props.getFixedItemSize) {
5545
+ if (anchorIndex === void 0 || anchorIndex < 0 || anchorIndex >= dataLength || targetIndex < anchorIndex) {
5443
5546
  return true;
5444
5547
  }
5445
- for (let index = anchorIndex; index < dataLength; index++) {
5446
- if (!state.sizesKnown.has(getId(state, index))) {
5447
- return false;
5448
- }
5449
- }
5450
- return true;
5548
+ return areKnownOrFixedItemSizesAvailable(ctx, anchorIndex, dataLength - 1);
5451
5549
  };
5452
5550
  const runWhenReady = (token, run, isReady) => {
5453
5551
  const startedAt = Date.now();
@@ -5470,11 +5568,7 @@ function createImperativeHandle(ctx) {
5470
5568
  };
5471
5569
  requestAnimationFrame(check);
5472
5570
  };
5473
- const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
5474
- var _a3;
5475
- const token = ++imperativeScrollToken;
5476
- (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
5477
- state.pendingScrollResolve = resolve;
5571
+ const runScrollRequest = (token, resolve, run, isReady = () => true) => {
5478
5572
  const runNow = () => {
5479
5573
  if (token !== imperativeScrollToken) {
5480
5574
  return;
@@ -5492,7 +5586,33 @@ function createImperativeHandle(ctx) {
5492
5586
  } else {
5493
5587
  runNow();
5494
5588
  }
5589
+ };
5590
+ const startImperativeScroll = (resolve) => {
5591
+ var _a3;
5592
+ const token = ++imperativeScrollToken;
5593
+ state.pendingScrollToEnd = void 0;
5594
+ (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
5595
+ state.pendingScrollResolve = resolve;
5596
+ return token;
5597
+ };
5598
+ const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
5599
+ const token = startImperativeScroll(resolve);
5600
+ runScrollRequest(token, resolve, run, isReady);
5495
5601
  });
5602
+ state.runPendingScrollToEnd = () => {
5603
+ const pendingScroll = state.pendingScrollToEnd;
5604
+ if (pendingScroll) {
5605
+ state.pendingScrollToEnd = void 0;
5606
+ if (pendingScroll.token === imperativeScrollToken) {
5607
+ runScrollRequest(
5608
+ pendingScroll.token,
5609
+ pendingScroll.resolve,
5610
+ () => scrollToEnd(ctx, pendingScroll.options),
5611
+ () => isScrollToIndexReady(state.props.data.length - 1, true)
5612
+ );
5613
+ }
5614
+ }
5615
+ };
5496
5616
  const scrollIndexIntoView = (options) => {
5497
5617
  if (state) {
5498
5618
  const { index, ...rest } = options;
@@ -5591,26 +5711,20 @@ function createImperativeHandle(ctx) {
5591
5711
  }
5592
5712
  return false;
5593
5713
  }),
5594
- scrollToEnd: (options) => runScrollWithPromise(
5595
- () => {
5596
- const data = state.props.data;
5597
- const stylePaddingBottom = state.props.stylePaddingBottom;
5598
- const index = data.length - 1;
5599
- if (index !== -1) {
5600
- const paddingBottom = stylePaddingBottom || 0;
5601
- const footerSize = peek$(ctx, "footerSize") || 0;
5602
- scrollToIndex(ctx, {
5603
- ...options,
5604
- index,
5605
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
5606
- viewPosition: 1
5607
- });
5608
- return true;
5609
- }
5610
- return false;
5611
- },
5612
- () => isScrollToIndexReady(state.props.data.length - 1, true)
5613
- ),
5714
+ scrollToEnd: (options) => new Promise((resolve) => {
5715
+ var _a3;
5716
+ const token = startImperativeScroll(resolve);
5717
+ state.pendingScrollToEnd = {
5718
+ options,
5719
+ resolve,
5720
+ token
5721
+ };
5722
+ if (scheduleImperativeScrollCommit) {
5723
+ scheduleImperativeScrollCommit();
5724
+ } else {
5725
+ (_a3 = state.runPendingScrollToEnd) == null ? void 0 : _a3.call(state);
5726
+ }
5727
+ }),
5614
5728
  scrollToIndex: (params) => {
5615
5729
  return runScrollWithPromise(
5616
5730
  () => {
@@ -5980,6 +6094,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5980
6094
  viewOffset: 0
5981
6095
  } : void 0;
5982
6096
  const [canRender, setCanRender] = React2.useState(!IsNewArchitecture);
6097
+ const [, scheduleImperativeScrollCommit] = React2.useReducer((value) => value + 1, 0);
5983
6098
  const ctx = useStateContext();
5984
6099
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
5985
6100
  const refScroller = useRef(null);
@@ -6352,7 +6467,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6352
6467
  doInitialAllocateContainers(ctx);
6353
6468
  }
6354
6469
  });
6355
- useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
6470
+ useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
6471
+ useLayoutEffect(() => {
6472
+ var _a4;
6473
+ (_a4 = state.runPendingScrollToEnd) == null ? void 0 : _a4.call(state);
6474
+ });
6356
6475
  useEffect(() => {
6357
6476
  if (Platform.OS !== "web" || usesBootstrapInitialScroll) {
6358
6477
  return;
@@ -417,12 +417,22 @@ interface MaintainVisibleContentPositionConfig<ItemT = any> {
417
417
  size?: boolean;
418
418
  shouldRestorePosition?: (item: ItemT, index: number, data: readonly ItemT[]) => boolean;
419
419
  }
420
+ interface AnchoredEndSpaceReadyInfo {
421
+ anchorIndex: number | undefined;
422
+ anchorKey: string | undefined;
423
+ size: number;
424
+ }
425
+ interface ScrollToEndOptions {
426
+ animated?: boolean;
427
+ viewOffset?: number;
428
+ }
420
429
  interface AnchoredEndSpaceConfig$1 {
421
430
  anchorIndex: number;
422
431
  anchorOffset?: number;
423
432
  anchorMaxSize?: number;
424
433
  includeInEndInset?: boolean;
425
434
  onSizeChanged?: (size: number) => void;
435
+ onReady?: (info: AnchoredEndSpaceReadyInfo) => void;
426
436
  }
427
437
  interface StickyHeaderConfig {
428
438
  /**
@@ -554,10 +564,7 @@ type LegendListRef$1 = {
554
564
  * @param options.animated - If true, animates the scroll. Default: true.
555
565
  * @param options.viewOffset - Offset from the target position.
556
566
  */
557
- scrollToEnd(options?: {
558
- animated?: boolean | undefined;
559
- viewOffset?: number | undefined;
560
- }): Promise<void>;
567
+ scrollToEnd(options?: ScrollToEndOptions): Promise<void>;
561
568
  /**
562
569
  * Scrolls to a specific index in the list.
563
570
  * @param params - Parameters for scrolling.