@legendapp/list 2.0.0-beta.3 → 2.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/index.d.mts +4 -11
  2. package/index.d.ts +4 -11
  3. package/index.js +157 -213
  4. package/index.mjs +157 -213
  5. package/package.json +1 -1
package/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React$1 from 'react';
2
2
  import { ComponentProps, ReactNode, Dispatch, SetStateAction } from 'react';
3
- import { View, Animated, ScrollView, LayoutRectangle, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, ScrollViewProps } from 'react-native';
3
+ import { View, Animated, ScrollView, LayoutRectangle, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, NativeSyntheticEvent, NativeScrollEvent, ScrollViewProps } from 'react-native';
4
4
  import Animated$1 from 'react-native-reanimated';
5
5
 
6
6
  type ListenerType = "numContainers" | "numContainersPooled" | `containerItemKey${number}` | `containerItemData${number}` | `containerPosition${number}` | `containerColumn${number}` | `containerSticky${number}` | `containerStickyOffset${number}` | "containersDidLayout" | "extraData" | "numColumns" | "lastItemKeys" | "totalSize" | "alignItemsPaddingTop" | "stylePaddingTop" | "scrollAdjust" | "scrollAdjustUserOffset" | "headerSize" | "footerSize" | "maintainVisibleContentPosition" | "debugRawScroll" | "debugComputedScroll" | "otherAxisSize" | "snapToOffsets" | "scrollSize";
@@ -30,9 +30,10 @@ declare class ScrollAdjustHandler {
30
30
  constructor(ctx: StateContext);
31
31
  requestAdjust(add: number): void;
32
32
  setMounted(): void;
33
+ getAdjust(): number;
33
34
  }
34
35
 
35
- type BaseScrollViewProps<TScrollView> = Omit<TScrollView, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children">;
36
+ type BaseScrollViewProps<TScrollView> = Omit<TScrollView, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children" | "onScroll">;
36
37
  interface DataModeProps<ItemT, TItemType extends string | undefined> {
37
38
  /**
38
39
  * Array of items to render in the list.
@@ -195,6 +196,7 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
195
196
  * Function to call when the user pulls to refresh.
196
197
  */
197
198
  onRefresh?: () => void;
199
+ onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
198
200
  /**
199
201
  * Called when scrolling reaches the start within onStartReachedThreshold.
200
202
  */
@@ -287,7 +289,6 @@ interface InternalState {
287
289
  sizesKnown: Map<string, number>;
288
290
  containerItemKeys: Set<string>;
289
291
  containerItemTypes: Map<number, string>;
290
- pendingAdjust: number;
291
292
  isStartReached: boolean;
292
293
  isEndReached: boolean;
293
294
  isAtEnd: boolean;
@@ -352,14 +353,6 @@ interface InternalState {
352
353
  loadStartTime: number;
353
354
  initialScroll: ScrollIndexWithOffset | undefined;
354
355
  lastLayout: LayoutRectangle | undefined;
355
- queuedItemSizeUpdates: {
356
- itemKey: string;
357
- sizeObj: {
358
- width: number;
359
- height: number;
360
- };
361
- }[];
362
- queuedItemSizeUpdatesWaiting?: boolean;
363
356
  timeoutSetPaddingTop?: any;
364
357
  activeStickyIndex: number | undefined;
365
358
  stickyContainers: Map<number, number>;
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React$1 from 'react';
2
2
  import { ComponentProps, ReactNode, Dispatch, SetStateAction } from 'react';
3
- import { View, Animated, ScrollView, LayoutRectangle, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, ScrollViewProps } from 'react-native';
3
+ import { View, Animated, ScrollView, LayoutRectangle, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, NativeSyntheticEvent, NativeScrollEvent, ScrollViewProps } from 'react-native';
4
4
  import Animated$1 from 'react-native-reanimated';
5
5
 
6
6
  type ListenerType = "numContainers" | "numContainersPooled" | `containerItemKey${number}` | `containerItemData${number}` | `containerPosition${number}` | `containerColumn${number}` | `containerSticky${number}` | `containerStickyOffset${number}` | "containersDidLayout" | "extraData" | "numColumns" | "lastItemKeys" | "totalSize" | "alignItemsPaddingTop" | "stylePaddingTop" | "scrollAdjust" | "scrollAdjustUserOffset" | "headerSize" | "footerSize" | "maintainVisibleContentPosition" | "debugRawScroll" | "debugComputedScroll" | "otherAxisSize" | "snapToOffsets" | "scrollSize";
@@ -30,9 +30,10 @@ declare class ScrollAdjustHandler {
30
30
  constructor(ctx: StateContext);
31
31
  requestAdjust(add: number): void;
32
32
  setMounted(): void;
33
+ getAdjust(): number;
33
34
  }
34
35
 
35
- type BaseScrollViewProps<TScrollView> = Omit<TScrollView, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children">;
36
+ type BaseScrollViewProps<TScrollView> = Omit<TScrollView, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children" | "onScroll">;
36
37
  interface DataModeProps<ItemT, TItemType extends string | undefined> {
37
38
  /**
38
39
  * Array of items to render in the list.
@@ -195,6 +196,7 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
195
196
  * Function to call when the user pulls to refresh.
196
197
  */
197
198
  onRefresh?: () => void;
199
+ onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
198
200
  /**
199
201
  * Called when scrolling reaches the start within onStartReachedThreshold.
200
202
  */
@@ -287,7 +289,6 @@ interface InternalState {
287
289
  sizesKnown: Map<string, number>;
288
290
  containerItemKeys: Set<string>;
289
291
  containerItemTypes: Map<number, string>;
290
- pendingAdjust: number;
291
292
  isStartReached: boolean;
292
293
  isEndReached: boolean;
293
294
  isAtEnd: boolean;
@@ -352,14 +353,6 @@ interface InternalState {
352
353
  loadStartTime: number;
353
354
  initialScroll: ScrollIndexWithOffset | undefined;
354
355
  lastLayout: LayoutRectangle | undefined;
355
- queuedItemSizeUpdates: {
356
- itemKey: string;
357
- sizeObj: {
358
- width: number;
359
- height: number;
360
- };
361
- }[];
362
- queuedItemSizeUpdatesWaiting?: boolean;
363
356
  timeoutSetPaddingTop?: any;
364
357
  activeStickyIndex: number | undefined;
365
358
  stickyContainers: Map<number, number>;
package/index.js CHANGED
@@ -693,30 +693,33 @@ function useThrottleDebounce(mode) {
693
693
  timeoutRef.current = null;
694
694
  }
695
695
  };
696
- const execute = React3.useCallback((callback, delay, ...args) => {
697
- {
698
- const now = Date.now();
699
- lastArgsRef.current = args;
700
- if (now - lastCallTimeRef.current >= delay) {
701
- lastCallTimeRef.current = now;
702
- callback(...args);
703
- clearTimeoutRef();
704
- } else {
705
- clearTimeoutRef();
706
- timeoutRef.current = setTimeout(
707
- () => {
708
- if (lastArgsRef.current) {
709
- lastCallTimeRef.current = Date.now();
710
- callback(...lastArgsRef.current);
711
- timeoutRef.current = null;
712
- lastArgsRef.current = null;
713
- }
714
- },
715
- delay - (now - lastCallTimeRef.current)
716
- );
696
+ const execute = React3.useCallback(
697
+ (callback, delay, ...args) => {
698
+ {
699
+ const now = Date.now();
700
+ lastArgsRef.current = args;
701
+ if (now - lastCallTimeRef.current >= delay) {
702
+ lastCallTimeRef.current = now;
703
+ callback(...args);
704
+ clearTimeoutRef();
705
+ } else {
706
+ clearTimeoutRef();
707
+ timeoutRef.current = setTimeout(
708
+ () => {
709
+ if (lastArgsRef.current) {
710
+ lastCallTimeRef.current = Date.now();
711
+ callback(...lastArgsRef.current);
712
+ timeoutRef.current = null;
713
+ lastArgsRef.current = null;
714
+ }
715
+ },
716
+ delay - (now - lastCallTimeRef.current)
717
+ );
718
+ }
717
719
  }
718
- }
719
- }, [mode]);
720
+ },
721
+ [mode]
722
+ );
720
723
  return execute;
721
724
  }
722
725
 
@@ -912,7 +915,7 @@ function calculateOffsetForIndex(ctx, state, index) {
912
915
  }
913
916
 
914
917
  // src/utils/getItemSize.ts
915
- function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize, preferRenderedCache) {
918
+ function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize) {
916
919
  var _a, _b;
917
920
  const {
918
921
  sizesKnown,
@@ -933,11 +936,7 @@ function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize
933
936
  sizesKnown.set(key, size);
934
937
  }
935
938
  }
936
- const renderedSize = sizes.get(key);
937
- if (size === void 0 && preferRenderedCache && renderedSize !== void 0) {
938
- return renderedSize;
939
- }
940
- if (size === void 0 && useAverageSize && !scrollingTo) {
939
+ if (size === void 0 && useAverageSize && sizeKnown === void 0 && !scrollingTo) {
941
940
  if (itemType === "") {
942
941
  size = defaultAverageSize;
943
942
  } else {
@@ -947,8 +946,11 @@ function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize
947
946
  }
948
947
  }
949
948
  }
950
- if (size === void 0 && renderedSize !== void 0) {
951
- return renderedSize;
949
+ if (size === void 0) {
950
+ size = sizes.get(key);
951
+ if (size !== void 0) {
952
+ return size;
953
+ }
952
954
  }
953
955
  if (size === void 0) {
954
956
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
@@ -1175,44 +1177,6 @@ function addTotalSize(ctx, state, key, add) {
1175
1177
  }
1176
1178
  }
1177
1179
 
1178
- // src/utils/getScrollVelocity.ts
1179
- var getScrollVelocity = (state) => {
1180
- const { scrollHistory } = state;
1181
- let velocity = 0;
1182
- if (scrollHistory.length >= 1) {
1183
- const newest = scrollHistory[scrollHistory.length - 1];
1184
- let oldest;
1185
- let start = 0;
1186
- const now = Date.now();
1187
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1188
- const entry = scrollHistory[i];
1189
- const nextEntry = scrollHistory[i + 1];
1190
- if (i > 0) {
1191
- const prevEntry = scrollHistory[i - 1];
1192
- const prevDirection = entry.scroll - prevEntry.scroll;
1193
- const currentDirection = nextEntry.scroll - entry.scroll;
1194
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1195
- start = i;
1196
- break;
1197
- }
1198
- }
1199
- }
1200
- for (let i = start; i < scrollHistory.length - 1; i++) {
1201
- const entry = scrollHistory[i];
1202
- if (now - entry.time <= 1e3) {
1203
- oldest = entry;
1204
- break;
1205
- }
1206
- }
1207
- if (oldest && oldest !== newest) {
1208
- const scrollDiff = newest.scroll - oldest.scroll;
1209
- const timeDiff = newest.time - oldest.time;
1210
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1211
- }
1212
- }
1213
- return velocity;
1214
- };
1215
-
1216
1180
  // src/utils/updateSnapToOffsets.ts
1217
1181
  function updateSnapToOffsets(ctx, state) {
1218
1182
  const {
@@ -1229,14 +1193,13 @@ function updateSnapToOffsets(ctx, state) {
1229
1193
  }
1230
1194
 
1231
1195
  // src/core/updateAllPositions.ts
1232
- function updateAllPositions(ctx, state, dataChanged) {
1233
- var _a, _b, _c, _d, _e;
1196
+ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1197
+ var _a, _b, _c, _d, _e, _f, _g;
1234
1198
  const {
1235
1199
  averageSizes,
1236
1200
  columns,
1237
1201
  indexByKey,
1238
1202
  positions,
1239
- firstFullyOnScreenIndex,
1240
1203
  idCache,
1241
1204
  sizesKnown,
1242
1205
  props: { getEstimatedItemSize, snapToIndices, enableAverages }
@@ -1244,69 +1207,34 @@ function updateAllPositions(ctx, state, dataChanged) {
1244
1207
  const data = state.props.data;
1245
1208
  const numColumns = peek$(ctx, "numColumns");
1246
1209
  const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1247
- const scrollVelocity = getScrollVelocity(state);
1248
1210
  const useAverageSize = enableAverages && !getEstimatedItemSize;
1249
1211
  const itemType = "";
1250
1212
  let averageSize = (_a = averageSizes[itemType]) == null ? void 0 : _a.avg;
1251
1213
  if (averageSize !== void 0) {
1252
1214
  averageSize = roundSize(averageSize);
1253
1215
  }
1254
- const shouldUseBackwards = !dataChanged && scrollVelocity < 0 && firstFullyOnScreenIndex > 5 && firstFullyOnScreenIndex < data.length;
1255
- if (shouldUseBackwards && firstFullyOnScreenIndex !== void 0) {
1256
- const anchorId = getId(state, firstFullyOnScreenIndex);
1257
- const anchorPosition = positions.get(anchorId);
1258
- if (anchorPosition !== void 0) {
1259
- let currentRowTop2 = anchorPosition;
1260
- let maxSizeInRow2 = 0;
1261
- let bailout = false;
1262
- for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1263
- const id = (_b = idCache.get(i)) != null ? _b : getId(state, i);
1264
- const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(
1265
- state,
1266
- id,
1267
- i,
1268
- data[i],
1269
- useAverageSize,
1270
- averageSize,
1271
- /*preferRenderedCache*/
1272
- !!dataChanged
1273
- );
1274
- const itemColumn = columns.get(id);
1275
- maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1276
- if (itemColumn === 1) {
1277
- currentRowTop2 -= maxSizeInRow2;
1278
- maxSizeInRow2 = 0;
1279
- }
1280
- if (currentRowTop2 < -2e3) {
1281
- bailout = true;
1282
- break;
1283
- }
1284
- positions.set(id, currentRowTop2);
1285
- }
1286
- if (!bailout) {
1287
- updateTotalSize(ctx, state);
1288
- return;
1289
- }
1290
- }
1291
- }
1292
1216
  let currentRowTop = 0;
1293
1217
  let column = 1;
1294
1218
  let maxSizeInRow = 0;
1295
1219
  const hasColumns = numColumns > 1;
1220
+ if (startIndex > 0) {
1221
+ const prevIndex = startIndex - 1;
1222
+ const prevId = (_b = idCache.get(prevIndex)) != null ? _b : getId(state, prevIndex);
1223
+ const prevPosition = (_c = positions.get(prevId)) != null ? _c : 0;
1224
+ if (hasColumns) {
1225
+ const prevColumn = (_d = columns.get(prevId)) != null ? _d : 1;
1226
+ currentRowTop = prevPosition;
1227
+ column = prevColumn % numColumns + 1;
1228
+ } else {
1229
+ const prevSize = (_e = sizesKnown.get(prevId)) != null ? _e : getItemSize(state, prevId, prevIndex, data[prevIndex], useAverageSize, averageSize);
1230
+ currentRowTop = prevPosition + prevSize;
1231
+ }
1232
+ }
1296
1233
  const needsIndexByKey = dataChanged || indexByKey.size === 0;
1297
1234
  const dataLength = data.length;
1298
- for (let i = 0; i < dataLength; i++) {
1299
- const id = (_d = idCache.get(i)) != null ? _d : getId(state, i);
1300
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(
1301
- state,
1302
- id,
1303
- i,
1304
- data[i],
1305
- useAverageSize,
1306
- averageSize,
1307
- /*preferRenderedCache*/
1308
- !!dataChanged
1309
- );
1235
+ for (let i = startIndex; i < dataLength; i++) {
1236
+ const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
1237
+ const size = (_g = sizesKnown.get(id)) != null ? _g : getItemSize(state, id, i, data[i], useAverageSize, averageSize);
1310
1238
  if (__DEV__ && needsIndexByKey) {
1311
1239
  if (indexByKeyForChecking.has(id)) {
1312
1240
  console.error(
@@ -1669,6 +1597,44 @@ function comparatorByDistance(a, b) {
1669
1597
  return b.distance - a.distance;
1670
1598
  }
1671
1599
 
1600
+ // src/utils/getScrollVelocity.ts
1601
+ var getScrollVelocity = (state) => {
1602
+ const { scrollHistory } = state;
1603
+ let velocity = 0;
1604
+ if (scrollHistory.length >= 1) {
1605
+ const newest = scrollHistory[scrollHistory.length - 1];
1606
+ let oldest;
1607
+ let start = 0;
1608
+ const now = Date.now();
1609
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
1610
+ const entry = scrollHistory[i];
1611
+ const nextEntry = scrollHistory[i + 1];
1612
+ if (i > 0) {
1613
+ const prevEntry = scrollHistory[i - 1];
1614
+ const prevDirection = entry.scroll - prevEntry.scroll;
1615
+ const currentDirection = nextEntry.scroll - entry.scroll;
1616
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1617
+ start = i;
1618
+ break;
1619
+ }
1620
+ }
1621
+ }
1622
+ for (let i = start; i < scrollHistory.length - 1; i++) {
1623
+ const entry = scrollHistory[i];
1624
+ if (now - entry.time <= 1e3) {
1625
+ oldest = entry;
1626
+ break;
1627
+ }
1628
+ }
1629
+ if (oldest && oldest !== newest) {
1630
+ const scrollDiff = newest.scroll - oldest.scroll;
1631
+ const timeDiff = newest.time - oldest.time;
1632
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1633
+ }
1634
+ }
1635
+ return velocity;
1636
+ };
1637
+
1672
1638
  // src/core/scrollToIndex.ts
1673
1639
  function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1674
1640
  if (index >= state.props.data.length) {
@@ -1880,7 +1846,11 @@ function calculateItemsInView(ctx, state, params = {}) {
1880
1846
  idCache.clear();
1881
1847
  positions.clear();
1882
1848
  }
1883
- updateAllPositions(ctx, state, dataChanged);
1849
+ const startIndex = dataChanged ? 0 : minIndexSizeChanged != null ? minIndexSizeChanged : 0;
1850
+ updateAllPositions(ctx, state, dataChanged, startIndex);
1851
+ if (minIndexSizeChanged !== void 0) {
1852
+ state.minIndexSizeChanged = void 0;
1853
+ }
1884
1854
  checkMVCP == null ? void 0 : checkMVCP();
1885
1855
  }
1886
1856
  const scrollExtra = 0;
@@ -1927,10 +1897,6 @@ function calculateItemsInView(ctx, state, params = {}) {
1927
1897
  let endNoBuffer = null;
1928
1898
  let endBuffered = null;
1929
1899
  let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1930
- if (minIndexSizeChanged !== void 0) {
1931
- loopStart = Math.min(minIndexSizeChanged, loopStart);
1932
- state.minIndexSizeChanged = void 0;
1933
- }
1934
1900
  for (let i = loopStart; i >= 0; i--) {
1935
1901
  const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1936
1902
  const top = positions.get(id);
@@ -2300,7 +2266,8 @@ function updateScroll(ctx, state, newScroll) {
2300
2266
  state.lastBatchingAction = Date.now();
2301
2267
  const currentTime = Date.now();
2302
2268
  if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
2303
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2269
+ const adjust = state.scrollAdjustHandler.getAdjust();
2270
+ state.scrollHistory.push({ scroll: newScroll - adjust, time: currentTime });
2304
2271
  }
2305
2272
  if (state.scrollHistory.length > 5) {
2306
2273
  state.scrollHistory.shift();
@@ -2336,13 +2303,19 @@ var ScrollAdjustHandler = class {
2336
2303
  setMounted() {
2337
2304
  this.mounted = true;
2338
2305
  }
2306
+ getAdjust() {
2307
+ return this.appliedAdjust;
2308
+ }
2339
2309
  };
2340
2310
 
2341
2311
  // src/core/updateItemSize.ts
2342
- function updateItemSizes(ctx, state, itemUpdates) {
2343
- var _a;
2312
+ function updateItemSize(ctx, state, itemKey, sizeObj) {
2313
+ var _a, _b;
2344
2314
  const {
2315
+ sizesKnown,
2345
2316
  props: {
2317
+ getFixedItemSize,
2318
+ getItemType,
2346
2319
  horizontal,
2347
2320
  maintainVisibleContentPosition,
2348
2321
  suggestEstimatedItemSize,
@@ -2352,47 +2325,60 @@ function updateItemSizes(ctx, state, itemUpdates) {
2352
2325
  }
2353
2326
  } = state;
2354
2327
  if (!data) return;
2328
+ if (getFixedItemSize) {
2329
+ const index2 = state.indexByKey.get(itemKey);
2330
+ if (index2 === void 0) {
2331
+ return;
2332
+ }
2333
+ const itemData = state.props.data[index2];
2334
+ if (itemData === void 0) {
2335
+ return;
2336
+ }
2337
+ const type = getItemType ? (_a = getItemType(itemData, index2)) != null ? _a : "" : "";
2338
+ const size2 = getFixedItemSize(index2, itemData, type);
2339
+ if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
2340
+ return;
2341
+ }
2342
+ }
2355
2343
  const containersDidLayout = peek$(ctx, "containersDidLayout");
2356
2344
  let needsRecalculate = !containersDidLayout;
2357
2345
  let shouldMaintainScrollAtEnd = false;
2358
2346
  let minIndexSizeChanged;
2359
2347
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2360
- for (const { itemKey, sizeObj } of itemUpdates) {
2361
- const index = state.indexByKey.get(itemKey);
2362
- const prevSizeKnown = state.sizesKnown.get(itemKey);
2363
- const diff = updateOneItemSize(state, itemKey, sizeObj);
2364
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2365
- if (diff !== 0) {
2366
- minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2367
- if (((_a = state.scrollingTo) == null ? void 0 : _a.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index && diff > 0) {
2368
- requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
2369
- }
2370
- const { startBuffered, endBuffered } = state;
2371
- needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2372
- if (!needsRecalculate) {
2373
- const numContainers = ctx.values.get("numContainers");
2374
- for (let i = 0; i < numContainers; i++) {
2375
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2376
- needsRecalculate = true;
2377
- break;
2378
- }
2348
+ const index = state.indexByKey.get(itemKey);
2349
+ const prevSizeKnown = state.sizesKnown.get(itemKey);
2350
+ const diff = updateOneItemSize(state, itemKey, sizeObj);
2351
+ const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2352
+ if (diff !== 0) {
2353
+ minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2354
+ if (((_b = state.scrollingTo) == null ? void 0 : _b.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index && diff > 0) {
2355
+ requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
2356
+ }
2357
+ const { startBuffered, endBuffered } = state;
2358
+ needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2359
+ if (!needsRecalculate) {
2360
+ const numContainers = ctx.values.get("numContainers");
2361
+ for (let i = 0; i < numContainers; i++) {
2362
+ if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2363
+ needsRecalculate = true;
2364
+ break;
2379
2365
  }
2380
2366
  }
2381
- if (state.needsOtherAxisSize) {
2382
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2383
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
2384
- }
2385
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2386
- shouldMaintainScrollAtEnd = true;
2387
- }
2388
- onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2389
- index,
2390
- itemData: state.props.data[index],
2391
- itemKey,
2392
- previous: size - diff,
2393
- size
2394
- });
2395
2367
  }
2368
+ if (state.needsOtherAxisSize) {
2369
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2370
+ maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
2371
+ }
2372
+ if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2373
+ shouldMaintainScrollAtEnd = true;
2374
+ }
2375
+ onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2376
+ index,
2377
+ itemData: state.props.data[index],
2378
+ itemKey,
2379
+ previous: size - diff,
2380
+ size
2381
+ });
2396
2382
  }
2397
2383
  if (minIndexSizeChanged !== void 0) {
2398
2384
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
@@ -2425,45 +2411,6 @@ function updateItemSizes(ctx, state, itemUpdates) {
2425
2411
  }
2426
2412
  }
2427
2413
  }
2428
- function updateItemSize(ctx, state, itemKey, sizeObj) {
2429
- var _a;
2430
- const {
2431
- queuedItemSizeUpdates,
2432
- queuedItemSizeUpdatesWaiting,
2433
- sizesKnown,
2434
- props: { getFixedItemSize, getItemType }
2435
- } = state;
2436
- if (getFixedItemSize) {
2437
- const index = state.indexByKey.get(itemKey);
2438
- if (index === void 0) {
2439
- return;
2440
- }
2441
- const itemData = state.props.data[index];
2442
- if (itemData === void 0) {
2443
- return;
2444
- }
2445
- const type = getItemType ? (_a = getItemType(itemData, index)) != null ? _a : "" : "";
2446
- const size = getFixedItemSize(index, itemData, type);
2447
- if (size !== void 0 && size === sizesKnown.get(itemKey)) {
2448
- return;
2449
- }
2450
- }
2451
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2452
- const speed = getScrollVelocity(state);
2453
- if (!containersDidLayout || !queuedItemSizeUpdatesWaiting || Math.abs(speed) < 1) {
2454
- updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
2455
- if (containersDidLayout) {
2456
- state.queuedItemSizeUpdatesWaiting = true;
2457
- requestAnimationFrame(() => {
2458
- state.queuedItemSizeUpdatesWaiting = false;
2459
- updateItemSizes(ctx, state, queuedItemSizeUpdates);
2460
- queuedItemSizeUpdates.length = 0;
2461
- });
2462
- }
2463
- } else {
2464
- queuedItemSizeUpdates.push({ itemKey, sizeObj });
2465
- }
2466
- }
2467
2414
  function updateOneItemSize(state, itemKey, sizeObj) {
2468
2415
  var _a;
2469
2416
  const {
@@ -2551,11 +2498,9 @@ function getRenderedItem(ctx, state, key) {
2551
2498
  }
2552
2499
 
2553
2500
  // src/utils/throttledOnScroll.ts
2554
- function throttledOnScroll(originalHandler, scrollEventThrottle) {
2501
+ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
2555
2502
  const throttle = useThrottleDebounce("throttle");
2556
- return (event) => {
2557
- throttle(originalHandler, scrollEventThrottle, event);
2558
- };
2503
+ return (event) => throttle(originalHandler, scrollEventThrottle, { nativeEvent: event.nativeEvent });
2559
2504
  }
2560
2505
 
2561
2506
  // src/utils/updateAveragesOnDataChange.ts
@@ -2724,11 +2669,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2724
2669
  loadStartTime: Date.now(),
2725
2670
  minIndexSizeChanged: 0,
2726
2671
  nativeMarginTop: 0,
2727
- pendingAdjust: 0,
2728
2672
  positions: /* @__PURE__ */ new Map(),
2729
2673
  props: {},
2730
2674
  queuedCalculateItemsInView: 0,
2731
- queuedItemSizeUpdates: [],
2732
2675
  refScroller: void 0,
2733
2676
  scroll: 0,
2734
2677
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
@@ -2758,6 +2701,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2758
2701
  const state = refState.current;
2759
2702
  const isFirst = !state.props.renderItem;
2760
2703
  const didDataChange = state.props.data !== dataProp;
2704
+ const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
2761
2705
  state.props = {
2762
2706
  alignItemsAtEnd,
2763
2707
  data: dataProp,
@@ -2779,7 +2723,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2779
2723
  onEndReachedThreshold,
2780
2724
  onItemSizeChanged,
2781
2725
  onLoad,
2782
- onScroll: onScrollProp,
2726
+ onScroll: throttleScrollFn,
2783
2727
  onStartReached,
2784
2728
  onStartReachedThreshold,
2785
2729
  recycleItems: !!recycleItems,
@@ -3037,8 +2981,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3037
2981
  }),
3038
2982
  []
3039
2983
  );
3040
- const animatedScrollHandler = React3.useMemo(() => {
3041
- const onScrollFn = scrollEventThrottle && scrollEventThrottle > 0 ? throttledOnScroll(fns.onScroll, scrollEventThrottle) : fns.onScroll;
2984
+ const onScrollHandler = React3.useMemo(() => {
2985
+ const onScrollFn = fns.onScroll;
3042
2986
  if (stickyIndices == null ? void 0 : stickyIndices.length) {
3043
2987
  const { animatedScrollY } = ctx;
3044
2988
  return reactNative.Animated.event([{ nativeEvent: { contentOffset: { [horizontal ? "x" : "y"]: animatedScrollY } } }], {
@@ -3077,7 +3021,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3077
3021
  onMomentumScrollEnd(event);
3078
3022
  }
3079
3023
  },
3080
- onScroll: animatedScrollHandler,
3024
+ onScroll: onScrollHandler,
3081
3025
  recycleItems,
3082
3026
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControl, {
3083
3027
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
package/index.mjs CHANGED
@@ -672,30 +672,33 @@ function useThrottleDebounce(mode) {
672
672
  timeoutRef.current = null;
673
673
  }
674
674
  };
675
- const execute = useCallback((callback, delay, ...args) => {
676
- {
677
- const now = Date.now();
678
- lastArgsRef.current = args;
679
- if (now - lastCallTimeRef.current >= delay) {
680
- lastCallTimeRef.current = now;
681
- callback(...args);
682
- clearTimeoutRef();
683
- } else {
684
- clearTimeoutRef();
685
- timeoutRef.current = setTimeout(
686
- () => {
687
- if (lastArgsRef.current) {
688
- lastCallTimeRef.current = Date.now();
689
- callback(...lastArgsRef.current);
690
- timeoutRef.current = null;
691
- lastArgsRef.current = null;
692
- }
693
- },
694
- delay - (now - lastCallTimeRef.current)
695
- );
675
+ const execute = useCallback(
676
+ (callback, delay, ...args) => {
677
+ {
678
+ const now = Date.now();
679
+ lastArgsRef.current = args;
680
+ if (now - lastCallTimeRef.current >= delay) {
681
+ lastCallTimeRef.current = now;
682
+ callback(...args);
683
+ clearTimeoutRef();
684
+ } else {
685
+ clearTimeoutRef();
686
+ timeoutRef.current = setTimeout(
687
+ () => {
688
+ if (lastArgsRef.current) {
689
+ lastCallTimeRef.current = Date.now();
690
+ callback(...lastArgsRef.current);
691
+ timeoutRef.current = null;
692
+ lastArgsRef.current = null;
693
+ }
694
+ },
695
+ delay - (now - lastCallTimeRef.current)
696
+ );
697
+ }
696
698
  }
697
- }
698
- }, [mode]);
699
+ },
700
+ [mode]
701
+ );
699
702
  return execute;
700
703
  }
701
704
 
@@ -891,7 +894,7 @@ function calculateOffsetForIndex(ctx, state, index) {
891
894
  }
892
895
 
893
896
  // src/utils/getItemSize.ts
894
- function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize, preferRenderedCache) {
897
+ function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize) {
895
898
  var _a, _b;
896
899
  const {
897
900
  sizesKnown,
@@ -912,11 +915,7 @@ function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize
912
915
  sizesKnown.set(key, size);
913
916
  }
914
917
  }
915
- const renderedSize = sizes.get(key);
916
- if (size === void 0 && preferRenderedCache && renderedSize !== void 0) {
917
- return renderedSize;
918
- }
919
- if (size === void 0 && useAverageSize && !scrollingTo) {
918
+ if (size === void 0 && useAverageSize && sizeKnown === void 0 && !scrollingTo) {
920
919
  if (itemType === "") {
921
920
  size = defaultAverageSize;
922
921
  } else {
@@ -926,8 +925,11 @@ function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize
926
925
  }
927
926
  }
928
927
  }
929
- if (size === void 0 && renderedSize !== void 0) {
930
- return renderedSize;
928
+ if (size === void 0) {
929
+ size = sizes.get(key);
930
+ if (size !== void 0) {
931
+ return size;
932
+ }
931
933
  }
932
934
  if (size === void 0) {
933
935
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
@@ -1154,44 +1156,6 @@ function addTotalSize(ctx, state, key, add) {
1154
1156
  }
1155
1157
  }
1156
1158
 
1157
- // src/utils/getScrollVelocity.ts
1158
- var getScrollVelocity = (state) => {
1159
- const { scrollHistory } = state;
1160
- let velocity = 0;
1161
- if (scrollHistory.length >= 1) {
1162
- const newest = scrollHistory[scrollHistory.length - 1];
1163
- let oldest;
1164
- let start = 0;
1165
- const now = Date.now();
1166
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1167
- const entry = scrollHistory[i];
1168
- const nextEntry = scrollHistory[i + 1];
1169
- if (i > 0) {
1170
- const prevEntry = scrollHistory[i - 1];
1171
- const prevDirection = entry.scroll - prevEntry.scroll;
1172
- const currentDirection = nextEntry.scroll - entry.scroll;
1173
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1174
- start = i;
1175
- break;
1176
- }
1177
- }
1178
- }
1179
- for (let i = start; i < scrollHistory.length - 1; i++) {
1180
- const entry = scrollHistory[i];
1181
- if (now - entry.time <= 1e3) {
1182
- oldest = entry;
1183
- break;
1184
- }
1185
- }
1186
- if (oldest && oldest !== newest) {
1187
- const scrollDiff = newest.scroll - oldest.scroll;
1188
- const timeDiff = newest.time - oldest.time;
1189
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1190
- }
1191
- }
1192
- return velocity;
1193
- };
1194
-
1195
1159
  // src/utils/updateSnapToOffsets.ts
1196
1160
  function updateSnapToOffsets(ctx, state) {
1197
1161
  const {
@@ -1208,14 +1172,13 @@ function updateSnapToOffsets(ctx, state) {
1208
1172
  }
1209
1173
 
1210
1174
  // src/core/updateAllPositions.ts
1211
- function updateAllPositions(ctx, state, dataChanged) {
1212
- var _a, _b, _c, _d, _e;
1175
+ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1176
+ var _a, _b, _c, _d, _e, _f, _g;
1213
1177
  const {
1214
1178
  averageSizes,
1215
1179
  columns,
1216
1180
  indexByKey,
1217
1181
  positions,
1218
- firstFullyOnScreenIndex,
1219
1182
  idCache,
1220
1183
  sizesKnown,
1221
1184
  props: { getEstimatedItemSize, snapToIndices, enableAverages }
@@ -1223,69 +1186,34 @@ function updateAllPositions(ctx, state, dataChanged) {
1223
1186
  const data = state.props.data;
1224
1187
  const numColumns = peek$(ctx, "numColumns");
1225
1188
  const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1226
- const scrollVelocity = getScrollVelocity(state);
1227
1189
  const useAverageSize = enableAverages && !getEstimatedItemSize;
1228
1190
  const itemType = "";
1229
1191
  let averageSize = (_a = averageSizes[itemType]) == null ? void 0 : _a.avg;
1230
1192
  if (averageSize !== void 0) {
1231
1193
  averageSize = roundSize(averageSize);
1232
1194
  }
1233
- const shouldUseBackwards = !dataChanged && scrollVelocity < 0 && firstFullyOnScreenIndex > 5 && firstFullyOnScreenIndex < data.length;
1234
- if (shouldUseBackwards && firstFullyOnScreenIndex !== void 0) {
1235
- const anchorId = getId(state, firstFullyOnScreenIndex);
1236
- const anchorPosition = positions.get(anchorId);
1237
- if (anchorPosition !== void 0) {
1238
- let currentRowTop2 = anchorPosition;
1239
- let maxSizeInRow2 = 0;
1240
- let bailout = false;
1241
- for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1242
- const id = (_b = idCache.get(i)) != null ? _b : getId(state, i);
1243
- const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(
1244
- state,
1245
- id,
1246
- i,
1247
- data[i],
1248
- useAverageSize,
1249
- averageSize,
1250
- /*preferRenderedCache*/
1251
- !!dataChanged
1252
- );
1253
- const itemColumn = columns.get(id);
1254
- maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1255
- if (itemColumn === 1) {
1256
- currentRowTop2 -= maxSizeInRow2;
1257
- maxSizeInRow2 = 0;
1258
- }
1259
- if (currentRowTop2 < -2e3) {
1260
- bailout = true;
1261
- break;
1262
- }
1263
- positions.set(id, currentRowTop2);
1264
- }
1265
- if (!bailout) {
1266
- updateTotalSize(ctx, state);
1267
- return;
1268
- }
1269
- }
1270
- }
1271
1195
  let currentRowTop = 0;
1272
1196
  let column = 1;
1273
1197
  let maxSizeInRow = 0;
1274
1198
  const hasColumns = numColumns > 1;
1199
+ if (startIndex > 0) {
1200
+ const prevIndex = startIndex - 1;
1201
+ const prevId = (_b = idCache.get(prevIndex)) != null ? _b : getId(state, prevIndex);
1202
+ const prevPosition = (_c = positions.get(prevId)) != null ? _c : 0;
1203
+ if (hasColumns) {
1204
+ const prevColumn = (_d = columns.get(prevId)) != null ? _d : 1;
1205
+ currentRowTop = prevPosition;
1206
+ column = prevColumn % numColumns + 1;
1207
+ } else {
1208
+ const prevSize = (_e = sizesKnown.get(prevId)) != null ? _e : getItemSize(state, prevId, prevIndex, data[prevIndex], useAverageSize, averageSize);
1209
+ currentRowTop = prevPosition + prevSize;
1210
+ }
1211
+ }
1275
1212
  const needsIndexByKey = dataChanged || indexByKey.size === 0;
1276
1213
  const dataLength = data.length;
1277
- for (let i = 0; i < dataLength; i++) {
1278
- const id = (_d = idCache.get(i)) != null ? _d : getId(state, i);
1279
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(
1280
- state,
1281
- id,
1282
- i,
1283
- data[i],
1284
- useAverageSize,
1285
- averageSize,
1286
- /*preferRenderedCache*/
1287
- !!dataChanged
1288
- );
1214
+ for (let i = startIndex; i < dataLength; i++) {
1215
+ const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
1216
+ const size = (_g = sizesKnown.get(id)) != null ? _g : getItemSize(state, id, i, data[i], useAverageSize, averageSize);
1289
1217
  if (__DEV__ && needsIndexByKey) {
1290
1218
  if (indexByKeyForChecking.has(id)) {
1291
1219
  console.error(
@@ -1648,6 +1576,44 @@ function comparatorByDistance(a, b) {
1648
1576
  return b.distance - a.distance;
1649
1577
  }
1650
1578
 
1579
+ // src/utils/getScrollVelocity.ts
1580
+ var getScrollVelocity = (state) => {
1581
+ const { scrollHistory } = state;
1582
+ let velocity = 0;
1583
+ if (scrollHistory.length >= 1) {
1584
+ const newest = scrollHistory[scrollHistory.length - 1];
1585
+ let oldest;
1586
+ let start = 0;
1587
+ const now = Date.now();
1588
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
1589
+ const entry = scrollHistory[i];
1590
+ const nextEntry = scrollHistory[i + 1];
1591
+ if (i > 0) {
1592
+ const prevEntry = scrollHistory[i - 1];
1593
+ const prevDirection = entry.scroll - prevEntry.scroll;
1594
+ const currentDirection = nextEntry.scroll - entry.scroll;
1595
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1596
+ start = i;
1597
+ break;
1598
+ }
1599
+ }
1600
+ }
1601
+ for (let i = start; i < scrollHistory.length - 1; i++) {
1602
+ const entry = scrollHistory[i];
1603
+ if (now - entry.time <= 1e3) {
1604
+ oldest = entry;
1605
+ break;
1606
+ }
1607
+ }
1608
+ if (oldest && oldest !== newest) {
1609
+ const scrollDiff = newest.scroll - oldest.scroll;
1610
+ const timeDiff = newest.time - oldest.time;
1611
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1612
+ }
1613
+ }
1614
+ return velocity;
1615
+ };
1616
+
1651
1617
  // src/core/scrollToIndex.ts
1652
1618
  function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1653
1619
  if (index >= state.props.data.length) {
@@ -1859,7 +1825,11 @@ function calculateItemsInView(ctx, state, params = {}) {
1859
1825
  idCache.clear();
1860
1826
  positions.clear();
1861
1827
  }
1862
- updateAllPositions(ctx, state, dataChanged);
1828
+ const startIndex = dataChanged ? 0 : minIndexSizeChanged != null ? minIndexSizeChanged : 0;
1829
+ updateAllPositions(ctx, state, dataChanged, startIndex);
1830
+ if (minIndexSizeChanged !== void 0) {
1831
+ state.minIndexSizeChanged = void 0;
1832
+ }
1863
1833
  checkMVCP == null ? void 0 : checkMVCP();
1864
1834
  }
1865
1835
  const scrollExtra = 0;
@@ -1906,10 +1876,6 @@ function calculateItemsInView(ctx, state, params = {}) {
1906
1876
  let endNoBuffer = null;
1907
1877
  let endBuffered = null;
1908
1878
  let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1909
- if (minIndexSizeChanged !== void 0) {
1910
- loopStart = Math.min(minIndexSizeChanged, loopStart);
1911
- state.minIndexSizeChanged = void 0;
1912
- }
1913
1879
  for (let i = loopStart; i >= 0; i--) {
1914
1880
  const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1915
1881
  const top = positions.get(id);
@@ -2279,7 +2245,8 @@ function updateScroll(ctx, state, newScroll) {
2279
2245
  state.lastBatchingAction = Date.now();
2280
2246
  const currentTime = Date.now();
2281
2247
  if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
2282
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2248
+ const adjust = state.scrollAdjustHandler.getAdjust();
2249
+ state.scrollHistory.push({ scroll: newScroll - adjust, time: currentTime });
2283
2250
  }
2284
2251
  if (state.scrollHistory.length > 5) {
2285
2252
  state.scrollHistory.shift();
@@ -2315,13 +2282,19 @@ var ScrollAdjustHandler = class {
2315
2282
  setMounted() {
2316
2283
  this.mounted = true;
2317
2284
  }
2285
+ getAdjust() {
2286
+ return this.appliedAdjust;
2287
+ }
2318
2288
  };
2319
2289
 
2320
2290
  // src/core/updateItemSize.ts
2321
- function updateItemSizes(ctx, state, itemUpdates) {
2322
- var _a;
2291
+ function updateItemSize(ctx, state, itemKey, sizeObj) {
2292
+ var _a, _b;
2323
2293
  const {
2294
+ sizesKnown,
2324
2295
  props: {
2296
+ getFixedItemSize,
2297
+ getItemType,
2325
2298
  horizontal,
2326
2299
  maintainVisibleContentPosition,
2327
2300
  suggestEstimatedItemSize,
@@ -2331,47 +2304,60 @@ function updateItemSizes(ctx, state, itemUpdates) {
2331
2304
  }
2332
2305
  } = state;
2333
2306
  if (!data) return;
2307
+ if (getFixedItemSize) {
2308
+ const index2 = state.indexByKey.get(itemKey);
2309
+ if (index2 === void 0) {
2310
+ return;
2311
+ }
2312
+ const itemData = state.props.data[index2];
2313
+ if (itemData === void 0) {
2314
+ return;
2315
+ }
2316
+ const type = getItemType ? (_a = getItemType(itemData, index2)) != null ? _a : "" : "";
2317
+ const size2 = getFixedItemSize(index2, itemData, type);
2318
+ if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
2319
+ return;
2320
+ }
2321
+ }
2334
2322
  const containersDidLayout = peek$(ctx, "containersDidLayout");
2335
2323
  let needsRecalculate = !containersDidLayout;
2336
2324
  let shouldMaintainScrollAtEnd = false;
2337
2325
  let minIndexSizeChanged;
2338
2326
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2339
- for (const { itemKey, sizeObj } of itemUpdates) {
2340
- const index = state.indexByKey.get(itemKey);
2341
- const prevSizeKnown = state.sizesKnown.get(itemKey);
2342
- const diff = updateOneItemSize(state, itemKey, sizeObj);
2343
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2344
- if (diff !== 0) {
2345
- minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2346
- if (((_a = state.scrollingTo) == null ? void 0 : _a.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index && diff > 0) {
2347
- requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
2348
- }
2349
- const { startBuffered, endBuffered } = state;
2350
- needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2351
- if (!needsRecalculate) {
2352
- const numContainers = ctx.values.get("numContainers");
2353
- for (let i = 0; i < numContainers; i++) {
2354
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2355
- needsRecalculate = true;
2356
- break;
2357
- }
2327
+ const index = state.indexByKey.get(itemKey);
2328
+ const prevSizeKnown = state.sizesKnown.get(itemKey);
2329
+ const diff = updateOneItemSize(state, itemKey, sizeObj);
2330
+ const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2331
+ if (diff !== 0) {
2332
+ minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2333
+ if (((_b = state.scrollingTo) == null ? void 0 : _b.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index && diff > 0) {
2334
+ requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
2335
+ }
2336
+ const { startBuffered, endBuffered } = state;
2337
+ needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2338
+ if (!needsRecalculate) {
2339
+ const numContainers = ctx.values.get("numContainers");
2340
+ for (let i = 0; i < numContainers; i++) {
2341
+ if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2342
+ needsRecalculate = true;
2343
+ break;
2358
2344
  }
2359
2345
  }
2360
- if (state.needsOtherAxisSize) {
2361
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2362
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
2363
- }
2364
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2365
- shouldMaintainScrollAtEnd = true;
2366
- }
2367
- onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2368
- index,
2369
- itemData: state.props.data[index],
2370
- itemKey,
2371
- previous: size - diff,
2372
- size
2373
- });
2374
2346
  }
2347
+ if (state.needsOtherAxisSize) {
2348
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2349
+ maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
2350
+ }
2351
+ if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2352
+ shouldMaintainScrollAtEnd = true;
2353
+ }
2354
+ onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2355
+ index,
2356
+ itemData: state.props.data[index],
2357
+ itemKey,
2358
+ previous: size - diff,
2359
+ size
2360
+ });
2375
2361
  }
2376
2362
  if (minIndexSizeChanged !== void 0) {
2377
2363
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
@@ -2404,45 +2390,6 @@ function updateItemSizes(ctx, state, itemUpdates) {
2404
2390
  }
2405
2391
  }
2406
2392
  }
2407
- function updateItemSize(ctx, state, itemKey, sizeObj) {
2408
- var _a;
2409
- const {
2410
- queuedItemSizeUpdates,
2411
- queuedItemSizeUpdatesWaiting,
2412
- sizesKnown,
2413
- props: { getFixedItemSize, getItemType }
2414
- } = state;
2415
- if (getFixedItemSize) {
2416
- const index = state.indexByKey.get(itemKey);
2417
- if (index === void 0) {
2418
- return;
2419
- }
2420
- const itemData = state.props.data[index];
2421
- if (itemData === void 0) {
2422
- return;
2423
- }
2424
- const type = getItemType ? (_a = getItemType(itemData, index)) != null ? _a : "" : "";
2425
- const size = getFixedItemSize(index, itemData, type);
2426
- if (size !== void 0 && size === sizesKnown.get(itemKey)) {
2427
- return;
2428
- }
2429
- }
2430
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2431
- const speed = getScrollVelocity(state);
2432
- if (!containersDidLayout || !queuedItemSizeUpdatesWaiting || Math.abs(speed) < 1) {
2433
- updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
2434
- if (containersDidLayout) {
2435
- state.queuedItemSizeUpdatesWaiting = true;
2436
- requestAnimationFrame(() => {
2437
- state.queuedItemSizeUpdatesWaiting = false;
2438
- updateItemSizes(ctx, state, queuedItemSizeUpdates);
2439
- queuedItemSizeUpdates.length = 0;
2440
- });
2441
- }
2442
- } else {
2443
- queuedItemSizeUpdates.push({ itemKey, sizeObj });
2444
- }
2445
- }
2446
2393
  function updateOneItemSize(state, itemKey, sizeObj) {
2447
2394
  var _a;
2448
2395
  const {
@@ -2530,11 +2477,9 @@ function getRenderedItem(ctx, state, key) {
2530
2477
  }
2531
2478
 
2532
2479
  // src/utils/throttledOnScroll.ts
2533
- function throttledOnScroll(originalHandler, scrollEventThrottle) {
2480
+ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
2534
2481
  const throttle = useThrottleDebounce("throttle");
2535
- return (event) => {
2536
- throttle(originalHandler, scrollEventThrottle, event);
2537
- };
2482
+ return (event) => throttle(originalHandler, scrollEventThrottle, { nativeEvent: event.nativeEvent });
2538
2483
  }
2539
2484
 
2540
2485
  // src/utils/updateAveragesOnDataChange.ts
@@ -2703,11 +2648,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2703
2648
  loadStartTime: Date.now(),
2704
2649
  minIndexSizeChanged: 0,
2705
2650
  nativeMarginTop: 0,
2706
- pendingAdjust: 0,
2707
2651
  positions: /* @__PURE__ */ new Map(),
2708
2652
  props: {},
2709
2653
  queuedCalculateItemsInView: 0,
2710
- queuedItemSizeUpdates: [],
2711
2654
  refScroller: void 0,
2712
2655
  scroll: 0,
2713
2656
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
@@ -2737,6 +2680,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2737
2680
  const state = refState.current;
2738
2681
  const isFirst = !state.props.renderItem;
2739
2682
  const didDataChange = state.props.data !== dataProp;
2683
+ const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
2740
2684
  state.props = {
2741
2685
  alignItemsAtEnd,
2742
2686
  data: dataProp,
@@ -2758,7 +2702,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2758
2702
  onEndReachedThreshold,
2759
2703
  onItemSizeChanged,
2760
2704
  onLoad,
2761
- onScroll: onScrollProp,
2705
+ onScroll: throttleScrollFn,
2762
2706
  onStartReached,
2763
2707
  onStartReachedThreshold,
2764
2708
  recycleItems: !!recycleItems,
@@ -3016,8 +2960,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3016
2960
  }),
3017
2961
  []
3018
2962
  );
3019
- const animatedScrollHandler = useMemo(() => {
3020
- const onScrollFn = scrollEventThrottle && scrollEventThrottle > 0 ? throttledOnScroll(fns.onScroll, scrollEventThrottle) : fns.onScroll;
2963
+ const onScrollHandler = useMemo(() => {
2964
+ const onScrollFn = fns.onScroll;
3021
2965
  if (stickyIndices == null ? void 0 : stickyIndices.length) {
3022
2966
  const { animatedScrollY } = ctx;
3023
2967
  return Animated.event([{ nativeEvent: { contentOffset: { [horizontal ? "x" : "y"]: animatedScrollY } } }], {
@@ -3056,7 +3000,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3056
3000
  onMomentumScrollEnd(event);
3057
3001
  }
3058
3002
  },
3059
- onScroll: animatedScrollHandler,
3003
+ onScroll: onScrollHandler,
3060
3004
  recycleItems,
3061
3005
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
3062
3006
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "2.0.0-beta.3",
3
+ "version": "2.0.0-beta.4",
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,