@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.mjs CHANGED
@@ -421,6 +421,10 @@ function getGlobalResizeObserver() {
421
421
  }
422
422
  var callbackMap = /* @__PURE__ */ new WeakMap();
423
423
  function createResizeObserver(element, callback) {
424
+ if (typeof ResizeObserver === "undefined") {
425
+ return () => {
426
+ };
427
+ }
424
428
  if (!element) {
425
429
  return () => {
426
430
  };
@@ -456,7 +460,7 @@ function useOnLayoutSync({
456
460
  const current = ref.current;
457
461
  const scrollableNode = (_b = (_a3 = current == null ? void 0 : current.getScrollableNode) == null ? void 0 : _a3.call(current)) != null ? _b : null;
458
462
  const element = scrollableNode || current;
459
- if (!element || !(element instanceof HTMLElement)) {
463
+ if (!element) {
460
464
  return;
461
465
  }
462
466
  const emit = (layout, fromLayoutEffect) => {
@@ -478,6 +482,9 @@ function useOnLayoutSync({
478
482
  return {};
479
483
  }
480
484
  function toLayout(rect) {
485
+ if (!rect) {
486
+ return { height: 0, width: 0, x: 0, y: 0 };
487
+ }
481
488
  return {
482
489
  height: rect.height,
483
490
  width: rect.width,
@@ -1168,6 +1175,114 @@ function calculateOffsetForIndex(ctx, state, index) {
1168
1175
  return position;
1169
1176
  }
1170
1177
 
1178
+ // src/core/checkActualChange.ts
1179
+ function checkActualChange(state, dataProp, previousData) {
1180
+ if (!previousData || !dataProp || dataProp.length !== previousData.length) {
1181
+ return true;
1182
+ }
1183
+ const {
1184
+ idCache,
1185
+ props: { keyExtractor }
1186
+ } = state;
1187
+ for (let i = 0; i < dataProp.length; i++) {
1188
+ if (dataProp[i] !== previousData[i]) {
1189
+ return true;
1190
+ }
1191
+ if (keyExtractor ? idCache[i] !== keyExtractor(previousData[i], i) : dataProp[i] !== previousData[i]) {
1192
+ return true;
1193
+ }
1194
+ }
1195
+ return false;
1196
+ }
1197
+
1198
+ // src/utils/setPaddingTop.ts
1199
+ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1200
+ if (stylePaddingTop !== void 0) {
1201
+ const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1202
+ if (stylePaddingTop < prevStylePaddingTop) {
1203
+ let prevTotalSize = peek$(ctx, "totalSize") || 0;
1204
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1205
+ state.timeoutSetPaddingTop = setTimeout(() => {
1206
+ prevTotalSize = peek$(ctx, "totalSize") || 0;
1207
+ set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1208
+ }, 16);
1209
+ }
1210
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1211
+ }
1212
+ if (alignItemsPaddingTop !== void 0) {
1213
+ set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1214
+ }
1215
+ }
1216
+
1217
+ // src/utils/updateAlignItemsPaddingTop.ts
1218
+ function updateAlignItemsPaddingTop(ctx, state) {
1219
+ const {
1220
+ scrollLength,
1221
+ props: { alignItemsAtEnd, data }
1222
+ } = state;
1223
+ if (alignItemsAtEnd) {
1224
+ let alignItemsPaddingTop = 0;
1225
+ if ((data == null ? void 0 : data.length) > 0) {
1226
+ const contentSize = getContentSize(ctx);
1227
+ alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1228
+ }
1229
+ setPaddingTop(ctx, state, { alignItemsPaddingTop });
1230
+ }
1231
+ }
1232
+
1233
+ // src/core/updateTotalSize.ts
1234
+ function updateTotalSize(ctx, state) {
1235
+ const {
1236
+ positions,
1237
+ props: { data }
1238
+ } = state;
1239
+ if (data.length === 0) {
1240
+ addTotalSize(ctx, state, null, 0);
1241
+ } else {
1242
+ const lastId = getId(state, data.length - 1);
1243
+ if (lastId !== void 0) {
1244
+ const lastPosition = positions.get(lastId);
1245
+ if (lastPosition !== void 0) {
1246
+ const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1247
+ if (lastSize !== void 0) {
1248
+ const totalSize = lastPosition + lastSize;
1249
+ addTotalSize(ctx, state, null, totalSize);
1250
+ }
1251
+ }
1252
+ }
1253
+ }
1254
+ }
1255
+ function addTotalSize(ctx, state, key, add) {
1256
+ const { alignItemsAtEnd } = state.props;
1257
+ const prevTotalSize = state.totalSize;
1258
+ if (key === null) {
1259
+ state.totalSize = add;
1260
+ if (state.timeoutSetPaddingTop) {
1261
+ clearTimeout(state.timeoutSetPaddingTop);
1262
+ state.timeoutSetPaddingTop = void 0;
1263
+ }
1264
+ } else {
1265
+ state.totalSize += add;
1266
+ }
1267
+ if (prevTotalSize !== state.totalSize) {
1268
+ set$(ctx, "totalSize", state.totalSize);
1269
+ if (alignItemsAtEnd) {
1270
+ updateAlignItemsPaddingTop(ctx, state);
1271
+ }
1272
+ }
1273
+ }
1274
+
1275
+ // src/core/setSize.ts
1276
+ function setSize(ctx, state, itemKey, size) {
1277
+ const { sizes } = state;
1278
+ const previousSize = sizes.get(itemKey);
1279
+ const diff = previousSize !== void 0 ? size - previousSize : size;
1280
+ if (diff !== 0) {
1281
+ addTotalSize(ctx, state, itemKey, diff);
1282
+ }
1283
+ sizes.set(itemKey, size);
1284
+ }
1285
+
1171
1286
  // src/utils/getItemSize.ts
1172
1287
  function getItemSize(ctx, state, key, index, data, useAverageSize) {
1173
1288
  var _a3, _b;
@@ -1205,7 +1320,7 @@ function getItemSize(ctx, state, key, index, data, useAverageSize) {
1205
1320
  if (size === void 0) {
1206
1321
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1207
1322
  }
1208
- sizes.set(key, size);
1323
+ setSize(ctx, state, key, size);
1209
1324
  return size;
1210
1325
  }
1211
1326
 
@@ -1393,10 +1508,15 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1393
1508
 
1394
1509
  // src/core/finishScrollTo.ts
1395
1510
  function finishScrollTo(ctx, state) {
1511
+ var _a3;
1396
1512
  if (state) {
1397
1513
  state.scrollHistory.length = 0;
1398
1514
  state.initialScroll = void 0;
1515
+ state.isOptimizingItemPositions = false;
1399
1516
  set$(ctx, "scrollingTo", void 0);
1517
+ if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1518
+ calculateItemsInView(ctx, state, { forceFullItemPositions: true });
1519
+ }
1400
1520
  }
1401
1521
  }
1402
1522
 
@@ -1409,7 +1529,11 @@ function scrollTo(ctx, state, params) {
1409
1529
  refScroller,
1410
1530
  props: { horizontal }
1411
1531
  } = state;
1412
- const offset = calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1532
+ let offset = calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1533
+ if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1534
+ const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
1535
+ offset = Math.min(offset, maxOffset);
1536
+ }
1413
1537
  state.scrollHistory.length = 0;
1414
1538
  if (!noScrollingTo) {
1415
1539
  set$(ctx, "scrollingTo", scrollTarget);
@@ -1580,82 +1704,43 @@ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1580
1704
  return maxSize;
1581
1705
  }
1582
1706
 
1583
- // src/utils/setPaddingTop.ts
1584
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1585
- if (stylePaddingTop !== void 0) {
1586
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1587
- if (stylePaddingTop < prevStylePaddingTop) {
1588
- let prevTotalSize = peek$(ctx, "totalSize") || 0;
1589
- set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1590
- state.timeoutSetPaddingTop = setTimeout(() => {
1591
- prevTotalSize = peek$(ctx, "totalSize") || 0;
1592
- set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1593
- }, 16);
1594
- }
1595
- set$(ctx, "stylePaddingTop", stylePaddingTop);
1596
- }
1597
- if (alignItemsPaddingTop !== void 0) {
1598
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1599
- }
1600
- }
1601
-
1602
- // src/utils/updateAlignItemsPaddingTop.ts
1603
- function updateAlignItemsPaddingTop(ctx, state) {
1604
- const {
1605
- scrollLength,
1606
- props: { alignItemsAtEnd, data }
1607
- } = state;
1608
- if (alignItemsAtEnd) {
1609
- let alignItemsPaddingTop = 0;
1610
- if ((data == null ? void 0 : data.length) > 0) {
1611
- const contentSize = getContentSize(ctx);
1612
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1613
- }
1614
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1615
- }
1616
- }
1617
-
1618
- // src/core/updateTotalSize.ts
1619
- function updateTotalSize(ctx, state) {
1620
- const {
1621
- positions,
1622
- props: { data }
1623
- } = state;
1624
- if (data.length === 0) {
1625
- addTotalSize(ctx, state, null, 0);
1626
- } else {
1627
- const lastId = getId(state, data.length - 1);
1628
- if (lastId !== void 0) {
1629
- const lastPosition = positions.get(lastId);
1630
- if (lastPosition !== void 0) {
1631
- const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1632
- if (lastSize !== void 0) {
1633
- const totalSize = lastPosition + lastSize;
1634
- addTotalSize(ctx, state, null, totalSize);
1707
+ // src/utils/getScrollVelocity.ts
1708
+ var getScrollVelocity = (state) => {
1709
+ const { scrollHistory } = state;
1710
+ let velocity = 0;
1711
+ if (scrollHistory.length >= 1) {
1712
+ const newest = scrollHistory[scrollHistory.length - 1];
1713
+ let oldest;
1714
+ let start = 0;
1715
+ const now = Date.now();
1716
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
1717
+ const entry = scrollHistory[i];
1718
+ const nextEntry = scrollHistory[i + 1];
1719
+ if (i > 0) {
1720
+ const prevEntry = scrollHistory[i - 1];
1721
+ const prevDirection = entry.scroll - prevEntry.scroll;
1722
+ const currentDirection = nextEntry.scroll - entry.scroll;
1723
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1724
+ start = i;
1725
+ break;
1635
1726
  }
1636
1727
  }
1637
1728
  }
1638
- }
1639
- }
1640
- function addTotalSize(ctx, state, key, add) {
1641
- const { alignItemsAtEnd } = state.props;
1642
- const prevTotalSize = state.totalSize;
1643
- if (key === null) {
1644
- state.totalSize = add;
1645
- if (state.timeoutSetPaddingTop) {
1646
- clearTimeout(state.timeoutSetPaddingTop);
1647
- state.timeoutSetPaddingTop = void 0;
1729
+ for (let i = start; i < scrollHistory.length - 1; i++) {
1730
+ const entry = scrollHistory[i];
1731
+ if (now - entry.time <= 1e3) {
1732
+ oldest = entry;
1733
+ break;
1734
+ }
1648
1735
  }
1649
- } else {
1650
- state.totalSize += add;
1651
- }
1652
- if (prevTotalSize !== state.totalSize) {
1653
- set$(ctx, "totalSize", state.totalSize);
1654
- if (alignItemsAtEnd) {
1655
- updateAlignItemsPaddingTop(ctx, state);
1736
+ if (oldest && oldest !== newest) {
1737
+ const scrollDiff = newest.scroll - oldest.scroll;
1738
+ const timeDiff = newest.time - oldest.time;
1739
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1656
1740
  }
1657
1741
  }
1658
- }
1742
+ return velocity;
1743
+ };
1659
1744
 
1660
1745
  // src/utils/updateSnapToOffsets.ts
1661
1746
  function updateSnapToOffsets(ctx, state) {
@@ -1673,7 +1758,11 @@ function updateSnapToOffsets(ctx, state) {
1673
1758
  }
1674
1759
 
1675
1760
  // src/core/updateItemPositions.ts
1676
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered } = { scrollBottomBuffered: -1, startIndex: 0 }) {
1761
+ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false } = {
1762
+ forceFullUpdate: false,
1763
+ scrollBottomBuffered: -1,
1764
+ startIndex: 0
1765
+ }) {
1677
1766
  var _a3, _b, _c, _d;
1678
1767
  const {
1679
1768
  columns,
@@ -1689,6 +1778,8 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1689
1778
  const scrollingTo = peek$(ctx, "scrollingTo");
1690
1779
  const hasColumns = numColumns > 1;
1691
1780
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1781
+ const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1782
+ state.isOptimizingItemPositions = shouldOptimize;
1692
1783
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1693
1784
  const useAverageSize = enableAverages && !getEstimatedItemSize;
1694
1785
  let currentRowTop = 0;
@@ -1716,11 +1807,11 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1716
1807
  let didBreakEarly = false;
1717
1808
  let breakAt;
1718
1809
  for (let i = startIndex; i < dataLength; i++) {
1719
- if (breakAt && i > breakAt) {
1810
+ if (shouldOptimize && breakAt !== void 0 && i > breakAt) {
1720
1811
  didBreakEarly = true;
1721
1812
  break;
1722
1813
  }
1723
- if (breakAt === void 0 && !scrollingTo && !dataChanged && currentRowTop > maxVisibleArea) {
1814
+ if (shouldOptimize && breakAt === void 0 && !scrollingTo && !dataChanged && currentRowTop > maxVisibleArea) {
1724
1815
  const itemsPerRow = hasColumns ? numColumns : 1;
1725
1816
  breakAt = i + itemsPerRow + 10;
1726
1817
  }
@@ -2098,44 +2189,6 @@ function comparatorByDistance(a, b) {
2098
2189
  return b.distance - a.distance;
2099
2190
  }
2100
2191
 
2101
- // src/utils/getScrollVelocity.ts
2102
- var getScrollVelocity = (state) => {
2103
- const { scrollHistory } = state;
2104
- let velocity = 0;
2105
- if (scrollHistory.length >= 1) {
2106
- const newest = scrollHistory[scrollHistory.length - 1];
2107
- let oldest;
2108
- let start = 0;
2109
- const now = Date.now();
2110
- for (let i = 0; i < scrollHistory.length - 1; i++) {
2111
- const entry = scrollHistory[i];
2112
- const nextEntry = scrollHistory[i + 1];
2113
- if (i > 0) {
2114
- const prevEntry = scrollHistory[i - 1];
2115
- const prevDirection = entry.scroll - prevEntry.scroll;
2116
- const currentDirection = nextEntry.scroll - entry.scroll;
2117
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
2118
- start = i;
2119
- break;
2120
- }
2121
- }
2122
- }
2123
- for (let i = start; i < scrollHistory.length - 1; i++) {
2124
- const entry = scrollHistory[i];
2125
- if (now - entry.time <= 1e3) {
2126
- oldest = entry;
2127
- break;
2128
- }
2129
- }
2130
- if (oldest && oldest !== newest) {
2131
- const scrollDiff = newest.scroll - oldest.scroll;
2132
- const timeDiff = newest.time - oldest.time;
2133
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
2134
- }
2135
- }
2136
- return velocity;
2137
- };
2138
-
2139
2192
  // src/core/scrollToIndex.ts
2140
2193
  function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2141
2194
  if (index >= state.props.data.length) {
@@ -2255,14 +2308,15 @@ function calculateItemsInView(ctx, state, params = {}) {
2255
2308
  enableScrollForNextCalculateItemsInView,
2256
2309
  idCache,
2257
2310
  indexByKey,
2311
+ initialScroll,
2258
2312
  minIndexSizeChanged,
2259
2313
  positions,
2314
+ props: { getItemType, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer },
2260
2315
  scrollForNextCalculateItemsInView,
2261
2316
  scrollLength,
2262
2317
  sizes,
2263
2318
  startBufferedId: startBufferedIdOrig,
2264
- viewabilityConfigCallbackPairs,
2265
- props: { getItemType, initialScroll, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer }
2319
+ viewabilityConfigCallbackPairs
2266
2320
  } = state;
2267
2321
  const { data } = state.props;
2268
2322
  const stickyIndicesArr = state.props.stickyIndicesArr || [];
@@ -2274,7 +2328,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2274
2328
  const totalSize = peek$(ctx, "totalSize");
2275
2329
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
2276
2330
  const numColumns = peek$(ctx, "numColumns");
2277
- const { dataChanged, doMVCP } = params;
2331
+ const { dataChanged, doMVCP, forceFullItemPositions } = params;
2278
2332
  const speed = getScrollVelocity(state);
2279
2333
  const scrollExtra = 0;
2280
2334
  const { queuedInitialLayout } = state;
@@ -2328,7 +2382,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2328
2382
  positions.clear();
2329
2383
  }
2330
2384
  const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2331
- updateItemPositions(ctx, state, dataChanged, { scrollBottomBuffered, startIndex });
2385
+ updateItemPositions(ctx, state, dataChanged, {
2386
+ forceFullUpdate: !!forceFullItemPositions,
2387
+ scrollBottomBuffered,
2388
+ startIndex
2389
+ });
2332
2390
  if (minIndexSizeChanged !== void 0) {
2333
2391
  state.minIndexSizeChanged = void 0;
2334
2392
  }
@@ -2651,25 +2709,23 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2651
2709
  }
2652
2710
 
2653
2711
  // src/core/checkResetContainers.ts
2654
- function checkResetContainers(ctx, state, isFirst, dataProp) {
2655
- if (state) {
2656
- if (!isFirst && state.props.data !== dataProp) {
2657
- updateAveragesOnDataChange(state, state.props.data, dataProp);
2658
- }
2659
- const { maintainScrollAtEnd } = state.props;
2660
- if (!isFirst) {
2661
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2662
- const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2663
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2664
- if (!didMaintainScrollAtEnd && dataProp.length > state.props.data.length) {
2665
- state.isEndReached = false;
2666
- }
2667
- if (!didMaintainScrollAtEnd) {
2668
- checkAtTop(state);
2669
- checkAtBottom(ctx, state);
2670
- }
2671
- }
2712
+ function checkResetContainers(ctx, state, dataProp) {
2713
+ const { previousData } = state;
2714
+ if (previousData) {
2715
+ updateAveragesOnDataChange(state, previousData, dataProp);
2716
+ }
2717
+ const { maintainScrollAtEnd } = state.props;
2718
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2719
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2720
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2721
+ if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2722
+ state.isEndReached = false;
2672
2723
  }
2724
+ if (!didMaintainScrollAtEnd) {
2725
+ checkAtTop(state);
2726
+ checkAtBottom(ctx, state);
2727
+ }
2728
+ delete state.previousData;
2673
2729
  }
2674
2730
 
2675
2731
  // src/core/doInitialAllocateContainers.ts
@@ -2710,7 +2766,7 @@ function doInitialAllocateContainers(ctx, state) {
2710
2766
  set$(ctx, "numContainers", numContainers);
2711
2767
  set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
2712
2768
  if (state.lastLayout) {
2713
- if (state.props.initialScroll) {
2769
+ if (state.initialScroll) {
2714
2770
  requestAnimationFrame(() => {
2715
2771
  calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2716
2772
  });
@@ -2876,7 +2932,6 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2876
2932
  if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2877
2933
  shouldMaintainScrollAtEnd = true;
2878
2934
  }
2879
- addTotalSize(ctx, state, itemKey, diff);
2880
2935
  onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2881
2936
  index,
2882
2937
  itemData: state.props.data[index],
@@ -2941,7 +2996,7 @@ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2941
2996
  averages.num++;
2942
2997
  }
2943
2998
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2944
- sizes.set(itemKey, size);
2999
+ setSize(ctx, state, itemKey, size);
2945
3000
  return size - prevSize;
2946
3001
  }
2947
3002
  return 0;
@@ -3096,6 +3151,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3096
3151
  getItemType,
3097
3152
  horizontal,
3098
3153
  initialContainerPoolRatio = 2,
3154
+ initialScrollAtEnd = false,
3099
3155
  initialScrollIndex: initialScrollIndexProp,
3100
3156
  initialScrollOffset: initialScrollOffsetProp,
3101
3157
  itemsAreEqual,
@@ -3135,7 +3191,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3135
3191
  ...rest
3136
3192
  } = props;
3137
3193
  const [renderNum, setRenderNum] = useState(0);
3138
- const initialScrollProp = initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3194
+ 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;
3139
3195
  const [canRender, setCanRender] = React3.useState(!IsNewArchitecture);
3140
3196
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3141
3197
  const style = { ...StyleSheet.flatten(styleProp) };
@@ -3159,6 +3215,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3159
3215
  containerItemKeys: /* @__PURE__ */ new Set(),
3160
3216
  containerItemTypes: /* @__PURE__ */ new Map(),
3161
3217
  dataChangeNeedsScrollUpdate: false,
3218
+ didColumnsChange: false,
3219
+ didDataChange: false,
3162
3220
  enableScrollForNextCalculateItemsInView: true,
3163
3221
  endBuffered: -1,
3164
3222
  endNoBuffer: -1,
@@ -3171,6 +3229,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3171
3229
  isAtEnd: false,
3172
3230
  isAtStart: false,
3173
3231
  isEndReached: false,
3232
+ isFirst: true,
3233
+ isOptimizingItemPositions: false,
3174
3234
  isStartReached: false,
3175
3235
  lastBatchingAction: Date.now(),
3176
3236
  lastLayout: void 0,
@@ -3209,10 +3269,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3209
3269
  refState.current = ctx.internalState;
3210
3270
  }
3211
3271
  const state = refState.current;
3212
- const isFirst = !state.props.renderItem;
3213
- const didDataChange = state.props.data !== dataProp;
3214
- if (didDataChange) {
3272
+ const isFirstLocal = state.isFirst;
3273
+ state.didColumnsChange = numColumnsProp !== state.props.numColumns;
3274
+ const didDataChangeLocal = state.props.data !== dataProp && checkActualChange(state, dataProp, state.props.data);
3275
+ if (didDataChangeLocal) {
3215
3276
  state.dataChangeNeedsScrollUpdate = true;
3277
+ state.didDataChange = true;
3278
+ state.previousData = state.props.data;
3216
3279
  }
3217
3280
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3218
3281
  state.props = {
@@ -3271,7 +3334,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3271
3334
  requestAdjust(ctx, state, paddingDiff);
3272
3335
  }
3273
3336
  };
3274
- if (isFirst) {
3337
+ if (isFirstLocal) {
3275
3338
  initializeStateVars();
3276
3339
  updateItemPositions(
3277
3340
  ctx,
@@ -3289,28 +3352,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3289
3352
  initialContentOffset2 += calculateOffsetForIndex(ctx, state, index);
3290
3353
  }
3291
3354
  refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
3292
- if (initialContentOffset2 > 0) {
3293
- scrollTo(ctx, state, {
3294
- animated: false,
3295
- index,
3296
- isInitialScroll: true,
3297
- offset: initialContentOffset2,
3298
- viewPosition: index === dataProp.length - 1 ? 1 : 0
3299
- });
3300
- }
3301
3355
  return initialContentOffset2;
3302
3356
  }
3303
3357
  return 0;
3304
3358
  }, [renderNum]);
3305
- if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
3359
+ if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3306
3360
  refState.current.lastBatchingAction = Date.now();
3307
- if (!keyExtractorProp && !isFirst && didDataChange) {
3361
+ if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3308
3362
  IS_DEV && warnDevOnce(
3309
3363
  "keyExtractor",
3310
3364
  "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."
3311
3365
  );
3312
3366
  refState.current.sizes.clear();
3313
3367
  refState.current.positions.clear();
3368
+ refState.current.totalSize = 0;
3369
+ set$(ctx, "totalSize", 0);
3314
3370
  }
3315
3371
  }
3316
3372
  const onLayoutHeader = useCallback((rect, fromLayoutEffect) => {
@@ -3325,22 +3381,41 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3325
3381
  }
3326
3382
  }
3327
3383
  }, []);
3384
+ const doInitialScroll = useCallback(() => {
3385
+ const initialScroll = state.initialScroll;
3386
+ if (initialScroll) {
3387
+ scrollTo(ctx, state, { animated: false, offset: initialContentOffset, ...state.initialScroll || {} });
3388
+ }
3389
+ }, [initialContentOffset, state.initialScroll]);
3390
+ const onLayoutChange = useCallback((layout) => {
3391
+ doInitialScroll();
3392
+ handleLayout(ctx, state, layout, setCanRender);
3393
+ }, []);
3394
+ const { onLayout } = useOnLayoutSync({
3395
+ onLayoutChange,
3396
+ onLayoutProp,
3397
+ ref: refScroller
3398
+ // the type of ScrollView doesn't include measure?
3399
+ });
3328
3400
  useLayoutEffect(() => {
3329
3401
  if (snapToIndices) {
3330
3402
  updateSnapToOffsets(ctx, state);
3331
3403
  }
3332
3404
  }, [snapToIndices]);
3333
3405
  useLayoutEffect(() => {
3334
- const didAllocateContainers = dataProp.length > 0 && doInitialAllocateContainers(ctx, state);
3335
- if (!didAllocateContainers) {
3336
- checkResetContainers(
3337
- ctx,
3338
- state,
3339
- /*isFirst*/
3340
- isFirst,
3341
- dataProp
3342
- );
3406
+ const {
3407
+ didColumnsChange,
3408
+ didDataChange,
3409
+ isFirst,
3410
+ props: { data }
3411
+ } = state;
3412
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3413
+ if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3414
+ checkResetContainers(ctx, state, data);
3343
3415
  }
3416
+ state.didColumnsChange = false;
3417
+ state.didDataChange = false;
3418
+ state.isFirst = false;
3344
3419
  }, [dataProp, numColumnsProp]);
3345
3420
  useLayoutEffect(() => {
3346
3421
  set$(ctx, "extraData", extraData);
@@ -3360,15 +3435,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3360
3435
  state.viewabilityConfigCallbackPairs = viewability;
3361
3436
  state.enableScrollForNextCalculateItemsInView = !viewability;
3362
3437
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3363
- const onLayoutChange = useCallback((layout) => {
3364
- handleLayout(ctx, state, layout, setCanRender);
3365
- }, []);
3366
- const { onLayout } = useOnLayoutSync({
3367
- onLayoutChange,
3368
- onLayoutProp,
3369
- ref: refScroller
3370
- // the type of ScrollView doesn't include measure?
3371
- });
3372
3438
  useImperativeHandle(forwardedRef, () => {
3373
3439
  const scrollIndexIntoView = (options) => {
3374
3440
  const state2 = refState.current;
@@ -3452,12 +3518,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3452
3518
  };
3453
3519
  }, []);
3454
3520
  {
3455
- useEffect(() => {
3456
- const { initialScroll } = refState.current;
3457
- if (initialContentOffset) {
3458
- scrollTo(ctx, state, { animated: false, offset: initialContentOffset, ...initialScroll || {} });
3459
- }
3460
- }, []);
3521
+ useEffect(doInitialScroll, []);
3461
3522
  }
3462
3523
  const fns = useMemo(
3463
3524
  () => ({