@legendapp/list 3.0.0-beta.18 → 3.0.0-beta.19

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.d.mts CHANGED
@@ -410,7 +410,7 @@ interface InternalState {
410
410
  avg: number;
411
411
  }>;
412
412
  columns: Map<string, number>;
413
- containerItemKeys: Set<string>;
413
+ containerItemKeys: Map<string, number>;
414
414
  containerItemTypes: Map<number, string>;
415
415
  dataChangeNeedsScrollUpdate: boolean;
416
416
  didColumnsChange?: boolean;
@@ -442,6 +442,7 @@ interface InternalState {
442
442
  lastBatchingAction: number;
443
443
  lastLayout: LayoutRectangle | undefined;
444
444
  lastScrollAdjustForHistory?: number;
445
+ lastScrollDelta: number;
445
446
  loadStartTime: number;
446
447
  maintainingScrollAtEnd?: boolean;
447
448
  minIndexSizeChanged: number | undefined;
package/index.d.ts CHANGED
@@ -410,7 +410,7 @@ interface InternalState {
410
410
  avg: number;
411
411
  }>;
412
412
  columns: Map<string, number>;
413
- containerItemKeys: Set<string>;
413
+ containerItemKeys: Map<string, number>;
414
414
  containerItemTypes: Map<number, string>;
415
415
  dataChangeNeedsScrollUpdate: boolean;
416
416
  didColumnsChange?: boolean;
@@ -442,6 +442,7 @@ interface InternalState {
442
442
  lastBatchingAction: number;
443
443
  lastLayout: LayoutRectangle | undefined;
444
444
  lastScrollAdjustForHistory?: number;
445
+ lastScrollDelta: number;
445
446
  loadStartTime: number;
446
447
  maintainingScrollAtEnd?: boolean;
447
448
  minIndexSizeChanged: number | undefined;
package/index.js CHANGED
@@ -287,6 +287,11 @@ function extractPadding(style, contentContainerStyle, type) {
287
287
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
288
288
  }
289
289
  function findContainerId(ctx, key) {
290
+ var _a3, _b;
291
+ const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
292
+ if (directMatch !== void 0) {
293
+ return directMatch;
294
+ }
290
295
  const numContainers = peek$(ctx, "numContainers");
291
296
  for (let i = 0; i < numContainers; i++) {
292
297
  const itemKey = peek$(ctx, `containerItemKey${i}`);
@@ -1713,9 +1718,9 @@ function checkAtTop(state) {
1713
1718
 
1714
1719
  // src/core/updateScroll.ts
1715
1720
  function updateScroll(ctx, newScroll, forceUpdate) {
1716
- var _a3;
1717
1721
  const state = ctx.state;
1718
1722
  const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1723
+ const prevScroll = state.scroll;
1719
1724
  state.hasScrolled = true;
1720
1725
  state.lastBatchingAction = Date.now();
1721
1726
  const currentTime = Date.now();
@@ -1733,7 +1738,7 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1733
1738
  if (state.scrollHistory.length > 5) {
1734
1739
  state.scrollHistory.shift();
1735
1740
  }
1736
- state.scrollPrev = state.scroll;
1741
+ state.scrollPrev = prevScroll;
1737
1742
  state.scrollPrevTime = state.scrollTime;
1738
1743
  state.scroll = newScroll;
1739
1744
  state.scrollTime = currentTime;
@@ -1745,15 +1750,27 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1745
1750
  return;
1746
1751
  }
1747
1752
  }
1753
+ const scrollDelta = Math.abs(newScroll - prevScroll);
1754
+ const scrollLength = state.scrollLength;
1748
1755
  const lastCalculated = state.scrollLastCalculate;
1749
1756
  const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1750
1757
  if (shouldUpdate) {
1751
1758
  state.scrollLastCalculate = state.scroll;
1752
1759
  state.ignoreScrollFromMVCPIgnored = false;
1753
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1754
- checkAtBottom(ctx);
1755
- checkAtTop(state);
1760
+ state.lastScrollDelta = scrollDelta;
1761
+ const runCalculateItems = () => {
1762
+ var _a3;
1763
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1764
+ checkAtBottom(ctx);
1765
+ checkAtTop(state);
1766
+ };
1767
+ if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
1768
+ reactDom.flushSync(runCalculateItems);
1769
+ } else {
1770
+ runCalculateItems();
1771
+ }
1756
1772
  state.dataChangeNeedsScrollUpdate = false;
1773
+ state.lastScrollDelta = 0;
1757
1774
  }
1758
1775
  }
1759
1776
 
@@ -2033,7 +2050,9 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2033
2050
  const numColumns = peek$(ctx, "numColumns");
2034
2051
  const hasColumns = numColumns > 1;
2035
2052
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
2036
- const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
2053
+ const lastScrollDelta = state.lastScrollDelta;
2054
+ const velocity = getScrollVelocity(state);
2055
+ const shouldOptimize = !forceFullUpdate && !dataChanged && (Math.abs(velocity) > 0 || state.scrollLength > 0 && lastScrollDelta > state.scrollLength);
2037
2056
  const maxVisibleArea = scrollBottomBuffered + 1e3;
2038
2057
  const useAverageSize = !getEstimatedItemSize;
2039
2058
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
@@ -2806,7 +2825,7 @@ function calculateItemsInView(ctx, params = {}) {
2806
2825
  if (requiredItemTypes) {
2807
2826
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2808
2827
  }
2809
- containerItemKeys.add(id);
2828
+ containerItemKeys.set(id, containerIndex);
2810
2829
  const containerSticky = `containerSticky${containerIndex}`;
2811
2830
  if (stickyIndicesSet.has(i)) {
2812
2831
  set$(ctx, containerSticky, true);
@@ -3299,14 +3318,8 @@ function updateItemSize(ctx, itemKey, sizeObj) {
3299
3318
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
3300
3319
  const { startBuffered, endBuffered } = state;
3301
3320
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
3302
- if (!needsRecalculate) {
3303
- const numContainers = ctx.values.get("numContainers");
3304
- for (let i = 0; i < numContainers; i++) {
3305
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
3306
- needsRecalculate = true;
3307
- break;
3308
- }
3309
- }
3321
+ if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
3322
+ needsRecalculate = true;
3310
3323
  }
3311
3324
  if (state.needsOtherAxisSize) {
3312
3325
  const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
@@ -3732,7 +3745,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3732
3745
  activeStickyIndex: -1,
3733
3746
  averageSizes: {},
3734
3747
  columns: /* @__PURE__ */ new Map(),
3735
- containerItemKeys: /* @__PURE__ */ new Set(),
3748
+ containerItemKeys: /* @__PURE__ */ new Map(),
3736
3749
  containerItemTypes: /* @__PURE__ */ new Map(),
3737
3750
  dataChangeNeedsScrollUpdate: false,
3738
3751
  didColumnsChange: false,
@@ -3760,6 +3773,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3760
3773
  isStartReached: null,
3761
3774
  lastBatchingAction: Date.now(),
3762
3775
  lastLayout: void 0,
3776
+ lastScrollDelta: 0,
3763
3777
  loadStartTime: Date.now(),
3764
3778
  minIndexSizeChanged: 0,
3765
3779
  nativeMarginTop: 0,
package/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React3 from 'react';
2
2
  import React3__default, { forwardRef, useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useImperativeHandle, useLayoutEffect, memo, useContext } from 'react';
3
3
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
4
- import { unstable_batchedUpdates } from 'react-dom';
4
+ import { unstable_batchedUpdates, flushSync } from 'react-dom';
5
5
 
6
6
  // src/components/LegendList.tsx
7
7
  forwardRef(function AnimatedView2(props, ref) {
@@ -266,6 +266,11 @@ function extractPadding(style, contentContainerStyle, type) {
266
266
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
267
267
  }
268
268
  function findContainerId(ctx, key) {
269
+ var _a3, _b;
270
+ const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
271
+ if (directMatch !== void 0) {
272
+ return directMatch;
273
+ }
269
274
  const numContainers = peek$(ctx, "numContainers");
270
275
  for (let i = 0; i < numContainers; i++) {
271
276
  const itemKey = peek$(ctx, `containerItemKey${i}`);
@@ -1692,9 +1697,9 @@ function checkAtTop(state) {
1692
1697
 
1693
1698
  // src/core/updateScroll.ts
1694
1699
  function updateScroll(ctx, newScroll, forceUpdate) {
1695
- var _a3;
1696
1700
  const state = ctx.state;
1697
1701
  const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1702
+ const prevScroll = state.scroll;
1698
1703
  state.hasScrolled = true;
1699
1704
  state.lastBatchingAction = Date.now();
1700
1705
  const currentTime = Date.now();
@@ -1712,7 +1717,7 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1712
1717
  if (state.scrollHistory.length > 5) {
1713
1718
  state.scrollHistory.shift();
1714
1719
  }
1715
- state.scrollPrev = state.scroll;
1720
+ state.scrollPrev = prevScroll;
1716
1721
  state.scrollPrevTime = state.scrollTime;
1717
1722
  state.scroll = newScroll;
1718
1723
  state.scrollTime = currentTime;
@@ -1724,15 +1729,27 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1724
1729
  return;
1725
1730
  }
1726
1731
  }
1732
+ const scrollDelta = Math.abs(newScroll - prevScroll);
1733
+ const scrollLength = state.scrollLength;
1727
1734
  const lastCalculated = state.scrollLastCalculate;
1728
1735
  const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1729
1736
  if (shouldUpdate) {
1730
1737
  state.scrollLastCalculate = state.scroll;
1731
1738
  state.ignoreScrollFromMVCPIgnored = false;
1732
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1733
- checkAtBottom(ctx);
1734
- checkAtTop(state);
1739
+ state.lastScrollDelta = scrollDelta;
1740
+ const runCalculateItems = () => {
1741
+ var _a3;
1742
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1743
+ checkAtBottom(ctx);
1744
+ checkAtTop(state);
1745
+ };
1746
+ if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
1747
+ flushSync(runCalculateItems);
1748
+ } else {
1749
+ runCalculateItems();
1750
+ }
1735
1751
  state.dataChangeNeedsScrollUpdate = false;
1752
+ state.lastScrollDelta = 0;
1736
1753
  }
1737
1754
  }
1738
1755
 
@@ -2012,7 +2029,9 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2012
2029
  const numColumns = peek$(ctx, "numColumns");
2013
2030
  const hasColumns = numColumns > 1;
2014
2031
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
2015
- const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
2032
+ const lastScrollDelta = state.lastScrollDelta;
2033
+ const velocity = getScrollVelocity(state);
2034
+ const shouldOptimize = !forceFullUpdate && !dataChanged && (Math.abs(velocity) > 0 || state.scrollLength > 0 && lastScrollDelta > state.scrollLength);
2016
2035
  const maxVisibleArea = scrollBottomBuffered + 1e3;
2017
2036
  const useAverageSize = !getEstimatedItemSize;
2018
2037
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
@@ -2785,7 +2804,7 @@ function calculateItemsInView(ctx, params = {}) {
2785
2804
  if (requiredItemTypes) {
2786
2805
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2787
2806
  }
2788
- containerItemKeys.add(id);
2807
+ containerItemKeys.set(id, containerIndex);
2789
2808
  const containerSticky = `containerSticky${containerIndex}`;
2790
2809
  if (stickyIndicesSet.has(i)) {
2791
2810
  set$(ctx, containerSticky, true);
@@ -3278,14 +3297,8 @@ function updateItemSize(ctx, itemKey, sizeObj) {
3278
3297
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
3279
3298
  const { startBuffered, endBuffered } = state;
3280
3299
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
3281
- if (!needsRecalculate) {
3282
- const numContainers = ctx.values.get("numContainers");
3283
- for (let i = 0; i < numContainers; i++) {
3284
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
3285
- needsRecalculate = true;
3286
- break;
3287
- }
3288
- }
3300
+ if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
3301
+ needsRecalculate = true;
3289
3302
  }
3290
3303
  if (state.needsOtherAxisSize) {
3291
3304
  const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
@@ -3711,7 +3724,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3711
3724
  activeStickyIndex: -1,
3712
3725
  averageSizes: {},
3713
3726
  columns: /* @__PURE__ */ new Map(),
3714
- containerItemKeys: /* @__PURE__ */ new Set(),
3727
+ containerItemKeys: /* @__PURE__ */ new Map(),
3715
3728
  containerItemTypes: /* @__PURE__ */ new Map(),
3716
3729
  dataChangeNeedsScrollUpdate: false,
3717
3730
  didColumnsChange: false,
@@ -3739,6 +3752,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3739
3752
  isStartReached: null,
3740
3753
  lastBatchingAction: Date.now(),
3741
3754
  lastLayout: void 0,
3755
+ lastScrollDelta: 0,
3742
3756
  loadStartTime: Date.now(),
3743
3757
  minIndexSizeChanged: 0,
3744
3758
  nativeMarginTop: 0,
package/index.native.js CHANGED
@@ -286,6 +286,11 @@ function extractPadding(style, contentContainerStyle, type) {
286
286
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
287
287
  }
288
288
  function findContainerId(ctx, key) {
289
+ var _a3, _b;
290
+ const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
291
+ if (directMatch !== void 0) {
292
+ return directMatch;
293
+ }
289
294
  const numContainers = peek$(ctx, "numContainers");
290
295
  for (let i = 0; i < numContainers; i++) {
291
296
  const itemKey = peek$(ctx, `containerItemKey${i}`);
@@ -1320,6 +1325,11 @@ function scrollTo(ctx, params) {
1320
1325
  }
1321
1326
  }
1322
1327
 
1328
+ // src/platform/flushSync.native.ts
1329
+ var flushSync = (fn) => {
1330
+ fn();
1331
+ };
1332
+
1323
1333
  // src/utils/checkThreshold.ts
1324
1334
  var HYSTERESIS_MULTIPLIER = 1.3;
1325
1335
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot, allowReentryOnChange) => {
@@ -1443,9 +1453,9 @@ function checkAtTop(state) {
1443
1453
 
1444
1454
  // src/core/updateScroll.ts
1445
1455
  function updateScroll(ctx, newScroll, forceUpdate) {
1446
- var _a3;
1447
1456
  const state = ctx.state;
1448
1457
  const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1458
+ const prevScroll = state.scroll;
1449
1459
  state.hasScrolled = true;
1450
1460
  state.lastBatchingAction = Date.now();
1451
1461
  const currentTime = Date.now();
@@ -1463,7 +1473,7 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1463
1473
  if (state.scrollHistory.length > 5) {
1464
1474
  state.scrollHistory.shift();
1465
1475
  }
1466
- state.scrollPrev = state.scroll;
1476
+ state.scrollPrev = prevScroll;
1467
1477
  state.scrollPrevTime = state.scrollTime;
1468
1478
  state.scroll = newScroll;
1469
1479
  state.scrollTime = currentTime;
@@ -1475,15 +1485,27 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1475
1485
  return;
1476
1486
  }
1477
1487
  }
1488
+ const scrollDelta = Math.abs(newScroll - prevScroll);
1489
+ const scrollLength = state.scrollLength;
1478
1490
  const lastCalculated = state.scrollLastCalculate;
1479
1491
  const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1480
1492
  if (shouldUpdate) {
1481
1493
  state.scrollLastCalculate = state.scroll;
1482
1494
  state.ignoreScrollFromMVCPIgnored = false;
1483
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1484
- checkAtBottom(ctx);
1485
- checkAtTop(state);
1495
+ state.lastScrollDelta = scrollDelta;
1496
+ const runCalculateItems = () => {
1497
+ var _a3;
1498
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1499
+ checkAtBottom(ctx);
1500
+ checkAtTop(state);
1501
+ };
1502
+ if (Platform2.OS === "web" && scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
1503
+ flushSync(runCalculateItems);
1504
+ } else {
1505
+ runCalculateItems();
1506
+ }
1486
1507
  state.dataChangeNeedsScrollUpdate = false;
1508
+ state.lastScrollDelta = 0;
1487
1509
  }
1488
1510
  }
1489
1511
 
@@ -1848,7 +1870,9 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
1848
1870
  const numColumns = peek$(ctx, "numColumns");
1849
1871
  const hasColumns = numColumns > 1;
1850
1872
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1851
- const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1873
+ const lastScrollDelta = state.lastScrollDelta;
1874
+ const velocity = getScrollVelocity(state);
1875
+ const shouldOptimize = !forceFullUpdate && !dataChanged && (Math.abs(velocity) > 0 || Platform2.OS === "web" && state.scrollLength > 0 && lastScrollDelta > state.scrollLength);
1852
1876
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1853
1877
  const useAverageSize = !getEstimatedItemSize;
1854
1878
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
@@ -2627,7 +2651,7 @@ function calculateItemsInView(ctx, params = {}) {
2627
2651
  if (requiredItemTypes) {
2628
2652
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2629
2653
  }
2630
- containerItemKeys.add(id);
2654
+ containerItemKeys.set(id, containerIndex);
2631
2655
  const containerSticky = `containerSticky${containerIndex}`;
2632
2656
  if (stickyIndicesSet.has(i)) {
2633
2657
  set$(ctx, containerSticky, true);
@@ -3077,14 +3101,8 @@ function updateItemSize(ctx, itemKey, sizeObj) {
3077
3101
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
3078
3102
  const { startBuffered, endBuffered } = state;
3079
3103
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
3080
- if (!needsRecalculate) {
3081
- const numContainers = ctx.values.get("numContainers");
3082
- for (let i = 0; i < numContainers; i++) {
3083
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
3084
- needsRecalculate = true;
3085
- break;
3086
- }
3087
- }
3104
+ if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
3105
+ needsRecalculate = true;
3088
3106
  }
3089
3107
  if (state.needsOtherAxisSize) {
3090
3108
  const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
@@ -3529,7 +3547,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3529
3547
  activeStickyIndex: -1,
3530
3548
  averageSizes: {},
3531
3549
  columns: /* @__PURE__ */ new Map(),
3532
- containerItemKeys: /* @__PURE__ */ new Set(),
3550
+ containerItemKeys: /* @__PURE__ */ new Map(),
3533
3551
  containerItemTypes: /* @__PURE__ */ new Map(),
3534
3552
  dataChangeNeedsScrollUpdate: false,
3535
3553
  didColumnsChange: false,
@@ -3557,6 +3575,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3557
3575
  isStartReached: null,
3558
3576
  lastBatchingAction: Date.now(),
3559
3577
  lastLayout: void 0,
3578
+ lastScrollDelta: 0,
3560
3579
  loadStartTime: Date.now(),
3561
3580
  minIndexSizeChanged: 0,
3562
3581
  nativeMarginTop: 0,
package/index.native.mjs CHANGED
@@ -265,6 +265,11 @@ function extractPadding(style, contentContainerStyle, type) {
265
265
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
266
266
  }
267
267
  function findContainerId(ctx, key) {
268
+ var _a3, _b;
269
+ const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
270
+ if (directMatch !== void 0) {
271
+ return directMatch;
272
+ }
268
273
  const numContainers = peek$(ctx, "numContainers");
269
274
  for (let i = 0; i < numContainers; i++) {
270
275
  const itemKey = peek$(ctx, `containerItemKey${i}`);
@@ -1299,6 +1304,11 @@ function scrollTo(ctx, params) {
1299
1304
  }
1300
1305
  }
1301
1306
 
1307
+ // src/platform/flushSync.native.ts
1308
+ var flushSync = (fn) => {
1309
+ fn();
1310
+ };
1311
+
1302
1312
  // src/utils/checkThreshold.ts
1303
1313
  var HYSTERESIS_MULTIPLIER = 1.3;
1304
1314
  var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot, allowReentryOnChange) => {
@@ -1422,9 +1432,9 @@ function checkAtTop(state) {
1422
1432
 
1423
1433
  // src/core/updateScroll.ts
1424
1434
  function updateScroll(ctx, newScroll, forceUpdate) {
1425
- var _a3;
1426
1435
  const state = ctx.state;
1427
1436
  const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1437
+ const prevScroll = state.scroll;
1428
1438
  state.hasScrolled = true;
1429
1439
  state.lastBatchingAction = Date.now();
1430
1440
  const currentTime = Date.now();
@@ -1442,7 +1452,7 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1442
1452
  if (state.scrollHistory.length > 5) {
1443
1453
  state.scrollHistory.shift();
1444
1454
  }
1445
- state.scrollPrev = state.scroll;
1455
+ state.scrollPrev = prevScroll;
1446
1456
  state.scrollPrevTime = state.scrollTime;
1447
1457
  state.scroll = newScroll;
1448
1458
  state.scrollTime = currentTime;
@@ -1454,15 +1464,27 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1454
1464
  return;
1455
1465
  }
1456
1466
  }
1467
+ const scrollDelta = Math.abs(newScroll - prevScroll);
1468
+ const scrollLength = state.scrollLength;
1457
1469
  const lastCalculated = state.scrollLastCalculate;
1458
1470
  const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1459
1471
  if (shouldUpdate) {
1460
1472
  state.scrollLastCalculate = state.scroll;
1461
1473
  state.ignoreScrollFromMVCPIgnored = false;
1462
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1463
- checkAtBottom(ctx);
1464
- checkAtTop(state);
1474
+ state.lastScrollDelta = scrollDelta;
1475
+ const runCalculateItems = () => {
1476
+ var _a3;
1477
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1478
+ checkAtBottom(ctx);
1479
+ checkAtTop(state);
1480
+ };
1481
+ if (Platform2.OS === "web" && scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
1482
+ flushSync(runCalculateItems);
1483
+ } else {
1484
+ runCalculateItems();
1485
+ }
1465
1486
  state.dataChangeNeedsScrollUpdate = false;
1487
+ state.lastScrollDelta = 0;
1466
1488
  }
1467
1489
  }
1468
1490
 
@@ -1827,7 +1849,9 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
1827
1849
  const numColumns = peek$(ctx, "numColumns");
1828
1850
  const hasColumns = numColumns > 1;
1829
1851
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1830
- const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1852
+ const lastScrollDelta = state.lastScrollDelta;
1853
+ const velocity = getScrollVelocity(state);
1854
+ const shouldOptimize = !forceFullUpdate && !dataChanged && (Math.abs(velocity) > 0 || Platform2.OS === "web" && state.scrollLength > 0 && lastScrollDelta > state.scrollLength);
1831
1855
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1832
1856
  const useAverageSize = !getEstimatedItemSize;
1833
1857
  const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
@@ -2606,7 +2630,7 @@ function calculateItemsInView(ctx, params = {}) {
2606
2630
  if (requiredItemTypes) {
2607
2631
  state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2608
2632
  }
2609
- containerItemKeys.add(id);
2633
+ containerItemKeys.set(id, containerIndex);
2610
2634
  const containerSticky = `containerSticky${containerIndex}`;
2611
2635
  if (stickyIndicesSet.has(i)) {
2612
2636
  set$(ctx, containerSticky, true);
@@ -3056,14 +3080,8 @@ function updateItemSize(ctx, itemKey, sizeObj) {
3056
3080
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
3057
3081
  const { startBuffered, endBuffered } = state;
3058
3082
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
3059
- if (!needsRecalculate) {
3060
- const numContainers = ctx.values.get("numContainers");
3061
- for (let i = 0; i < numContainers; i++) {
3062
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
3063
- needsRecalculate = true;
3064
- break;
3065
- }
3066
- }
3083
+ if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
3084
+ needsRecalculate = true;
3067
3085
  }
3068
3086
  if (state.needsOtherAxisSize) {
3069
3087
  const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
@@ -3508,7 +3526,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3508
3526
  activeStickyIndex: -1,
3509
3527
  averageSizes: {},
3510
3528
  columns: /* @__PURE__ */ new Map(),
3511
- containerItemKeys: /* @__PURE__ */ new Set(),
3529
+ containerItemKeys: /* @__PURE__ */ new Map(),
3512
3530
  containerItemTypes: /* @__PURE__ */ new Map(),
3513
3531
  dataChangeNeedsScrollUpdate: false,
3514
3532
  didColumnsChange: false,
@@ -3536,6 +3554,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3536
3554
  isStartReached: null,
3537
3555
  lastBatchingAction: Date.now(),
3538
3556
  lastLayout: void 0,
3557
+ lastScrollDelta: 0,
3539
3558
  loadStartTime: Date.now(),
3540
3559
  minIndexSizeChanged: 0,
3541
3560
  nativeMarginTop: 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "3.0.0-beta.18",
3
+ "version": "3.0.0-beta.19",
4
4
  "description": "Legend List is a drop-in replacement for FlatList with much better performance and supporting dynamically sized items.",
5
5
  "sideEffects": false,
6
6
  "private": false,
package/.DS_Store DELETED
Binary file