@legendapp/list 2.1.0-beta.5 → 2.1.0-beta.7

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
@@ -442,6 +442,10 @@ function getGlobalResizeObserver() {
442
442
  }
443
443
  var callbackMap = /* @__PURE__ */ new WeakMap();
444
444
  function createResizeObserver(element, callback) {
445
+ if (typeof ResizeObserver === "undefined") {
446
+ return () => {
447
+ };
448
+ }
445
449
  if (!element) {
446
450
  return () => {
447
451
  };
@@ -477,7 +481,7 @@ function useOnLayoutSync({
477
481
  const current = ref.current;
478
482
  const scrollableNode = (_b = (_a3 = current == null ? void 0 : current.getScrollableNode) == null ? void 0 : _a3.call(current)) != null ? _b : null;
479
483
  const element = scrollableNode || current;
480
- if (!element || !(element instanceof HTMLElement)) {
484
+ if (!element) {
481
485
  return;
482
486
  }
483
487
  const emit = (layout, fromLayoutEffect) => {
@@ -499,6 +503,9 @@ function useOnLayoutSync({
499
503
  return {};
500
504
  }
501
505
  function toLayout(rect) {
506
+ if (!rect) {
507
+ return { height: 0, width: 0, x: 0, y: 0 };
508
+ }
502
509
  return {
503
510
  height: rect.height,
504
511
  width: rect.width,
@@ -1189,6 +1196,114 @@ function calculateOffsetForIndex(ctx, state, index) {
1189
1196
  return position;
1190
1197
  }
1191
1198
 
1199
+ // src/core/checkActualChange.ts
1200
+ function checkActualChange(state, dataProp, previousData) {
1201
+ if (!previousData || !dataProp || dataProp.length !== previousData.length) {
1202
+ return true;
1203
+ }
1204
+ const {
1205
+ idCache,
1206
+ props: { keyExtractor }
1207
+ } = state;
1208
+ for (let i = 0; i < dataProp.length; i++) {
1209
+ if (dataProp[i] !== previousData[i]) {
1210
+ return true;
1211
+ }
1212
+ if (keyExtractor ? idCache[i] !== keyExtractor(previousData[i], i) : dataProp[i] !== previousData[i]) {
1213
+ return true;
1214
+ }
1215
+ }
1216
+ return false;
1217
+ }
1218
+
1219
+ // src/utils/setPaddingTop.ts
1220
+ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1221
+ if (stylePaddingTop !== void 0) {
1222
+ const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1223
+ if (stylePaddingTop < prevStylePaddingTop) {
1224
+ let prevTotalSize = peek$(ctx, "totalSize") || 0;
1225
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1226
+ state.timeoutSetPaddingTop = setTimeout(() => {
1227
+ prevTotalSize = peek$(ctx, "totalSize") || 0;
1228
+ set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1229
+ }, 16);
1230
+ }
1231
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1232
+ }
1233
+ if (alignItemsPaddingTop !== void 0) {
1234
+ set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1235
+ }
1236
+ }
1237
+
1238
+ // src/utils/updateAlignItemsPaddingTop.ts
1239
+ function updateAlignItemsPaddingTop(ctx, state) {
1240
+ const {
1241
+ scrollLength,
1242
+ props: { alignItemsAtEnd, data }
1243
+ } = state;
1244
+ if (alignItemsAtEnd) {
1245
+ let alignItemsPaddingTop = 0;
1246
+ if ((data == null ? void 0 : data.length) > 0) {
1247
+ const contentSize = getContentSize(ctx);
1248
+ alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1249
+ }
1250
+ setPaddingTop(ctx, state, { alignItemsPaddingTop });
1251
+ }
1252
+ }
1253
+
1254
+ // src/core/updateTotalSize.ts
1255
+ function updateTotalSize(ctx, state) {
1256
+ const {
1257
+ positions,
1258
+ props: { data }
1259
+ } = state;
1260
+ if (data.length === 0) {
1261
+ addTotalSize(ctx, state, null, 0);
1262
+ } else {
1263
+ const lastId = getId(state, data.length - 1);
1264
+ if (lastId !== void 0) {
1265
+ const lastPosition = positions.get(lastId);
1266
+ if (lastPosition !== void 0) {
1267
+ const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1268
+ if (lastSize !== void 0) {
1269
+ const totalSize = lastPosition + lastSize;
1270
+ addTotalSize(ctx, state, null, totalSize);
1271
+ }
1272
+ }
1273
+ }
1274
+ }
1275
+ }
1276
+ function addTotalSize(ctx, state, key, add) {
1277
+ const { alignItemsAtEnd } = state.props;
1278
+ const prevTotalSize = state.totalSize;
1279
+ if (key === null) {
1280
+ state.totalSize = add;
1281
+ if (state.timeoutSetPaddingTop) {
1282
+ clearTimeout(state.timeoutSetPaddingTop);
1283
+ state.timeoutSetPaddingTop = void 0;
1284
+ }
1285
+ } else {
1286
+ state.totalSize += add;
1287
+ }
1288
+ if (prevTotalSize !== state.totalSize) {
1289
+ set$(ctx, "totalSize", state.totalSize);
1290
+ if (alignItemsAtEnd) {
1291
+ updateAlignItemsPaddingTop(ctx, state);
1292
+ }
1293
+ }
1294
+ }
1295
+
1296
+ // src/core/setSize.ts
1297
+ function setSize(ctx, state, itemKey, size) {
1298
+ const { sizes } = state;
1299
+ const previousSize = sizes.get(itemKey);
1300
+ const diff = previousSize !== void 0 ? size - previousSize : size;
1301
+ if (diff !== 0) {
1302
+ addTotalSize(ctx, state, itemKey, diff);
1303
+ }
1304
+ sizes.set(itemKey, size);
1305
+ }
1306
+
1192
1307
  // src/utils/getItemSize.ts
1193
1308
  function getItemSize(ctx, state, key, index, data, useAverageSize) {
1194
1309
  var _a3, _b;
@@ -1226,7 +1341,7 @@ function getItemSize(ctx, state, key, index, data, useAverageSize) {
1226
1341
  if (size === void 0) {
1227
1342
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1228
1343
  }
1229
- sizes.set(key, size);
1344
+ setSize(ctx, state, key, size);
1230
1345
  return size;
1231
1346
  }
1232
1347
 
@@ -1414,10 +1529,15 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1414
1529
 
1415
1530
  // src/core/finishScrollTo.ts
1416
1531
  function finishScrollTo(ctx, state) {
1532
+ var _a3;
1417
1533
  if (state) {
1418
1534
  state.scrollHistory.length = 0;
1419
1535
  state.initialScroll = void 0;
1536
+ state.isOptimizingItemPositions = false;
1420
1537
  set$(ctx, "scrollingTo", void 0);
1538
+ if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1539
+ calculateItemsInView(ctx, state, { forceFullItemPositions: true });
1540
+ }
1421
1541
  }
1422
1542
  }
1423
1543
 
@@ -1430,7 +1550,11 @@ function scrollTo(ctx, state, params) {
1430
1550
  refScroller,
1431
1551
  props: { horizontal }
1432
1552
  } = state;
1433
- const offset = calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1553
+ let offset = calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1554
+ if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1555
+ const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
1556
+ offset = Math.min(offset, maxOffset);
1557
+ }
1434
1558
  state.scrollHistory.length = 0;
1435
1559
  if (!noScrollingTo) {
1436
1560
  set$(ctx, "scrollingTo", scrollTarget);
@@ -1601,82 +1725,43 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1601
1725
  return maxSize;
1602
1726
  }
1603
1727
 
1604
- // src/utils/setPaddingTop.ts
1605
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1606
- if (stylePaddingTop !== void 0) {
1607
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1608
- if (stylePaddingTop < prevStylePaddingTop) {
1609
- let prevTotalSize = peek$(ctx, "totalSize") || 0;
1610
- set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1611
- state.timeoutSetPaddingTop = setTimeout(() => {
1612
- prevTotalSize = peek$(ctx, "totalSize") || 0;
1613
- set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1614
- }, 16);
1615
- }
1616
- set$(ctx, "stylePaddingTop", stylePaddingTop);
1617
- }
1618
- if (alignItemsPaddingTop !== void 0) {
1619
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1620
- }
1621
- }
1622
-
1623
- // src/utils/updateAlignItemsPaddingTop.ts
1624
- function updateAlignItemsPaddingTop(ctx, state) {
1625
- const {
1626
- scrollLength,
1627
- props: { alignItemsAtEnd, data }
1628
- } = state;
1629
- if (alignItemsAtEnd) {
1630
- let alignItemsPaddingTop = 0;
1631
- if ((data == null ? void 0 : data.length) > 0) {
1632
- const contentSize = getContentSize(ctx);
1633
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1634
- }
1635
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1636
- }
1637
- }
1638
-
1639
- // src/core/updateTotalSize.ts
1640
- function updateTotalSize(ctx, state) {
1641
- const {
1642
- positions,
1643
- props: { data }
1644
- } = state;
1645
- if (data.length === 0) {
1646
- addTotalSize(ctx, state, null, 0);
1647
- } else {
1648
- const lastId = getId(state, data.length - 1);
1649
- if (lastId !== void 0) {
1650
- const lastPosition = positions.get(lastId);
1651
- if (lastPosition !== void 0) {
1652
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1653
- if (lastSize !== void 0) {
1654
- const totalSize = lastPosition + lastSize;
1655
- addTotalSize(ctx, state, null, totalSize);
1728
+ // src/utils/getScrollVelocity.ts
1729
+ var getScrollVelocity = (state) => {
1730
+ const { scrollHistory } = state;
1731
+ let velocity = 0;
1732
+ if (scrollHistory.length >= 1) {
1733
+ const newest = scrollHistory[scrollHistory.length - 1];
1734
+ let oldest;
1735
+ let start = 0;
1736
+ const now = Date.now();
1737
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
1738
+ const entry = scrollHistory[i];
1739
+ const nextEntry = scrollHistory[i + 1];
1740
+ if (i > 0) {
1741
+ const prevEntry = scrollHistory[i - 1];
1742
+ const prevDirection = entry.scroll - prevEntry.scroll;
1743
+ const currentDirection = nextEntry.scroll - entry.scroll;
1744
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1745
+ start = i;
1746
+ break;
1656
1747
  }
1657
1748
  }
1658
1749
  }
1659
- }
1660
- }
1661
- function addTotalSize(ctx, state, key, add) {
1662
- const { alignItemsAtEnd } = state.props;
1663
- const prevTotalSize = state.totalSize;
1664
- if (key === null) {
1665
- state.totalSize = add;
1666
- if (state.timeoutSetPaddingTop) {
1667
- clearTimeout(state.timeoutSetPaddingTop);
1668
- state.timeoutSetPaddingTop = void 0;
1750
+ for (let i = start; i < scrollHistory.length - 1; i++) {
1751
+ const entry = scrollHistory[i];
1752
+ if (now - entry.time <= 1e3) {
1753
+ oldest = entry;
1754
+ break;
1755
+ }
1669
1756
  }
1670
- } else {
1671
- state.totalSize += add;
1672
- }
1673
- if (prevTotalSize !== state.totalSize) {
1674
- set$(ctx, "totalSize", state.totalSize);
1675
- if (alignItemsAtEnd) {
1676
- updateAlignItemsPaddingTop(ctx, state);
1757
+ if (oldest && oldest !== newest) {
1758
+ const scrollDiff = newest.scroll - oldest.scroll;
1759
+ const timeDiff = newest.time - oldest.time;
1760
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1677
1761
  }
1678
1762
  }
1679
- }
1763
+ return velocity;
1764
+ };
1680
1765
 
1681
1766
  // src/utils/updateSnapToOffsets.ts
1682
1767
  function updateSnapToOffsets(ctx, state) {
@@ -1694,7 +1779,11 @@ function updateSnapToOffsets(ctx, state) {
1694
1779
  }
1695
1780
 
1696
1781
  // src/core/updateItemPositions.ts
1697
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered } = { scrollBottomBuffered: -1, startIndex: 0 }) {
1782
+ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false } = {
1783
+ forceFullUpdate: false,
1784
+ scrollBottomBuffered: -1,
1785
+ startIndex: 0
1786
+ }) {
1698
1787
  var _a3, _b, _c, _d;
1699
1788
  const {
1700
1789
  columns,
@@ -1710,6 +1799,8 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1710
1799
  const scrollingTo = peek$(ctx, "scrollingTo");
1711
1800
  const hasColumns = numColumns > 1;
1712
1801
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1802
+ const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1803
+ state.isOptimizingItemPositions = shouldOptimize;
1713
1804
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1714
1805
  const useAverageSize = enableAverages && !getEstimatedItemSize;
1715
1806
  let currentRowTop = 0;
@@ -1737,11 +1828,11 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1737
1828
  let didBreakEarly = false;
1738
1829
  let breakAt;
1739
1830
  for (let i = startIndex; i < dataLength; i++) {
1740
- if (breakAt && i > breakAt) {
1831
+ if (shouldOptimize && breakAt !== void 0 && i > breakAt) {
1741
1832
  didBreakEarly = true;
1742
1833
  break;
1743
1834
  }
1744
- if (breakAt === void 0 && !scrollingTo && !dataChanged && currentRowTop > maxVisibleArea) {
1835
+ if (shouldOptimize && breakAt === void 0 && !scrollingTo && !dataChanged && currentRowTop > maxVisibleArea) {
1745
1836
  const itemsPerRow = hasColumns ? numColumns : 1;
1746
1837
  breakAt = i + itemsPerRow + 10;
1747
1838
  }
@@ -2119,44 +2210,6 @@ function comparatorByDistance(a, b) {
2119
2210
  return b.distance - a.distance;
2120
2211
  }
2121
2212
 
2122
- // src/utils/getScrollVelocity.ts
2123
- var getScrollVelocity = (state) => {
2124
- const { scrollHistory } = state;
2125
- let velocity = 0;
2126
- if (scrollHistory.length >= 1) {
2127
- const newest = scrollHistory[scrollHistory.length - 1];
2128
- let oldest;
2129
- let start = 0;
2130
- const now = Date.now();
2131
- for (let i = 0; i < scrollHistory.length - 1; i++) {
2132
- const entry = scrollHistory[i];
2133
- const nextEntry = scrollHistory[i + 1];
2134
- if (i > 0) {
2135
- const prevEntry = scrollHistory[i - 1];
2136
- const prevDirection = entry.scroll - prevEntry.scroll;
2137
- const currentDirection = nextEntry.scroll - entry.scroll;
2138
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
2139
- start = i;
2140
- break;
2141
- }
2142
- }
2143
- }
2144
- for (let i = start; i < scrollHistory.length - 1; i++) {
2145
- const entry = scrollHistory[i];
2146
- if (now - entry.time <= 1e3) {
2147
- oldest = entry;
2148
- break;
2149
- }
2150
- }
2151
- if (oldest && oldest !== newest) {
2152
- const scrollDiff = newest.scroll - oldest.scroll;
2153
- const timeDiff = newest.time - oldest.time;
2154
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
2155
- }
2156
- }
2157
- return velocity;
2158
- };
2159
-
2160
2213
  // src/core/scrollToIndex.ts
2161
2214
  function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2162
2215
  if (index >= state.props.data.length) {
@@ -2276,14 +2329,15 @@ function calculateItemsInView(ctx, state, params = {}) {
2276
2329
  enableScrollForNextCalculateItemsInView,
2277
2330
  idCache,
2278
2331
  indexByKey,
2332
+ initialScroll,
2279
2333
  minIndexSizeChanged,
2280
2334
  positions,
2335
+ props: { getItemType, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer },
2281
2336
  scrollForNextCalculateItemsInView,
2282
2337
  scrollLength,
2283
2338
  sizes,
2284
2339
  startBufferedId: startBufferedIdOrig,
2285
- viewabilityConfigCallbackPairs,
2286
- props: { getItemType, initialScroll, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer }
2340
+ viewabilityConfigCallbackPairs
2287
2341
  } = state;
2288
2342
  const { data } = state.props;
2289
2343
  const stickyIndicesArr = state.props.stickyIndicesArr || [];
@@ -2295,7 +2349,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2295
2349
  const totalSize = peek$(ctx, "totalSize");
2296
2350
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
2297
2351
  const numColumns = peek$(ctx, "numColumns");
2298
- const { dataChanged, doMVCP } = params;
2352
+ const { dataChanged, doMVCP, forceFullItemPositions } = params;
2299
2353
  const speed = getScrollVelocity(state);
2300
2354
  const scrollExtra = 0;
2301
2355
  const { queuedInitialLayout } = state;
@@ -2349,7 +2403,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2349
2403
  positions.clear();
2350
2404
  }
2351
2405
  const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2352
- updateItemPositions(ctx, state, dataChanged, { scrollBottomBuffered, startIndex });
2406
+ updateItemPositions(ctx, state, dataChanged, {
2407
+ forceFullUpdate: !!forceFullItemPositions,
2408
+ scrollBottomBuffered,
2409
+ startIndex
2410
+ });
2353
2411
  if (minIndexSizeChanged !== void 0) {
2354
2412
  state.minIndexSizeChanged = void 0;
2355
2413
  }
@@ -2672,25 +2730,23 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2672
2730
  }
2673
2731
 
2674
2732
  // src/core/checkResetContainers.ts
2675
- function checkResetContainers(ctx, state, isFirst, dataProp) {
2676
- if (state) {
2677
- if (!isFirst && state.props.data !== dataProp) {
2678
- updateAveragesOnDataChange(state, state.props.data, dataProp);
2679
- }
2680
- const { maintainScrollAtEnd } = state.props;
2681
- if (!isFirst) {
2682
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2683
- const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2684
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2685
- if (!didMaintainScrollAtEnd && dataProp.length > state.props.data.length) {
2686
- state.isEndReached = false;
2687
- }
2688
- if (!didMaintainScrollAtEnd) {
2689
- checkAtTop(state);
2690
- checkAtBottom(ctx, state);
2691
- }
2692
- }
2733
+ function checkResetContainers(ctx, state, dataProp) {
2734
+ const { previousData } = state;
2735
+ if (previousData) {
2736
+ updateAveragesOnDataChange(state, previousData, dataProp);
2737
+ }
2738
+ const { maintainScrollAtEnd } = state.props;
2739
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2740
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2741
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2742
+ if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2743
+ state.isEndReached = false;
2693
2744
  }
2745
+ if (!didMaintainScrollAtEnd) {
2746
+ checkAtTop(state);
2747
+ checkAtBottom(ctx, state);
2748
+ }
2749
+ delete state.previousData;
2694
2750
  }
2695
2751
 
2696
2752
  // src/core/doInitialAllocateContainers.ts
@@ -2731,7 +2787,7 @@ function doInitialAllocateContainers(ctx, state) {
2731
2787
  set$(ctx, "numContainers", numContainers);
2732
2788
  set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
2733
2789
  if (state.lastLayout) {
2734
- if (state.props.initialScroll) {
2790
+ if (state.initialScroll) {
2735
2791
  requestAnimationFrame(() => {
2736
2792
  calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2737
2793
  });
@@ -2897,7 +2953,6 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2897
2953
  if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2898
2954
  shouldMaintainScrollAtEnd = true;
2899
2955
  }
2900
- addTotalSize(ctx, state, itemKey, diff);
2901
2956
  onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2902
2957
  index,
2903
2958
  itemData: state.props.data[index],
@@ -2962,7 +3017,7 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2962
3017
  averages.num++;
2963
3018
  }
2964
3019
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2965
- sizes.set(itemKey, size);
3020
+ setSize(ctx, state, itemKey, size);
2966
3021
  return size - prevSize;
2967
3022
  }
2968
3023
  return 0;
@@ -3117,6 +3172,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3117
3172
  getItemType,
3118
3173
  horizontal,
3119
3174
  initialContainerPoolRatio = 2,
3175
+ initialScrollAtEnd = false,
3120
3176
  initialScrollIndex: initialScrollIndexProp,
3121
3177
  initialScrollOffset: initialScrollOffsetProp,
3122
3178
  itemsAreEqual,
@@ -3156,7 +3212,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3156
3212
  ...rest
3157
3213
  } = props;
3158
3214
  const [renderNum, setRenderNum] = React3.useState(0);
3159
- const initialScrollProp = initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3215
+ const initialScrollProp = initialScrollAtEnd ? { index: dataProp.length - 1, viewOffset: 0 } : initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3160
3216
  const [canRender, setCanRender] = React3__namespace.useState(!IsNewArchitecture);
3161
3217
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3162
3218
  const style = { ...StyleSheet.flatten(styleProp) };
@@ -3180,6 +3236,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3180
3236
  containerItemKeys: /* @__PURE__ */ new Set(),
3181
3237
  containerItemTypes: /* @__PURE__ */ new Map(),
3182
3238
  dataChangeNeedsScrollUpdate: false,
3239
+ didColumnsChange: false,
3240
+ didDataChange: false,
3183
3241
  enableScrollForNextCalculateItemsInView: true,
3184
3242
  endBuffered: -1,
3185
3243
  endNoBuffer: -1,
@@ -3192,6 +3250,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3192
3250
  isAtEnd: false,
3193
3251
  isAtStart: false,
3194
3252
  isEndReached: false,
3253
+ isFirst: true,
3254
+ isOptimizingItemPositions: false,
3195
3255
  isStartReached: false,
3196
3256
  lastBatchingAction: Date.now(),
3197
3257
  lastLayout: void 0,
@@ -3230,10 +3290,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3230
3290
  refState.current = ctx.internalState;
3231
3291
  }
3232
3292
  const state = refState.current;
3233
- const isFirst = !state.props.renderItem;
3234
- const didDataChange = state.props.data !== dataProp;
3235
- if (didDataChange) {
3293
+ const isFirstLocal = state.isFirst;
3294
+ state.didColumnsChange = numColumnsProp !== state.props.numColumns;
3295
+ const didDataChangeLocal = state.props.data !== dataProp && checkActualChange(state, dataProp, state.props.data);
3296
+ if (didDataChangeLocal) {
3236
3297
  state.dataChangeNeedsScrollUpdate = true;
3298
+ state.didDataChange = true;
3299
+ state.previousData = state.props.data;
3237
3300
  }
3238
3301
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3239
3302
  state.props = {
@@ -3292,7 +3355,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3292
3355
  requestAdjust(ctx, state, paddingDiff);
3293
3356
  }
3294
3357
  };
3295
- if (isFirst) {
3358
+ if (isFirstLocal) {
3296
3359
  initializeStateVars();
3297
3360
  updateItemPositions(
3298
3361
  ctx,
@@ -3310,28 +3373,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3310
3373
  initialContentOffset2 += calculateOffsetForIndex(ctx, state, index);
3311
3374
  }
3312
3375
  refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
3313
- if (initialContentOffset2 > 0) {
3314
- scrollTo(ctx, state, {
3315
- animated: false,
3316
- index,
3317
- isInitialScroll: true,
3318
- offset: initialContentOffset2,
3319
- viewPosition: index === dataProp.length - 1 ? 1 : 0
3320
- });
3321
- }
3322
3376
  return initialContentOffset2;
3323
3377
  }
3324
3378
  return 0;
3325
3379
  }, [renderNum]);
3326
- if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
3380
+ if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3327
3381
  refState.current.lastBatchingAction = Date.now();
3328
- if (!keyExtractorProp && !isFirst && didDataChange) {
3382
+ if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3329
3383
  IS_DEV && warnDevOnce(
3330
3384
  "keyExtractor",
3331
3385
  "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."
3332
3386
  );
3333
3387
  refState.current.sizes.clear();
3334
3388
  refState.current.positions.clear();
3389
+ refState.current.totalSize = 0;
3390
+ set$(ctx, "totalSize", 0);
3335
3391
  }
3336
3392
  }
3337
3393
  const onLayoutHeader = React3.useCallback((rect, fromLayoutEffect) => {
@@ -3346,22 +3402,41 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3346
3402
  }
3347
3403
  }
3348
3404
  }, []);
3405
+ const doInitialScroll = React3.useCallback(() => {
3406
+ const initialScroll = state.initialScroll;
3407
+ if (initialScroll) {
3408
+ scrollTo(ctx, state, { animated: false, offset: initialContentOffset, ...state.initialScroll || {} });
3409
+ }
3410
+ }, [initialContentOffset, state.initialScroll]);
3411
+ const onLayoutChange = React3.useCallback((layout) => {
3412
+ doInitialScroll();
3413
+ handleLayout(ctx, state, layout, setCanRender);
3414
+ }, []);
3415
+ const { onLayout } = useOnLayoutSync({
3416
+ onLayoutChange,
3417
+ onLayoutProp,
3418
+ ref: refScroller
3419
+ // the type of ScrollView doesn't include measure?
3420
+ });
3349
3421
  React3.useLayoutEffect(() => {
3350
3422
  if (snapToIndices) {
3351
3423
  updateSnapToOffsets(ctx, state);
3352
3424
  }
3353
3425
  }, [snapToIndices]);
3354
3426
  React3.useLayoutEffect(() => {
3355
- const didAllocateContainers = dataProp.length > 0 && doInitialAllocateContainers(ctx, state);
3356
- if (!didAllocateContainers) {
3357
- checkResetContainers(
3358
- ctx,
3359
- state,
3360
- /*isFirst*/
3361
- isFirst,
3362
- dataProp
3363
- );
3427
+ const {
3428
+ didColumnsChange,
3429
+ didDataChange,
3430
+ isFirst,
3431
+ props: { data }
3432
+ } = state;
3433
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3434
+ if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3435
+ checkResetContainers(ctx, state, data);
3364
3436
  }
3437
+ state.didColumnsChange = false;
3438
+ state.didDataChange = false;
3439
+ state.isFirst = false;
3365
3440
  }, [dataProp, numColumnsProp]);
3366
3441
  React3.useLayoutEffect(() => {
3367
3442
  set$(ctx, "extraData", extraData);
@@ -3381,15 +3456,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3381
3456
  state.viewabilityConfigCallbackPairs = viewability;
3382
3457
  state.enableScrollForNextCalculateItemsInView = !viewability;
3383
3458
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3384
- const onLayoutChange = React3.useCallback((layout) => {
3385
- handleLayout(ctx, state, layout, setCanRender);
3386
- }, []);
3387
- const { onLayout } = useOnLayoutSync({
3388
- onLayoutChange,
3389
- onLayoutProp,
3390
- ref: refScroller
3391
- // the type of ScrollView doesn't include measure?
3392
- });
3393
3459
  React3.useImperativeHandle(forwardedRef, () => {
3394
3460
  const scrollIndexIntoView = (options) => {
3395
3461
  const state2 = refState.current;
@@ -3473,12 +3539,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3473
3539
  };
3474
3540
  }, []);
3475
3541
  {
3476
- React3.useEffect(() => {
3477
- const { initialScroll } = refState.current;
3478
- if (initialContentOffset) {
3479
- scrollTo(ctx, state, { animated: false, offset: initialContentOffset, ...initialScroll || {} });
3480
- }
3481
- }, []);
3542
+ React3.useEffect(doInitialScroll, []);
3482
3543
  }
3483
3544
  const fns = React3.useMemo(
3484
3545
  () => ({