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

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.native.mjs CHANGED
@@ -282,7 +282,8 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
282
282
  const transform = React2.useMemo(() => {
283
283
  if (animatedScrollY && stickyOffset !== void 0) {
284
284
  const stickyPosition = animatedScrollY.interpolate({
285
- extrapolate: "clamp",
285
+ extrapolateLeft: "clamp",
286
+ extrapolateRight: "extend",
286
287
  inputRange: [position + headerSize, position + 5e3 + headerSize],
287
288
  outputRange: [position, position + 5e3]
288
289
  });
@@ -332,6 +333,16 @@ function getPadding(s, type) {
332
333
  function extractPadding(style, contentContainerStyle, type) {
333
334
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
334
335
  }
336
+ function findContainerId(ctx, key) {
337
+ const numContainers = peek$(ctx, "numContainers");
338
+ for (let i = 0; i < numContainers; i++) {
339
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
340
+ if (itemKey === key) {
341
+ return i;
342
+ }
343
+ }
344
+ return -1;
345
+ }
335
346
 
336
347
  // src/state/ContextContainer.ts
337
348
  var ContextContainer = createContext(null);
@@ -882,26 +893,6 @@ function calculateOffsetForIndex(ctx, state, index) {
882
893
  return position;
883
894
  }
884
895
 
885
- // src/core/checkActualChange.ts
886
- function checkActualChange(state, dataProp, previousData) {
887
- if (!previousData || !dataProp || dataProp.length !== previousData.length) {
888
- return true;
889
- }
890
- const {
891
- idCache,
892
- props: { keyExtractor }
893
- } = state;
894
- for (let i = 0; i < dataProp.length; i++) {
895
- if (dataProp[i] !== previousData[i]) {
896
- return true;
897
- }
898
- if (keyExtractor ? idCache[i] !== keyExtractor(previousData[i], i) : dataProp[i] !== previousData[i]) {
899
- return true;
900
- }
901
- }
902
- return false;
903
- }
904
-
905
896
  // src/utils/setPaddingTop.ts
906
897
  function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
907
898
  if (stylePaddingTop !== void 0) {
@@ -991,7 +982,7 @@ function setSize(ctx, state, itemKey, size) {
991
982
  }
992
983
 
993
984
  // src/utils/getItemSize.ts
994
- function getItemSize(ctx, state, key, index, data, useAverageSize) {
985
+ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
995
986
  var _a3, _b;
996
987
  const {
997
988
  sizesKnown,
@@ -1006,6 +997,12 @@ function getItemSize(ctx, state, key, index, data, useAverageSize) {
1006
997
  let size;
1007
998
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1008
999
  const scrollingTo = peek$(ctx, "scrollingTo");
1000
+ if (preferCachedSize) {
1001
+ const cachedSize = sizes.get(key);
1002
+ if (cachedSize !== void 0) {
1003
+ return cachedSize;
1004
+ }
1005
+ }
1009
1006
  if (getFixedItemSize) {
1010
1007
  size = getFixedItemSize(index, data, itemType);
1011
1008
  if (size !== void 0) {
@@ -1215,14 +1212,13 @@ function updateScroll(ctx, state, newScroll, forceUpdate) {
1215
1212
 
1216
1213
  // src/core/finishScrollTo.ts
1217
1214
  function finishScrollTo(ctx, state) {
1218
- var _a3;
1215
+ var _a3, _b;
1219
1216
  if (state) {
1220
1217
  state.scrollHistory.length = 0;
1221
1218
  state.initialScroll = void 0;
1222
- state.isOptimizingItemPositions = false;
1223
1219
  set$(ctx, "scrollingTo", void 0);
1224
1220
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1225
- calculateItemsInView(ctx, state, { forceFullItemPositions: true });
1221
+ (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1226
1222
  }
1227
1223
  }
1228
1224
  }
@@ -1232,14 +1228,14 @@ var Platform2 = Platform;
1232
1228
  function scrollTo(ctx, state, params) {
1233
1229
  var _a3;
1234
1230
  const { noScrollingTo, ...scrollTarget } = params;
1235
- const { animated, isInitialScroll, offset: scrollTargetOffset } = scrollTarget;
1231
+ const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1236
1232
  const {
1237
1233
  refScroller,
1238
1234
  props: { horizontal }
1239
1235
  } = state;
1240
- let offset = calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1236
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1241
1237
  if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1242
- const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
1238
+ const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1243
1239
  offset = Math.min(offset, maxOffset);
1244
1240
  }
1245
1241
  state.scrollHistory.length = 0;
@@ -1501,14 +1497,14 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1501
1497
  scrollBottomBuffered: -1,
1502
1498
  startIndex: 0
1503
1499
  }) {
1504
- var _a3, _b, _c, _d;
1500
+ var _a3, _b, _c, _d, _e;
1505
1501
  const {
1506
1502
  columns,
1507
1503
  indexByKey,
1508
1504
  positions,
1509
1505
  idCache,
1510
1506
  sizesKnown,
1511
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1507
+ props: { getEstimatedItemSize, snapToIndices, enableAverages, maintainVisibleContentPosition }
1512
1508
  } = state;
1513
1509
  const data = state.props.data;
1514
1510
  const dataLength = data.length;
@@ -1517,9 +1513,9 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1517
1513
  const hasColumns = numColumns > 1;
1518
1514
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1519
1515
  const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1520
- state.isOptimizingItemPositions = shouldOptimize;
1521
1516
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1522
1517
  const useAverageSize = enableAverages && !getEstimatedItemSize;
1518
+ const preferCachedSize = maintainVisibleContentPosition && (dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0);
1523
1519
  let currentRowTop = 0;
1524
1520
  let column = 1;
1525
1521
  let maxSizeInRow = 0;
@@ -1536,8 +1532,8 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1536
1532
  } else if (startIndex < dataLength) {
1537
1533
  const prevIndex = startIndex - 1;
1538
1534
  const prevId = getId(state, prevIndex);
1539
- const prevPosition = (_a3 = positions.get(prevId)) != null ? _a3 : 0;
1540
- const prevSize = (_b = sizesKnown.get(prevId)) != null ? _b : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize);
1535
+ const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1536
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1541
1537
  currentRowTop = prevPosition + prevSize;
1542
1538
  }
1543
1539
  }
@@ -1553,8 +1549,8 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1553
1549
  const itemsPerRow = hasColumns ? numColumns : 1;
1554
1550
  breakAt = i + itemsPerRow + 10;
1555
1551
  }
1556
- const id = (_c = idCache[i]) != null ? _c : getId(state, i);
1557
- const size = (_d = sizesKnown.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i], useAverageSize);
1552
+ const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1553
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1558
1554
  if (IS_DEV && needsIndexByKey) {
1559
1555
  if (indexByKeyForChecking.has(id)) {
1560
1556
  console.error(
@@ -1772,16 +1768,6 @@ function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize,
1772
1768
  const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
1773
1769
  return value.isViewable;
1774
1770
  }
1775
- function findContainerId(ctx, key) {
1776
- const numContainers = peek$(ctx, "numContainers");
1777
- for (let i = 0; i < numContainers; i++) {
1778
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1779
- if (itemKey === key) {
1780
- return i;
1781
- }
1782
- }
1783
- return -1;
1784
- }
1785
1771
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1786
1772
  const key = containerId + configId;
1787
1773
  ctx.mapViewabilityValues.set(key, viewToken);
@@ -2314,7 +2300,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2314
2300
  for (let i = 0; i < numContainers; i++) {
2315
2301
  const itemKey = peek$(ctx, `containerItemKey${i}`);
2316
2302
  if (pendingRemoval.includes(i)) {
2317
- if (itemKey) {
2303
+ if (itemKey !== void 0) {
2318
2304
  containerItemKeys.delete(itemKey);
2319
2305
  }
2320
2306
  state.containerItemTypes.delete(i);
@@ -2375,6 +2361,26 @@ function calculateItemsInView(ctx, state, params = {}) {
2375
2361
  });
2376
2362
  }
2377
2363
 
2364
+ // src/core/checkActualChange.ts
2365
+ function checkActualChange(state, dataProp, previousData) {
2366
+ if (!previousData || !dataProp || dataProp.length !== previousData.length) {
2367
+ return true;
2368
+ }
2369
+ const {
2370
+ idCache,
2371
+ props: { keyExtractor }
2372
+ } = state;
2373
+ for (let i = 0; i < dataProp.length; i++) {
2374
+ if (dataProp[i] !== previousData[i]) {
2375
+ return true;
2376
+ }
2377
+ if (keyExtractor ? idCache[i] !== keyExtractor(previousData[i], i) : dataProp[i] !== previousData[i]) {
2378
+ return true;
2379
+ }
2380
+ }
2381
+ return false;
2382
+ }
2383
+
2378
2384
  // src/core/doMaintainScrollAtEnd.ts
2379
2385
  function doMaintainScrollAtEnd(ctx, state, animated) {
2380
2386
  const {
@@ -2909,6 +2915,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2909
2915
  columnWrapperStyle,
2910
2916
  contentContainerStyle: contentContainerStyleProp,
2911
2917
  data: dataProp = [],
2918
+ dataVersion,
2912
2919
  drawDistance = 250,
2913
2920
  enableAverages = true,
2914
2921
  estimatedItemSize: estimatedItemSizeProp,
@@ -2958,13 +2965,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2958
2965
  waitForInitialLayout = true,
2959
2966
  ...rest
2960
2967
  } = props;
2961
- const [renderNum, setRenderNum] = useState(0);
2962
- 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;
2963
- const [canRender, setCanRender] = React2.useState(!IsNewArchitecture);
2964
2968
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
2965
2969
  const style = { ...StyleSheet.flatten(styleProp) };
2966
2970
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
2967
2971
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
2972
+ const [renderNum, setRenderNum] = useState(0);
2973
+ const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState } : initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
2974
+ const [canRender, setCanRender] = React2.useState(!IsNewArchitecture);
2968
2975
  const ctx = useStateContext();
2969
2976
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
2970
2977
  const refScroller = useRef(null);
@@ -2998,7 +3005,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2998
3005
  isAtStart: false,
2999
3006
  isEndReached: false,
3000
3007
  isFirst: true,
3001
- isOptimizingItemPositions: false,
3002
3008
  isStartReached: false,
3003
3009
  lastBatchingAction: Date.now(),
3004
3010
  lastLayout: void 0,
@@ -3031,6 +3037,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3031
3037
  totalSize: 0,
3032
3038
  viewabilityConfigCallbackPairs: void 0
3033
3039
  };
3040
+ const internalState = ctx.internalState;
3041
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3034
3042
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3035
3043
  set$(ctx, "extraData", extraData);
3036
3044
  }
@@ -3039,7 +3047,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3039
3047
  const state = refState.current;
3040
3048
  const isFirstLocal = state.isFirst;
3041
3049
  state.didColumnsChange = numColumnsProp !== state.props.numColumns;
3042
- const didDataChangeLocal = state.props.data !== dataProp && checkActualChange(state, dataProp, state.props.data);
3050
+ const didDataChangeLocal = state.props.dataVersion !== dataVersion || state.props.data !== dataProp && checkActualChange(state, dataProp, state.props.data);
3043
3051
  if (didDataChangeLocal) {
3044
3052
  state.dataChangeNeedsScrollUpdate = true;
3045
3053
  state.didDataChange = true;
@@ -3049,6 +3057,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3049
3057
  state.props = {
3050
3058
  alignItemsAtEnd,
3051
3059
  data: dataProp,
3060
+ dataVersion,
3052
3061
  enableAverages,
3053
3062
  estimatedItemSize,
3054
3063
  getEstimatedItemSize,
@@ -3087,7 +3096,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3087
3096
  { length: Math.min(numColumnsProp, dataProp.length) },
3088
3097
  (_, i) => getId(state, dataProp.length - 1 - i)
3089
3098
  );
3090
- }, [dataProp, numColumnsProp]);
3099
+ }, [dataProp, dataVersion, numColumnsProp]);
3091
3100
  const initializeStateVars = () => {
3092
3101
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3093
3102
  set$(ctx, "numColumns", numColumnsProp);
@@ -3113,17 +3122,26 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3113
3122
  }
3114
3123
  const initialContentOffset = useMemo(() => {
3115
3124
  const { initialScroll } = refState.current;
3116
- if (initialScroll) {
3117
- const { index, viewOffset } = initialScroll;
3118
- let initialContentOffset2 = viewOffset || 0;
3119
- if (index !== void 0) {
3120
- initialContentOffset2 += calculateOffsetForIndex(ctx, state, index);
3121
- }
3122
- refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
3123
- return initialContentOffset2;
3124
- }
3125
- return 0;
3126
- }, [renderNum]);
3125
+ if (!initialScroll) {
3126
+ return 0;
3127
+ }
3128
+ if (initialScroll.contentOffset !== void 0) {
3129
+ return initialScroll.contentOffset;
3130
+ }
3131
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3132
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3133
+ let clampedOffset = resolvedOffset;
3134
+ if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3135
+ const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3136
+ clampedOffset = Math.min(clampedOffset, maxOffset);
3137
+ }
3138
+ clampedOffset = Math.max(0, clampedOffset);
3139
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3140
+ refState.current.initialScroll = updatedInitialScroll;
3141
+ state.initialScroll = updatedInitialScroll;
3142
+ refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3143
+ return clampedOffset;
3144
+ }, [renderNum, state.initialScroll]);
3127
3145
  if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3128
3146
  refState.current.lastBatchingAction = Date.now();
3129
3147
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
@@ -3152,9 +3170,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3152
3170
  }
3153
3171
  }, []);
3154
3172
  const doInitialScroll = useCallback(() => {
3173
+ var _a4;
3155
3174
  const initialScroll = state.initialScroll;
3156
3175
  if (initialScroll) {
3157
- scrollTo(ctx, state, { animated: false, offset: initialContentOffset, ...state.initialScroll || {} });
3176
+ scrollTo(ctx, state, {
3177
+ animated: false,
3178
+ index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3179
+ offset: initialContentOffset,
3180
+ precomputedWithViewOffset: true
3181
+ });
3158
3182
  }
3159
3183
  }, [initialContentOffset, state.initialScroll]);
3160
3184
  const onLayoutChange = useCallback((layout) => {
@@ -3186,15 +3210,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3186
3210
  state.didColumnsChange = false;
3187
3211
  state.didDataChange = false;
3188
3212
  state.isFirst = false;
3189
- }, [dataProp, numColumnsProp]);
3213
+ }, [dataProp, dataVersion, numColumnsProp]);
3190
3214
  useLayoutEffect(() => {
3191
3215
  set$(ctx, "extraData", extraData);
3192
3216
  }, [extraData]);
3193
3217
  useLayoutEffect(initializeStateVars, [
3218
+ dataVersion,
3194
3219
  memoizedLastItemKeys.join(","),
3195
3220
  numColumnsProp,
3196
- stylePaddingTopState,
3197
- stylePaddingBottomState
3221
+ stylePaddingBottomState,
3222
+ stylePaddingTopState
3198
3223
  ]);
3199
3224
  useEffect(() => {
3200
3225
  const viewability = setupViewability({
@@ -3237,6 +3262,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3237
3262
  activeStickyIndex: state2.activeStickyIndex,
3238
3263
  contentLength: state2.totalSize,
3239
3264
  data: state2.props.data,
3265
+ elementAtIndex: (index) => {
3266
+ var _a4;
3267
+ return (_a4 = ctx.viewRefs.get(findContainerId(ctx, getId(state2, index)))) == null ? void 0 : _a4.current;
3268
+ },
3240
3269
  end: state2.endNoBuffer,
3241
3270
  endBuffered: state2.endBuffered,
3242
3271
  isAtEnd: state2.isAtEnd,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "2.1.0-beta.7",
3
+ "version": "2.1.0-beta.9",
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,