@legendapp/list 2.0.13 → 2.0.15

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 2.0.15
2
+ - Fix: Container allocation for sticky headers could duplicate containers, causing rendering issues
3
+ - Fix: Sticky positioned components scrolling out of viewport after scrolling distance exceeded 5000
4
+
5
+ ## 2.0.14
6
+ - Feat: Add dataVersion prop to trigger re-render when mutating the data array in place
7
+
1
8
  ## 2.0.13
2
9
  - Feat: Allow returning undefined in getFixedItemSize to fall back to estimated size
3
10
  - Fix: scrollToIndex viewOffset was being subtracted twice, causing incorrect scroll positioning
package/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React$1 from 'react';
2
- import { ComponentProps, ReactNode, Dispatch, SetStateAction } from 'react';
2
+ import { ComponentProps, Key, ReactNode, Dispatch, SetStateAction } from 'react';
3
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
 
@@ -99,6 +99,11 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
99
99
  * Extra data to trigger re-rendering when changed.
100
100
  */
101
101
  extraData?: any;
102
+ /**
103
+ * Version token that forces the list to treat data as updated even when the array reference is stable.
104
+ * Increment or change this when mutating the data array in place.
105
+ */
106
+ dataVersion?: Key;
102
107
  /**
103
108
  * In case you have distinct item sizes, you can provide a function to get the size of an item.
104
109
  * Use instead of FlatList's getItemLayout or FlashList overrideItemLayout if you want to have accurate initialScrollOffset, you should provide this function
@@ -241,6 +246,7 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
241
246
  refreshing?: boolean;
242
247
  /**
243
248
  * Render custom ScrollView component.
249
+ * Note: When using `stickyHeaderIndices`, you must provide an Animated ScrollView component.
244
250
  * @default (props) => <ScrollView {...props} />
245
251
  */
246
252
  renderScrollComponent?: (props: ScrollViewProps) => React.ReactElement<ScrollViewProps>;
@@ -372,6 +378,7 @@ interface InternalState {
372
378
  props: {
373
379
  alignItemsAtEnd: boolean;
374
380
  data: readonly any[];
381
+ dataVersion: Key | undefined;
375
382
  estimatedItemSize: number | undefined;
376
383
  getEstimatedItemSize: LegendListProps["getEstimatedItemSize"];
377
384
  getFixedItemSize: LegendListProps["getFixedItemSize"];
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React$1 from 'react';
2
- import { ComponentProps, ReactNode, Dispatch, SetStateAction } from 'react';
2
+ import { ComponentProps, Key, ReactNode, Dispatch, SetStateAction } from 'react';
3
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
 
@@ -99,6 +99,11 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
99
99
  * Extra data to trigger re-rendering when changed.
100
100
  */
101
101
  extraData?: any;
102
+ /**
103
+ * Version token that forces the list to treat data as updated even when the array reference is stable.
104
+ * Increment or change this when mutating the data array in place.
105
+ */
106
+ dataVersion?: Key;
102
107
  /**
103
108
  * In case you have distinct item sizes, you can provide a function to get the size of an item.
104
109
  * Use instead of FlatList's getItemLayout or FlashList overrideItemLayout if you want to have accurate initialScrollOffset, you should provide this function
@@ -241,6 +246,7 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
241
246
  refreshing?: boolean;
242
247
  /**
243
248
  * Render custom ScrollView component.
249
+ * Note: When using `stickyHeaderIndices`, you must provide an Animated ScrollView component.
244
250
  * @default (props) => <ScrollView {...props} />
245
251
  */
246
252
  renderScrollComponent?: (props: ScrollViewProps) => React.ReactElement<ScrollViewProps>;
@@ -372,6 +378,7 @@ interface InternalState {
372
378
  props: {
373
379
  alignItemsAtEnd: boolean;
374
380
  data: readonly any[];
381
+ dataVersion: Key | undefined;
375
382
  estimatedItemSize: number | undefined;
376
383
  getEstimatedItemSize: LegendListProps["getEstimatedItemSize"];
377
384
  getFixedItemSize: LegendListProps["getFixedItemSize"];
package/index.js CHANGED
@@ -286,7 +286,8 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
286
286
  const transform = React2__namespace.useMemo(() => {
287
287
  if (animatedScrollY && stickyOffset !== void 0) {
288
288
  const stickyPosition = animatedScrollY.interpolate({
289
- extrapolate: "clamp",
289
+ extrapolateLeft: "clamp",
290
+ extrapolateRight: "extend",
290
291
  inputRange: [position + headerSize, position + 5e3 + headerSize],
291
292
  outputRange: [position, position + 5e3]
292
293
  });
@@ -1549,7 +1550,7 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1549
1550
  for (const containerIndex of stickyContainerPool) {
1550
1551
  const key = peek$(ctx, `containerItemKey${containerIndex}`);
1551
1552
  const isPendingRemoval = pendingRemovalSet.has(containerIndex);
1552
- if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
1553
+ if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType) && !result.includes(containerIndex)) {
1553
1554
  result.push(containerIndex);
1554
1555
  if (isPendingRemoval && pendingRemovalSet.delete(containerIndex)) {
1555
1556
  pendingRemovalChanged = true;
@@ -2738,6 +2739,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2738
2739
  columnWrapperStyle,
2739
2740
  contentContainerStyle: contentContainerStyleProp,
2740
2741
  data: dataProp = [],
2742
+ dataVersion,
2741
2743
  drawDistance = 250,
2742
2744
  enableAverages = true,
2743
2745
  estimatedItemSize: estimatedItemSizeProp,
@@ -2862,7 +2864,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2862
2864
  }
2863
2865
  const state = refState.current;
2864
2866
  const isFirst = !state.props.renderItem;
2865
- const didDataChange = state.props.data !== dataProp;
2867
+ const didDataChange = state.props.dataVersion !== dataVersion || state.props.data !== dataProp;
2866
2868
  if (didDataChange) {
2867
2869
  state.dataChangeNeedsScrollUpdate = true;
2868
2870
  }
@@ -2870,6 +2872,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2870
2872
  state.props = {
2871
2873
  alignItemsAtEnd,
2872
2874
  data: dataProp,
2875
+ dataVersion,
2873
2876
  enableAverages,
2874
2877
  estimatedItemSize,
2875
2878
  getEstimatedItemSize,
@@ -2909,7 +2912,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2909
2912
  { length: Math.min(numColumnsProp, dataProp.length) },
2910
2913
  (_, i) => getId(state, dataProp.length - 1 - i)
2911
2914
  );
2912
- }, [dataProp, numColumnsProp]);
2915
+ }, [dataProp, dataVersion, numColumnsProp]);
2913
2916
  const initializeStateVars = () => {
2914
2917
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
2915
2918
  set$(ctx, "numColumns", numColumnsProp);
@@ -2996,15 +2999,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2996
2999
  dataProp
2997
3000
  );
2998
3001
  }
2999
- }, [dataProp, numColumnsProp]);
3002
+ }, [dataProp, dataVersion, numColumnsProp]);
3000
3003
  React2.useLayoutEffect(() => {
3001
3004
  set$(ctx, "extraData", extraData);
3002
3005
  }, [extraData]);
3003
3006
  React2.useLayoutEffect(initializeStateVars, [
3007
+ dataVersion,
3004
3008
  memoizedLastItemKeys.join(","),
3005
3009
  numColumnsProp,
3006
- stylePaddingTopState,
3007
- stylePaddingBottomState
3010
+ stylePaddingBottomState,
3011
+ stylePaddingTopState
3008
3012
  ]);
3009
3013
  React2.useEffect(() => {
3010
3014
  const viewability = setupViewability({
package/index.mjs CHANGED
@@ -265,7 +265,8 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
265
265
  const transform = React2.useMemo(() => {
266
266
  if (animatedScrollY && stickyOffset !== void 0) {
267
267
  const stickyPosition = animatedScrollY.interpolate({
268
- extrapolate: "clamp",
268
+ extrapolateLeft: "clamp",
269
+ extrapolateRight: "extend",
269
270
  inputRange: [position + headerSize, position + 5e3 + headerSize],
270
271
  outputRange: [position, position + 5e3]
271
272
  });
@@ -1528,7 +1529,7 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1528
1529
  for (const containerIndex of stickyContainerPool) {
1529
1530
  const key = peek$(ctx, `containerItemKey${containerIndex}`);
1530
1531
  const isPendingRemoval = pendingRemovalSet.has(containerIndex);
1531
- if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
1532
+ if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType) && !result.includes(containerIndex)) {
1532
1533
  result.push(containerIndex);
1533
1534
  if (isPendingRemoval && pendingRemovalSet.delete(containerIndex)) {
1534
1535
  pendingRemovalChanged = true;
@@ -2717,6 +2718,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2717
2718
  columnWrapperStyle,
2718
2719
  contentContainerStyle: contentContainerStyleProp,
2719
2720
  data: dataProp = [],
2721
+ dataVersion,
2720
2722
  drawDistance = 250,
2721
2723
  enableAverages = true,
2722
2724
  estimatedItemSize: estimatedItemSizeProp,
@@ -2841,7 +2843,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2841
2843
  }
2842
2844
  const state = refState.current;
2843
2845
  const isFirst = !state.props.renderItem;
2844
- const didDataChange = state.props.data !== dataProp;
2846
+ const didDataChange = state.props.dataVersion !== dataVersion || state.props.data !== dataProp;
2845
2847
  if (didDataChange) {
2846
2848
  state.dataChangeNeedsScrollUpdate = true;
2847
2849
  }
@@ -2849,6 +2851,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2849
2851
  state.props = {
2850
2852
  alignItemsAtEnd,
2851
2853
  data: dataProp,
2854
+ dataVersion,
2852
2855
  enableAverages,
2853
2856
  estimatedItemSize,
2854
2857
  getEstimatedItemSize,
@@ -2888,7 +2891,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2888
2891
  { length: Math.min(numColumnsProp, dataProp.length) },
2889
2892
  (_, i) => getId(state, dataProp.length - 1 - i)
2890
2893
  );
2891
- }, [dataProp, numColumnsProp]);
2894
+ }, [dataProp, dataVersion, numColumnsProp]);
2892
2895
  const initializeStateVars = () => {
2893
2896
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
2894
2897
  set$(ctx, "numColumns", numColumnsProp);
@@ -2975,15 +2978,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2975
2978
  dataProp
2976
2979
  );
2977
2980
  }
2978
- }, [dataProp, numColumnsProp]);
2981
+ }, [dataProp, dataVersion, numColumnsProp]);
2979
2982
  useLayoutEffect(() => {
2980
2983
  set$(ctx, "extraData", extraData);
2981
2984
  }, [extraData]);
2982
2985
  useLayoutEffect(initializeStateVars, [
2986
+ dataVersion,
2983
2987
  memoizedLastItemKeys.join(","),
2984
2988
  numColumnsProp,
2985
- stylePaddingTopState,
2986
- stylePaddingBottomState
2989
+ stylePaddingBottomState,
2990
+ stylePaddingTopState
2987
2991
  ]);
2988
2992
  useEffect(() => {
2989
2993
  const viewability = setupViewability({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "2.0.13",
3
+ "version": "2.0.15",
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,