@legendapp/list 1.0.0-beta.50 → 1.0.0-beta.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs CHANGED
@@ -128,6 +128,16 @@ function useInterval(callback, delay) {
128
128
  function isFunction(obj) {
129
129
  return typeof obj === "function";
130
130
  }
131
+ var warned = /* @__PURE__ */ new Set();
132
+ function warnDevOnce(id, text) {
133
+ if (__DEV__ && !warned.has(id)) {
134
+ warned.add(id);
135
+ console.warn(`[legend-list] ${text}`);
136
+ }
137
+ }
138
+ function roundSize(size) {
139
+ return Math.floor(size * 8) / 8;
140
+ }
131
141
  var symbolFirst = Symbol();
132
142
  function useInit(cb) {
133
143
  const refValue = useRef(symbolFirst);
@@ -306,7 +316,7 @@ var Container = ({
306
316
  const onLayout = (event) => {
307
317
  if (itemKey !== void 0) {
308
318
  const layout = event.nativeEvent.layout;
309
- const size = Math.floor(layout[horizontal ? "width" : "height"] * 8) / 8;
319
+ const size = roundSize(layout[horizontal ? "width" : "height"]);
310
320
  refLastSize.current = size;
311
321
  updateItemSize(itemKey, size);
312
322
  }
@@ -876,9 +886,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
876
886
  renderItem,
877
887
  estimatedItemSize,
878
888
  getEstimatedItemSize,
889
+ suggestEstimatedItemSize,
879
890
  ListEmptyComponent,
880
891
  onItemSizeChanged,
881
- scrollEventThrottle,
882
892
  refScrollView,
883
893
  waitForInitialLayout = true,
884
894
  extraData,
@@ -926,14 +936,31 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
926
936
  const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
927
937
  return `${ret}`;
928
938
  };
929
- const getItemSize = (key, index, data) => {
930
- var _a;
931
- const sizeKnown = refState.current.sizes.get(key);
939
+ const getItemSize = (key, index, data, useAverageSize = false) => {
940
+ const state = refState.current;
941
+ const sizeKnown = state.sizesKnown.get(key);
932
942
  if (sizeKnown !== void 0) {
933
943
  return sizeKnown;
934
944
  }
935
- const size = (_a = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize) != null ? _a : DEFAULT_ITEM_SIZE;
936
- refState.current.sizes.set(key, size);
945
+ let size;
946
+ if (getEstimatedItemSize) {
947
+ size = getEstimatedItemSize(index, data);
948
+ }
949
+ if (size === void 0 && useAverageSize) {
950
+ const itemType = "";
951
+ const average = state.averageSizes[itemType];
952
+ if (average) {
953
+ size = roundSize(average.avg);
954
+ }
955
+ }
956
+ const sizePrevious = state.sizesKnown.get(key);
957
+ if (sizePrevious !== void 0) {
958
+ return sizePrevious;
959
+ }
960
+ if (size === void 0) {
961
+ size = estimatedItemSize != null ? estimatedItemSize : DEFAULT_ITEM_SIZE;
962
+ }
963
+ state.sizes.set(key, size);
937
964
  return size;
938
965
  };
939
966
  const calculateOffsetForIndex = (index = initialScrollIndex) => {
@@ -1004,6 +1031,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1004
1031
  numPendingInitialLayout: 0,
1005
1032
  queuedCalculateItemsInView: 0,
1006
1033
  lastBatchingAction: Date.now(),
1034
+ averageSizes: {},
1007
1035
  onScroll: onScrollProp
1008
1036
  };
1009
1037
  const dataLength = dataProp.length;
@@ -1019,7 +1047,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1019
1047
  id: getId(0)
1020
1048
  };
1021
1049
  } else {
1022
- console.warn("[legend-list] maintainVisibleContentPosition was not able to find an anchor element");
1050
+ __DEV__ && warnDevOnce(
1051
+ "maintainVisibleContentPosition",
1052
+ "[legend-list] maintainVisibleContentPosition was not able to find an anchor element"
1053
+ );
1023
1054
  }
1024
1055
  }
1025
1056
  set$(ctx, "scrollAdjust", 0);
@@ -1181,14 +1212,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1181
1212
  var _a;
1182
1213
  const state = refState.current;
1183
1214
  const { data, scrollLength, positions, startBuffered, endBuffered } = state;
1184
- if (!data || scrollLength === 0) {
1215
+ const numColumns = peek$(ctx, "numColumns");
1216
+ if (!data || scrollLength === 0 || numColumns > 1) {
1185
1217
  return;
1186
1218
  }
1187
1219
  const numContainers = ctx.values.get("numContainers");
1188
1220
  let numMeasurements = 0;
1189
1221
  for (let i = 0; i < numContainers; i++) {
1190
1222
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1191
- const isSizeKnown = refState.current.sizesKnown.get(itemKey);
1223
+ const isSizeKnown = state.sizesKnown.get(itemKey);
1192
1224
  if (itemKey && !isSizeKnown) {
1193
1225
  const containerRef = ctx.viewRefs.get(i);
1194
1226
  if (containerRef) {
@@ -1313,7 +1345,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1313
1345
  }
1314
1346
  const top2 = newPosition || positions.get(id);
1315
1347
  if (top2 !== void 0) {
1316
- const size = getItemSize(id, i, data[i]);
1348
+ const size = getItemSize(
1349
+ id,
1350
+ i,
1351
+ data[i],
1352
+ /*useAverageSize*/
1353
+ true
1354
+ );
1317
1355
  const bottom = top2 + size;
1318
1356
  if (bottom > scroll - scrollBuffer) {
1319
1357
  loopStart = i;
@@ -1343,7 +1381,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1343
1381
  };
1344
1382
  for (let i = Math.max(0, loopStart); i < data.length; i++) {
1345
1383
  const id = getId(i);
1346
- const size = getItemSize(id, i, data[i]);
1384
+ const size = getItemSize(
1385
+ id,
1386
+ i,
1387
+ data[i],
1388
+ /*useAverageSize*/
1389
+ true
1390
+ );
1347
1391
  maxSizeInRow = Math.max(maxSizeInRow, size);
1348
1392
  if (top === void 0 || id === ((_a = state.anchorElement) == null ? void 0 : _a.id)) {
1349
1393
  top = getInitialTop(i);
@@ -1567,9 +1611,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1567
1611
  }
1568
1612
  requestAnimationFrame(() => {
1569
1613
  var _a;
1614
+ state.maintainingScrollAtEnd = true;
1570
1615
  (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
1571
1616
  animated
1572
1617
  });
1618
+ setTimeout(
1619
+ () => {
1620
+ state.maintainingScrollAtEnd = false;
1621
+ },
1622
+ 0
1623
+ );
1573
1624
  });
1574
1625
  return true;
1575
1626
  }
@@ -1597,9 +1648,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1597
1648
  if (!refState.current) {
1598
1649
  return;
1599
1650
  }
1600
- const { queuedInitialLayout, scrollLength, scroll } = refState.current;
1651
+ const { queuedInitialLayout, scrollLength, scroll, maintainingScrollAtEnd } = refState.current;
1601
1652
  const contentSize = getContentSize(ctx);
1602
- if (contentSize > 0 && queuedInitialLayout) {
1653
+ if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1603
1654
  const distanceFromEnd = contentSize - scroll - scrollLength;
1604
1655
  const distanceFromEndAbs = Math.abs(distanceFromEnd);
1605
1656
  const isContentLess = contentSize < scrollLength;
@@ -1667,13 +1718,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1667
1718
  if (!didMaintainScrollAtEnd && dataProp.length > state.data.length) {
1668
1719
  state.isEndReached = false;
1669
1720
  }
1670
- checkAtTop();
1671
- checkAtBottom();
1721
+ if (!didMaintainScrollAtEnd) {
1722
+ checkAtTop();
1723
+ checkAtBottom();
1724
+ }
1672
1725
  }
1673
1726
  }
1674
1727
  };
1675
1728
  const calcTotalSizesAndPositions = ({ forgetPositions = false }) => {
1676
1729
  var _a, _b;
1730
+ const state = refState.current;
1677
1731
  let totalSize = 0;
1678
1732
  let totalSizeBelowIndex = 0;
1679
1733
  const indexByKey = /* @__PURE__ */ new Map();
@@ -1681,7 +1735,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1681
1735
  let column = 1;
1682
1736
  let maxSizeInRow = 0;
1683
1737
  const numColumns = (_a = peek$(ctx, "numColumns")) != null ? _a : numColumnsProp;
1684
- if (!refState.current) {
1738
+ if (!state) {
1685
1739
  return;
1686
1740
  }
1687
1741
  for (let i = 0; i < dataProp.length; i++) {
@@ -1694,36 +1748,36 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1694
1748
  }
1695
1749
  }
1696
1750
  indexByKey.set(key, i);
1697
- if (!forgetPositions && refState.current.positions.get(key) != null && refState.current.indexByKey.get(key) === i) {
1698
- newPositions.set(key, refState.current.positions.get(key));
1751
+ if (!forgetPositions && state.positions.get(key) != null && state.indexByKey.get(key) === i) {
1752
+ newPositions.set(key, state.positions.get(key));
1699
1753
  }
1700
1754
  }
1701
- refState.current.indexByKey = indexByKey;
1702
- refState.current.positions = newPositions;
1755
+ state.indexByKey = indexByKey;
1756
+ state.positions = newPositions;
1703
1757
  if (!forgetPositions && !isFirst) {
1704
1758
  if (maintainVisibleContentPosition) {
1705
- if (refState.current.anchorElement == null || indexByKey.get(refState.current.anchorElement.id) == null) {
1759
+ if (state.anchorElement == null || indexByKey.get(state.anchorElement.id) == null) {
1706
1760
  if (dataProp.length) {
1707
1761
  const newAnchorElement = {
1708
1762
  coordinate: 0,
1709
1763
  id: getId(0)
1710
1764
  };
1711
- refState.current.anchorElement = newAnchorElement;
1712
- (_b = refState.current.belowAnchorElementPositions) == null ? void 0 : _b.clear();
1765
+ state.anchorElement = newAnchorElement;
1766
+ (_b = state.belowAnchorElementPositions) == null ? void 0 : _b.clear();
1713
1767
  scrollTo(0, false);
1714
1768
  setTimeout(() => {
1715
1769
  calculateItemsInView();
1716
1770
  }, 0);
1717
1771
  } else {
1718
- refState.current.startBufferedId = void 0;
1772
+ state.startBufferedId = void 0;
1719
1773
  }
1720
1774
  }
1721
1775
  } else {
1722
- if (refState.current.startBufferedId != null && newPositions.get(refState.current.startBufferedId) == null) {
1776
+ if (state.startBufferedId != null && newPositions.get(state.startBufferedId) == null) {
1723
1777
  if (dataProp.length) {
1724
- refState.current.startBufferedId = getId(0);
1778
+ state.startBufferedId = getId(0);
1725
1779
  } else {
1726
- refState.current.startBufferedId = void 0;
1780
+ state.startBufferedId = void 0;
1727
1781
  }
1728
1782
  scrollTo(0, false);
1729
1783
  setTimeout(() => {
@@ -1750,7 +1804,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1750
1804
  if (maxSizeInRow > 0) {
1751
1805
  totalSize += maxSizeInRow;
1752
1806
  }
1753
- const state = refState.current;
1754
1807
  state.ignoreScrollFromCalcTotal = true;
1755
1808
  requestAnimationFrame(() => {
1756
1809
  state.ignoreScrollFromCalcTotal = false;
@@ -1783,6 +1836,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1783
1836
  if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
1784
1837
  refState.current.lastBatchingAction = Date.now();
1785
1838
  if (!keyExtractorProp && !isFirst && didDataChange) {
1839
+ __DEV__ && warnDevOnce(
1840
+ "keyExtractor",
1841
+ "Changing data without a keyExtractor can cause slow performance and resetting scroll. If your list data can change you should use a keyExtractor with a unique id for best performance and behavior."
1842
+ );
1786
1843
  refState.current.sizes.clear();
1787
1844
  refState.current.positions.clear();
1788
1845
  }
@@ -1813,24 +1870,28 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1813
1870
  if (index === void 0) {
1814
1871
  return null;
1815
1872
  }
1816
- const useViewability2 = __DEV__ ? (configId, callback) => {
1817
- console.warn(
1818
- `[legend-list] useViewability has been moved from a render prop to a regular import: import { useViewability } from "@legendapp/list";`
1873
+ const useViewability2 = __DEV__ ? () => {
1874
+ warnDevOnce(
1875
+ "useViewability",
1876
+ `useViewability has been moved from a render prop to a regular import: import { useViewability } from "@legendapp/list";`
1819
1877
  );
1820
1878
  } : void 0;
1821
- const useViewabilityAmount2 = __DEV__ ? (callback) => {
1822
- console.warn(
1823
- `[legend-list] useViewabilityAmount has been moved from a render prop to a regular import: import { useViewabilityAmount } from "@legendapp/list";`
1879
+ const useViewabilityAmount2 = __DEV__ ? () => {
1880
+ warnDevOnce(
1881
+ "useViewabilityAmount",
1882
+ `useViewabilityAmount has been moved from a render prop to a regular import: import { useViewabilityAmount } from "@legendapp/list";`
1824
1883
  );
1825
1884
  } : void 0;
1826
- const useRecyclingEffect2 = __DEV__ ? (effect) => {
1827
- console.warn(
1828
- `[legend-list] useRecyclingEffect has been moved from a render prop to a regular import: import { useRecyclingEffect } from "@legendapp/list";`
1885
+ const useRecyclingEffect2 = __DEV__ ? () => {
1886
+ warnDevOnce(
1887
+ "useRecyclingEffect",
1888
+ `useRecyclingEffect has been moved from a render prop to a regular import: import { useRecyclingEffect } from "@legendapp/list";`
1829
1889
  );
1830
1890
  } : void 0;
1831
- const useRecyclingState2 = __DEV__ ? (valueOrFun) => {
1832
- console.warn(
1833
- `[legend-list] useRecyclingState has been moved from a render prop to a regular import: import { useRecyclingState } from "@legendapp/list";`
1891
+ const useRecyclingState2 = __DEV__ ? () => {
1892
+ warnDevOnce(
1893
+ "useRecyclingState",
1894
+ `useRecyclingState has been moved from a render prop to a regular import: import { useRecyclingState } from "@legendapp/list";`
1834
1895
  );
1835
1896
  } : void 0;
1836
1897
  const renderedItem = (_b = (_a = refState.current).renderItem) == null ? void 0 : _b.call(_a, {
@@ -1883,7 +1944,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1883
1944
  });
1884
1945
  const updateItemSize = useCallback((itemKey, size, fromFixGaps) => {
1885
1946
  const state = refState.current;
1886
- const { sizes, indexByKey, sizesKnown, data, rowHeights, startBuffered, endBuffered } = state;
1947
+ const { sizes, indexByKey, sizesKnown, data, rowHeights, startBuffered, endBuffered, averageSizes } = state;
1887
1948
  if (!data) {
1888
1949
  return;
1889
1950
  }
@@ -1901,7 +1962,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1901
1962
  needsUpdateContainersDidLayout = true;
1902
1963
  }
1903
1964
  }
1904
- sizesKnown == null ? void 0 : sizesKnown.set(itemKey, size);
1965
+ sizesKnown.set(itemKey, size);
1966
+ const itemType = "";
1967
+ let averages = averageSizes[itemType];
1968
+ if (!averages) {
1969
+ averages = averageSizes[itemType] = {
1970
+ num: 0,
1971
+ avg: 0
1972
+ };
1973
+ }
1974
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
1975
+ averages.num++;
1905
1976
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1906
1977
  let diff;
1907
1978
  needsCalculate = true;
@@ -1916,19 +1987,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1916
1987
  sizes.set(itemKey, size);
1917
1988
  diff = size - prevSize;
1918
1989
  }
1919
- if (__DEV__ && !estimatedItemSize && !getEstimatedItemSize) {
1990
+ if (__DEV__ && suggestEstimatedItemSize) {
1920
1991
  if (state.timeoutSizeMessage) {
1921
1992
  clearTimeout(state.timeoutSizeMessage);
1922
1993
  }
1923
1994
  state.timeoutSizeMessage = setTimeout(() => {
1924
1995
  state.timeoutSizeMessage = void 0;
1925
- let total = 0;
1926
- let num = 0;
1927
- for (const [_, size2] of sizesKnown) {
1928
- num++;
1929
- total += size2;
1930
- }
1931
- const avg = Math.round(total / num);
1996
+ const num = sizesKnown.size;
1997
+ const avg = state.averageSizes[""].avg;
1932
1998
  console.warn(
1933
1999
  `[legend-list] estimatedItemSize or getEstimatedItemSize are not defined. Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
1934
2000
  );
@@ -1988,7 +2054,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1988
2054
  const isWidthZero = event.nativeEvent.layout.width === 0;
1989
2055
  const isHeightZero = event.nativeEvent.layout.height === 0;
1990
2056
  if (isWidthZero || isHeightZero) {
1991
- console.warn(
2057
+ warnDevOnce(
2058
+ "height0",
1992
2059
  `[legend-list] List ${isWidthZero ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
1993
2060
  );
1994
2061
  }
@@ -2155,7 +2222,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2155
2222
  alignItemsAtEnd,
2156
2223
  ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
2157
2224
  maintainVisibleContentPosition,
2158
- scrollEventThrottle: scrollEventThrottle != null ? scrollEventThrottle : Platform.OS === "web" ? 16 : void 0,
2225
+ scrollEventThrottle: Platform.OS === "web" ? 16 : void 0,
2159
2226
  waitForInitialLayout,
2160
2227
  refreshControl: refreshControl != null ? refreshControl : onRefresh && /* @__PURE__ */ React6.createElement(
2161
2228
  RefreshControl,