@legendapp/list 2.1.0-beta.0 → 2.1.0-beta.10

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,84 @@
1
+ ## 2.0.14
2
+ - Feat: Add dataVersion prop to trigger re-render when mutating the data array in place
3
+
4
+ ## 2.0.13
5
+ - Feat: Allow returning undefined in getFixedItemSize to fall back to estimated size
6
+ - Fix: scrollToIndex viewOffset was being subtracted twice, causing incorrect scroll positioning
7
+ - Fix: Initial container allocation was not applying maintainVisibleContentPosition calculations
8
+ - Fix: updateItemSize was providing full data array to getEstimatedItemSize and getFixedItemSize instead of individual item
9
+
10
+ ## 2.0.12
11
+ - Fix: Scroll velocity calculation was sometimes incorrect when item sizes were very different from estimate
12
+ - Fix: onScroll while scrolling was updating positions without maintainVisibleContentPosition calculations, which was breaking scroll position maintenance
13
+
14
+ ## 2.0.11
15
+ - Fix: Missing React import in a file
16
+
17
+ ## 2.0.10
18
+ - Feat: Add onStickyHeaderChange callback for sticky headers
19
+ - Fix: Items with a falsy value like 0 were not rendering
20
+ - Fix: Column positions sometimes not calculating correctly
21
+ - Perf: updateItemsPositions was not breaking early sometimes
22
+ - Perf: Changed idCache to be an array instead of a Map for better performance
23
+ - Perf: Speed up container reuse lookups
24
+
25
+ ## 2.0.9
26
+ - Fix: Improve initialScrollIndex accuracy and reliability
27
+
28
+ ## 2.0.8
29
+ - Fix: Data changing sometimes left blank spaces because it was ignoring scroll
30
+ - Fix: Toggling between empty and non-empty causing maintainVisibleContentPosition issues
31
+
32
+ ## 2.0.7
33
+ - Fix: Layout not working on react-native-macos because of transform instead of position
34
+
35
+ ## 2.0.6
36
+ - Fix: updateItemPositions edge case with items multiple screen heights long was breaking the loop too early
37
+
38
+ ## 2.0.5
39
+ - Perf: Change updateAllPositions to constrain processing to the scroll range
40
+ - Fix: Crash when using snapTo in some environments
41
+ - Perf: Change Separator to use useIsLastItem which should reduce the number of times it runs
42
+
43
+ ## 2.0.4
44
+ - Fix: Possible crash if refScroller is undefined
45
+
46
+ ## 2.0.3
47
+ - Feat: Set activeStickyIndex for usage in getState()
48
+ - Revert changes from 2.0.1 and 2.0.2 which were buggy in an edge case
49
+
50
+ ## 2.0.2
51
+ - Fix: Performance improvement in 2.0.1 caused a bug in an edge case
52
+
53
+ ## 2.0.1
54
+ - Perf: Improve performance in very long lists (bad release)
55
+
56
+ ## 2.0.0
57
+ Major version release with significant performance improvements and architectural changes:
58
+ - Feat: Complete rewrite of virtualization algorithm for better performance
59
+ - Feat: Add sticky headers support via stickyIndices prop
60
+ - Feat: Add snapToIndices prop for snap-to behavior
61
+ - Feat: Add getItemType prop for better item type handling
62
+ - Feat: Add getFixedItemSize prop for items with known fixed sizes
63
+ - Feat: Add itemsAreEqual prop to reduce re-rendering when data changes
64
+ - Feat: Expose positions in getState()
65
+ - Feat: Add enableAverages prop to control average size calculations
66
+ - Feat: Add viewOffset option to scrollToEnd
67
+ - Feat: Improve maintainScrollAtEnd with more granular options
68
+ - Feat: Add ref function to enable/disable scroll processing
69
+ - Feat: Support lazy rendering directly in LegendList component
70
+ - Perf: Optimize container positioning using transform instead of absolute positioning
71
+ - Perf: Improve scroll buffering algorithm with directional bias
72
+ - Perf: Enable batched updates for better rendering performance
73
+ - Perf: Optimize container allocation and reuse algorithms
74
+ - Perf: Improve average item size calculations
75
+ - Fix: Improve maintainVisibleContentPosition reliability
76
+ - Fix: Better handling of data changes and scroll position maintenance
77
+ - Fix: Improve initial scroll positioning accuracy
78
+ - Fix: Better handling of padding changes
79
+ - Fix: Resolve various edge cases with container recycling
80
+ - Fix: Improve viewability calculations
81
+
1
82
  ## 1.1.4
2
83
  - Feat: Add sizes to getState()
3
84
 
package/animated.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import * as React$1 from 'react';
2
1
  import * as _legendapp_list from '@legendapp/list';
2
+ import * as React from 'react';
3
3
  import { Animated } from 'react-native';
4
4
 
5
- declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: _legendapp_list.LegendListProps<T> & React$1.RefAttributes<_legendapp_list.LegendListRef>) => React.ReactNode) & {
5
+ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: _legendapp_list.LegendListProps<T> & React.RefAttributes<_legendapp_list.LegendListRef>) => React.ReactNode) & {
6
6
  displayName?: string;
7
7
  }>;
8
8
 
package/animated.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import * as React$1 from 'react';
2
1
  import * as _legendapp_list from '@legendapp/list';
2
+ import * as React from 'react';
3
3
  import { Animated } from 'react-native';
4
4
 
5
- declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: _legendapp_list.LegendListProps<T> & React$1.RefAttributes<_legendapp_list.LegendListRef>) => React.ReactNode) & {
5
+ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: _legendapp_list.LegendListProps<T> & React.RefAttributes<_legendapp_list.LegendListRef>) => React.ReactNode) & {
6
6
  displayName?: string;
7
7
  }>;
8
8
 
package/index.d.mts CHANGED
@@ -1,11 +1,11 @@
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, ScrollView, Animated, 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 AnimatedValue = number;
7
7
 
8
- 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" | "lastPositionUpdate";
8
+ type ListenerType = "numContainers" | "numContainersPooled" | `containerItemKey${number}` | `containerItemData${number}` | `containerPosition${number}` | `containerColumn${number}` | `containerSticky${number}` | `containerStickyOffset${number}` | "containersDidLayout" | "extraData" | "numColumns" | "lastItemKeys" | "totalSize" | "alignItemsPaddingTop" | "lastPositionUpdate" | "stylePaddingTop" | "scrollAdjust" | "scrollAdjustUserOffset" | "scrollAdjustPending" | "scrollingTo" | "headerSize" | "footerSize" | "maintainVisibleContentPosition" | "debugRawScroll" | "debugComputedScroll" | "otherAxisSize" | "snapToOffsets" | "scrollSize" | "activeStickyIndex";
9
9
  interface StateContext {
10
10
  internalState: InternalState | undefined;
11
11
  listeners: Map<ListenerType, Set<(value: any) => void>>;
@@ -28,6 +28,7 @@ interface StateContext {
28
28
 
29
29
  declare class ScrollAdjustHandler {
30
30
  private appliedAdjust;
31
+ private pendingAdjust;
31
32
  private context;
32
33
  private mounted;
33
34
  constructor(ctx: StateContext);
@@ -36,7 +37,7 @@ declare class ScrollAdjustHandler {
36
37
  getAdjust(): number;
37
38
  }
38
39
 
39
- type BaseScrollViewProps<TScrollView> = Omit<TScrollView, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children" | "onScroll">;
40
+ type BaseScrollViewProps<TScrollView> = Omit<TScrollView, "contentOffset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children" | "onScroll">;
40
41
  interface DataModeProps<ItemT, TItemType extends string | undefined> {
41
42
  /**
42
43
  * Array of items to render in the list.
@@ -101,6 +102,11 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
101
102
  * Extra data to trigger re-rendering when changed.
102
103
  */
103
104
  extraData?: any;
105
+ /**
106
+ * Version token that forces the list to treat data as updated even when the array reference is stable.
107
+ * Increment or change this when mutating the data array in place.
108
+ */
109
+ dataVersion?: Key;
104
110
  /**
105
111
  * In case you have distinct item sizes, you can provide a function to get the size of an item.
106
112
  * Use instead of FlatList's getItemLayout or FlashList overrideItemLayout if you want to have accurate initialScrollOffset, you should provide this function
@@ -124,6 +130,12 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
124
130
  index: number;
125
131
  viewOffset?: number | undefined;
126
132
  };
133
+ /**
134
+ * When true, the list initializes scrolled to the last item.
135
+ * Overrides `initialScrollIndex` and `initialScrollOffset` when data is available.
136
+ * @default false
137
+ */
138
+ initialScrollAtEnd?: boolean;
127
139
  /**
128
140
  * Component to render between items, receiving the leading item as prop.
129
141
  */
@@ -211,6 +223,13 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
211
223
  * @default 0.5
212
224
  */
213
225
  onStartReachedThreshold?: number | null | undefined;
226
+ /**
227
+ * Called when the sticky header changes.
228
+ */
229
+ onStickyHeaderChange?: (info: {
230
+ index: number;
231
+ item: any;
232
+ }) => void;
214
233
  /**
215
234
  * Called when the viewability of items changes.
216
235
  */
@@ -236,6 +255,7 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
236
255
  refreshing?: boolean;
237
256
  /**
238
257
  * Render custom ScrollView component.
258
+ * Note: When using `stickyHeaderIndices`, you must provide an Animated ScrollView component.
239
259
  * @default (props) => <ScrollView {...props} />
240
260
  */
241
261
  renderScrollComponent?: (props: ScrollViewProps) => React.ReactElement<ScrollViewProps>;
@@ -270,7 +290,7 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
270
290
  */
271
291
  stickyIndices?: number[];
272
292
  getItemType?: (item: ItemT, index: number) => TItemType;
273
- getFixedItemSize?: (index: number, item: ItemT, type: TItemType) => number;
293
+ getFixedItemSize?: (index: number, item: ItemT, type: TItemType) => number | undefined;
274
294
  itemsAreEqual?: (itemPrevious: ItemT, item: ItemT, index: number, data: readonly ItemT[]) => boolean;
275
295
  }
276
296
  type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof ScrollView> | ComponentProps<typeof Animated.ScrollView> | ComponentProps<typeof Animated$1.ScrollView>, TItemType extends string | undefined = string | undefined> = BaseScrollViewProps<TScrollView> & LegendListSpecificProps<ItemT, TItemType> & (DataModeProps<ItemT, TItemType> | ChildrenModeProps);
@@ -285,6 +305,21 @@ interface ColumnWrapperStyle {
285
305
  columnGap?: number;
286
306
  }
287
307
  type LegendListProps<ItemT = any> = LegendListPropsBase<ItemT, ComponentProps<typeof ScrollView>>;
308
+ interface ThresholdSnapshot {
309
+ scrollPosition: number;
310
+ contentSize?: number;
311
+ dataLength?: number;
312
+ atThreshold: boolean;
313
+ }
314
+ interface ScrollTarget {
315
+ offset: number;
316
+ index?: number;
317
+ viewOffset?: number;
318
+ viewPosition?: number;
319
+ animated?: boolean;
320
+ isInitialScroll?: boolean;
321
+ precomputedWithViewOffset?: boolean;
322
+ }
288
323
  interface InternalState {
289
324
  positions: Map<string, number>;
290
325
  columns: Map<string, number>;
@@ -311,6 +346,11 @@ interface InternalState {
311
346
  scrollPrev: number;
312
347
  scrollPrevTime: number;
313
348
  scrollAdjustHandler: ScrollAdjustHandler;
349
+ triggerCalculateItemsInView?: (params?: {
350
+ doMVCP?: boolean;
351
+ dataChanged?: boolean;
352
+ forceFullItemPositions?: boolean;
353
+ }) => void;
314
354
  maintainingScrollAtEnd?: boolean;
315
355
  totalSize: number;
316
356
  otherAxisSize?: number;
@@ -318,14 +358,15 @@ interface InternalState {
318
358
  timeoutSizeMessage: any;
319
359
  nativeMarginTop: number;
320
360
  indexByKey: Map<string, number>;
321
- idCache: Map<number, string>;
361
+ idCache: string[];
322
362
  viewabilityConfigCallbackPairs: ViewabilityConfigCallbackPairs<any> | undefined;
323
363
  scrollHistory: Array<{
324
364
  scroll: number;
325
365
  time: number;
326
366
  }>;
327
- startReachedBlockedByTimer: boolean;
328
- endReachedBlockedByTimer: boolean;
367
+ lastScrollAdjustForHistory?: number;
368
+ startReachedSnapshot: ThresholdSnapshot | undefined;
369
+ endReachedSnapshot: ThresholdSnapshot | undefined;
329
370
  scrollForNextCalculateItemsInView: {
330
371
  top: number;
331
372
  bottom: number;
@@ -334,19 +375,18 @@ interface InternalState {
334
375
  minIndexSizeChanged: number | undefined;
335
376
  queuedInitialLayout?: boolean | undefined;
336
377
  queuedCalculateItemsInView: number | undefined;
378
+ dataChangeNeedsScrollUpdate: boolean;
379
+ previousData?: readonly unknown[];
380
+ didColumnsChange?: boolean;
381
+ didDataChange?: boolean;
382
+ isFirst?: boolean;
337
383
  lastBatchingAction: number;
338
384
  ignoreScrollFromMVCP?: {
339
385
  lt?: number;
340
386
  gt?: number;
341
387
  };
388
+ ignoreScrollFromMVCPIgnored?: boolean;
342
389
  ignoreScrollFromMVCPTimeout?: any;
343
- scrollingTo?: {
344
- offset: number;
345
- index?: number;
346
- viewOffset?: number;
347
- viewPosition?: number;
348
- animated?: boolean;
349
- } | undefined;
350
390
  needsOtherAxisSize?: boolean;
351
391
  averageSizes: Record<string, {
352
392
  num: number;
@@ -354,17 +394,17 @@ interface InternalState {
354
394
  }>;
355
395
  refScroller: React.RefObject<ScrollView>;
356
396
  loadStartTime: number;
357
- initialScroll: ScrollIndexWithOffset | undefined;
397
+ initialScroll: ScrollIndexWithOffsetAndContentOffset | undefined;
358
398
  lastLayout: LayoutRectangle | undefined;
359
399
  timeoutSetPaddingTop?: any;
360
400
  activeStickyIndex: number | undefined;
361
401
  stickyContainers: Map<number, number>;
362
402
  stickyContainerPool: Set<number>;
363
403
  scrollProcessingEnabled: boolean;
364
- onScrollRafScheduled?: boolean;
365
404
  props: {
366
405
  alignItemsAtEnd: boolean;
367
406
  data: readonly any[];
407
+ dataVersion: Key | undefined;
368
408
  estimatedItemSize: number | undefined;
369
409
  getEstimatedItemSize: LegendListProps["getEstimatedItemSize"];
370
410
  getFixedItemSize: LegendListProps["getFixedItemSize"];
@@ -381,11 +421,11 @@ interface InternalState {
381
421
  onScroll: LegendListProps["onScroll"];
382
422
  onStartReached: LegendListProps["onStartReached"];
383
423
  onStartReachedThreshold: number | null | undefined;
424
+ onStickyHeaderChange: LegendListProps["onStickyHeaderChange"];
384
425
  recycleItems: boolean;
385
426
  suggestEstimatedItemSize: boolean;
386
427
  stylePaddingBottom: number | undefined;
387
428
  renderItem: LegendListProps["renderItem"];
388
- initialScroll: ScrollIndexWithOffset | undefined;
389
429
  scrollBuffer: number;
390
430
  numColumns: number;
391
431
  initialContainerPoolRatio: number;
@@ -412,8 +452,10 @@ interface LegendListRenderItemProps<ItemT, TItemType extends string | number | u
412
452
  extraData: any;
413
453
  }
414
454
  type ScrollState = {
455
+ activeStickyIndex: number | undefined;
415
456
  contentLength: number;
416
457
  data: readonly any[];
458
+ elementAtIndex: (index: number) => View | null | undefined;
417
459
  end: number;
418
460
  endBuffered: number;
419
461
  isAtEnd: boolean;
@@ -542,7 +584,7 @@ interface ViewAmountToken<ItemT = any> extends ViewToken<ItemT> {
542
584
  percentOfScroller: number;
543
585
  scrollSize: number;
544
586
  }
545
- interface ViewabilityConfigCallbackPair<ItemT> {
587
+ interface ViewabilityConfigCallbackPair<ItemT = any> {
546
588
  viewabilityConfig: ViewabilityConfig;
547
589
  onViewableItemsChanged?: OnViewableItemsChanged<ItemT>;
548
590
  }
@@ -601,6 +643,9 @@ interface ScrollIndexWithOffset {
601
643
  interface ScrollIndexWithOffsetPosition extends ScrollIndexWithOffset {
602
644
  viewPosition: number;
603
645
  }
646
+ interface ScrollIndexWithOffsetAndContentOffset extends ScrollIndexWithOffset {
647
+ contentOffset?: number;
648
+ }
604
649
  type GetRenderedItemResult<ItemT> = {
605
650
  index: number;
606
651
  item: ItemT;
@@ -623,4 +668,4 @@ declare function useListScrollSize(): {
623
668
  };
624
669
  declare function useSyncLayout(): () => void;
625
670
 
626
- export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type MaintainScrollAtEndOptions, type OnViewableItemsChanged, type ScrollIndexWithOffset, type ScrollIndexWithOffsetPosition, type ScrollState, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
671
+ export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type MaintainScrollAtEndOptions, type OnViewableItemsChanged, type ScrollIndexWithOffset, type ScrollIndexWithOffsetAndContentOffset, type ScrollIndexWithOffsetPosition, type ScrollState, type ScrollTarget, type ThresholdSnapshot, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
package/index.d.ts CHANGED
@@ -1,11 +1,11 @@
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, ScrollView, Animated, 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 AnimatedValue = number;
7
7
 
8
- 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" | "lastPositionUpdate";
8
+ type ListenerType = "numContainers" | "numContainersPooled" | `containerItemKey${number}` | `containerItemData${number}` | `containerPosition${number}` | `containerColumn${number}` | `containerSticky${number}` | `containerStickyOffset${number}` | "containersDidLayout" | "extraData" | "numColumns" | "lastItemKeys" | "totalSize" | "alignItemsPaddingTop" | "lastPositionUpdate" | "stylePaddingTop" | "scrollAdjust" | "scrollAdjustUserOffset" | "scrollAdjustPending" | "scrollingTo" | "headerSize" | "footerSize" | "maintainVisibleContentPosition" | "debugRawScroll" | "debugComputedScroll" | "otherAxisSize" | "snapToOffsets" | "scrollSize" | "activeStickyIndex";
9
9
  interface StateContext {
10
10
  internalState: InternalState | undefined;
11
11
  listeners: Map<ListenerType, Set<(value: any) => void>>;
@@ -28,6 +28,7 @@ interface StateContext {
28
28
 
29
29
  declare class ScrollAdjustHandler {
30
30
  private appliedAdjust;
31
+ private pendingAdjust;
31
32
  private context;
32
33
  private mounted;
33
34
  constructor(ctx: StateContext);
@@ -36,7 +37,7 @@ declare class ScrollAdjustHandler {
36
37
  getAdjust(): number;
37
38
  }
38
39
 
39
- type BaseScrollViewProps<TScrollView> = Omit<TScrollView, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children" | "onScroll">;
40
+ type BaseScrollViewProps<TScrollView> = Omit<TScrollView, "contentOffset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children" | "onScroll">;
40
41
  interface DataModeProps<ItemT, TItemType extends string | undefined> {
41
42
  /**
42
43
  * Array of items to render in the list.
@@ -101,6 +102,11 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
101
102
  * Extra data to trigger re-rendering when changed.
102
103
  */
103
104
  extraData?: any;
105
+ /**
106
+ * Version token that forces the list to treat data as updated even when the array reference is stable.
107
+ * Increment or change this when mutating the data array in place.
108
+ */
109
+ dataVersion?: Key;
104
110
  /**
105
111
  * In case you have distinct item sizes, you can provide a function to get the size of an item.
106
112
  * Use instead of FlatList's getItemLayout or FlashList overrideItemLayout if you want to have accurate initialScrollOffset, you should provide this function
@@ -124,6 +130,12 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
124
130
  index: number;
125
131
  viewOffset?: number | undefined;
126
132
  };
133
+ /**
134
+ * When true, the list initializes scrolled to the last item.
135
+ * Overrides `initialScrollIndex` and `initialScrollOffset` when data is available.
136
+ * @default false
137
+ */
138
+ initialScrollAtEnd?: boolean;
127
139
  /**
128
140
  * Component to render between items, receiving the leading item as prop.
129
141
  */
@@ -211,6 +223,13 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
211
223
  * @default 0.5
212
224
  */
213
225
  onStartReachedThreshold?: number | null | undefined;
226
+ /**
227
+ * Called when the sticky header changes.
228
+ */
229
+ onStickyHeaderChange?: (info: {
230
+ index: number;
231
+ item: any;
232
+ }) => void;
214
233
  /**
215
234
  * Called when the viewability of items changes.
216
235
  */
@@ -236,6 +255,7 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
236
255
  refreshing?: boolean;
237
256
  /**
238
257
  * Render custom ScrollView component.
258
+ * Note: When using `stickyHeaderIndices`, you must provide an Animated ScrollView component.
239
259
  * @default (props) => <ScrollView {...props} />
240
260
  */
241
261
  renderScrollComponent?: (props: ScrollViewProps) => React.ReactElement<ScrollViewProps>;
@@ -270,7 +290,7 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
270
290
  */
271
291
  stickyIndices?: number[];
272
292
  getItemType?: (item: ItemT, index: number) => TItemType;
273
- getFixedItemSize?: (index: number, item: ItemT, type: TItemType) => number;
293
+ getFixedItemSize?: (index: number, item: ItemT, type: TItemType) => number | undefined;
274
294
  itemsAreEqual?: (itemPrevious: ItemT, item: ItemT, index: number, data: readonly ItemT[]) => boolean;
275
295
  }
276
296
  type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof ScrollView> | ComponentProps<typeof Animated.ScrollView> | ComponentProps<typeof Animated$1.ScrollView>, TItemType extends string | undefined = string | undefined> = BaseScrollViewProps<TScrollView> & LegendListSpecificProps<ItemT, TItemType> & (DataModeProps<ItemT, TItemType> | ChildrenModeProps);
@@ -285,6 +305,21 @@ interface ColumnWrapperStyle {
285
305
  columnGap?: number;
286
306
  }
287
307
  type LegendListProps<ItemT = any> = LegendListPropsBase<ItemT, ComponentProps<typeof ScrollView>>;
308
+ interface ThresholdSnapshot {
309
+ scrollPosition: number;
310
+ contentSize?: number;
311
+ dataLength?: number;
312
+ atThreshold: boolean;
313
+ }
314
+ interface ScrollTarget {
315
+ offset: number;
316
+ index?: number;
317
+ viewOffset?: number;
318
+ viewPosition?: number;
319
+ animated?: boolean;
320
+ isInitialScroll?: boolean;
321
+ precomputedWithViewOffset?: boolean;
322
+ }
288
323
  interface InternalState {
289
324
  positions: Map<string, number>;
290
325
  columns: Map<string, number>;
@@ -311,6 +346,11 @@ interface InternalState {
311
346
  scrollPrev: number;
312
347
  scrollPrevTime: number;
313
348
  scrollAdjustHandler: ScrollAdjustHandler;
349
+ triggerCalculateItemsInView?: (params?: {
350
+ doMVCP?: boolean;
351
+ dataChanged?: boolean;
352
+ forceFullItemPositions?: boolean;
353
+ }) => void;
314
354
  maintainingScrollAtEnd?: boolean;
315
355
  totalSize: number;
316
356
  otherAxisSize?: number;
@@ -318,14 +358,15 @@ interface InternalState {
318
358
  timeoutSizeMessage: any;
319
359
  nativeMarginTop: number;
320
360
  indexByKey: Map<string, number>;
321
- idCache: Map<number, string>;
361
+ idCache: string[];
322
362
  viewabilityConfigCallbackPairs: ViewabilityConfigCallbackPairs<any> | undefined;
323
363
  scrollHistory: Array<{
324
364
  scroll: number;
325
365
  time: number;
326
366
  }>;
327
- startReachedBlockedByTimer: boolean;
328
- endReachedBlockedByTimer: boolean;
367
+ lastScrollAdjustForHistory?: number;
368
+ startReachedSnapshot: ThresholdSnapshot | undefined;
369
+ endReachedSnapshot: ThresholdSnapshot | undefined;
329
370
  scrollForNextCalculateItemsInView: {
330
371
  top: number;
331
372
  bottom: number;
@@ -334,19 +375,18 @@ interface InternalState {
334
375
  minIndexSizeChanged: number | undefined;
335
376
  queuedInitialLayout?: boolean | undefined;
336
377
  queuedCalculateItemsInView: number | undefined;
378
+ dataChangeNeedsScrollUpdate: boolean;
379
+ previousData?: readonly unknown[];
380
+ didColumnsChange?: boolean;
381
+ didDataChange?: boolean;
382
+ isFirst?: boolean;
337
383
  lastBatchingAction: number;
338
384
  ignoreScrollFromMVCP?: {
339
385
  lt?: number;
340
386
  gt?: number;
341
387
  };
388
+ ignoreScrollFromMVCPIgnored?: boolean;
342
389
  ignoreScrollFromMVCPTimeout?: any;
343
- scrollingTo?: {
344
- offset: number;
345
- index?: number;
346
- viewOffset?: number;
347
- viewPosition?: number;
348
- animated?: boolean;
349
- } | undefined;
350
390
  needsOtherAxisSize?: boolean;
351
391
  averageSizes: Record<string, {
352
392
  num: number;
@@ -354,17 +394,17 @@ interface InternalState {
354
394
  }>;
355
395
  refScroller: React.RefObject<ScrollView>;
356
396
  loadStartTime: number;
357
- initialScroll: ScrollIndexWithOffset | undefined;
397
+ initialScroll: ScrollIndexWithOffsetAndContentOffset | undefined;
358
398
  lastLayout: LayoutRectangle | undefined;
359
399
  timeoutSetPaddingTop?: any;
360
400
  activeStickyIndex: number | undefined;
361
401
  stickyContainers: Map<number, number>;
362
402
  stickyContainerPool: Set<number>;
363
403
  scrollProcessingEnabled: boolean;
364
- onScrollRafScheduled?: boolean;
365
404
  props: {
366
405
  alignItemsAtEnd: boolean;
367
406
  data: readonly any[];
407
+ dataVersion: Key | undefined;
368
408
  estimatedItemSize: number | undefined;
369
409
  getEstimatedItemSize: LegendListProps["getEstimatedItemSize"];
370
410
  getFixedItemSize: LegendListProps["getFixedItemSize"];
@@ -381,11 +421,11 @@ interface InternalState {
381
421
  onScroll: LegendListProps["onScroll"];
382
422
  onStartReached: LegendListProps["onStartReached"];
383
423
  onStartReachedThreshold: number | null | undefined;
424
+ onStickyHeaderChange: LegendListProps["onStickyHeaderChange"];
384
425
  recycleItems: boolean;
385
426
  suggestEstimatedItemSize: boolean;
386
427
  stylePaddingBottom: number | undefined;
387
428
  renderItem: LegendListProps["renderItem"];
388
- initialScroll: ScrollIndexWithOffset | undefined;
389
429
  scrollBuffer: number;
390
430
  numColumns: number;
391
431
  initialContainerPoolRatio: number;
@@ -412,8 +452,10 @@ interface LegendListRenderItemProps<ItemT, TItemType extends string | number | u
412
452
  extraData: any;
413
453
  }
414
454
  type ScrollState = {
455
+ activeStickyIndex: number | undefined;
415
456
  contentLength: number;
416
457
  data: readonly any[];
458
+ elementAtIndex: (index: number) => View | null | undefined;
417
459
  end: number;
418
460
  endBuffered: number;
419
461
  isAtEnd: boolean;
@@ -542,7 +584,7 @@ interface ViewAmountToken<ItemT = any> extends ViewToken<ItemT> {
542
584
  percentOfScroller: number;
543
585
  scrollSize: number;
544
586
  }
545
- interface ViewabilityConfigCallbackPair<ItemT> {
587
+ interface ViewabilityConfigCallbackPair<ItemT = any> {
546
588
  viewabilityConfig: ViewabilityConfig;
547
589
  onViewableItemsChanged?: OnViewableItemsChanged<ItemT>;
548
590
  }
@@ -601,6 +643,9 @@ interface ScrollIndexWithOffset {
601
643
  interface ScrollIndexWithOffsetPosition extends ScrollIndexWithOffset {
602
644
  viewPosition: number;
603
645
  }
646
+ interface ScrollIndexWithOffsetAndContentOffset extends ScrollIndexWithOffset {
647
+ contentOffset?: number;
648
+ }
604
649
  type GetRenderedItemResult<ItemT> = {
605
650
  index: number;
606
651
  item: ItemT;
@@ -623,4 +668,4 @@ declare function useListScrollSize(): {
623
668
  };
624
669
  declare function useSyncLayout(): () => void;
625
670
 
626
- export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type MaintainScrollAtEndOptions, type OnViewableItemsChanged, type ScrollIndexWithOffset, type ScrollIndexWithOffsetPosition, type ScrollState, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
671
+ export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type MaintainScrollAtEndOptions, type OnViewableItemsChanged, type ScrollIndexWithOffset, type ScrollIndexWithOffsetAndContentOffset, type ScrollIndexWithOffsetPosition, type ScrollState, type ScrollTarget, type ThresholdSnapshot, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };