@legendapp/list 2.0.0-next.1 → 2.0.0-next.3

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/animated.d.mts CHANGED
@@ -31,7 +31,7 @@ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Om
31
31
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
32
32
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
33
33
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
34
- maintainScrollAtEnd?: boolean;
34
+ maintainScrollAtEnd?: boolean | _legendapp_list.MaintainScrollAtEndOptions;
35
35
  maintainScrollAtEndThreshold?: number;
36
36
  maintainVisibleContentPosition?: boolean;
37
37
  numColumns?: number;
@@ -65,6 +65,7 @@ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Om
65
65
  onLoad?: (info: {
66
66
  elapsedTimeInMs: number;
67
67
  }) => void;
68
+ snapToIndices?: number[];
68
69
  } & React$1.RefAttributes<_legendapp_list.LegendListRef>) => React.ReactNode)>;
69
70
 
70
71
  export { AnimatedLegendList };
package/animated.d.ts CHANGED
@@ -31,7 +31,7 @@ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Om
31
31
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
32
32
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
33
33
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
34
- maintainScrollAtEnd?: boolean;
34
+ maintainScrollAtEnd?: boolean | _legendapp_list.MaintainScrollAtEndOptions;
35
35
  maintainScrollAtEndThreshold?: number;
36
36
  maintainVisibleContentPosition?: boolean;
37
37
  numColumns?: number;
@@ -65,6 +65,7 @@ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Om
65
65
  onLoad?: (info: {
66
66
  elapsedTimeInMs: number;
67
67
  }) => void;
68
+ snapToIndices?: number[];
68
69
  } & React$1.RefAttributes<_legendapp_list.LegendListRef>) => React.ReactNode)>;
69
70
 
70
71
  export { AnimatedLegendList };
package/index.d.mts CHANGED
@@ -1,11 +1,11 @@
1
1
  import * as React$1 from 'react';
2
2
  import { ComponentProps, ReactNode, Dispatch, SetStateAction } from 'react';
3
3
  import * as react_native from 'react-native';
4
- import { View, ScrollView, StyleProp, ViewStyle, ScrollViewProps, NativeSyntheticEvent, NativeScrollEvent, ScrollViewComponent, ScrollResponderMixin } from 'react-native';
5
- import Animated from 'react-native-reanimated';
4
+ import { View, ScrollView, Animated, StyleProp, ViewStyle, ScrollViewProps, LayoutRectangle, NativeSyntheticEvent, NativeScrollEvent, ScrollViewComponent, ScrollResponderMixin } from 'react-native';
5
+ import Animated$1 from 'react-native-reanimated';
6
6
  import * as _legendapp_list_reanimated from '@legendapp/list/reanimated';
7
7
 
8
- type ListenerType = "numContainers" | "numContainersPooled" | `containerItemKey${number}` | `containerItemData${number}` | `containerPosition${number}` | `containerColumn${number}` | "containersDidLayout" | "extraData" | "numColumns" | "lastItemKeys" | "totalSize" | "alignItemsPaddingTop" | "stylePaddingTop" | "scrollAdjust" | "scrollAdjustUserOffset" | "headerSize" | "footerSize" | "maintainVisibleContentPosition" | "debugRawScroll" | "debugComputedScroll" | "otherAxisSize" | "scrollSize";
8
+ type ListenerType = "numContainers" | "numContainersPooled" | `containerItemKey${number}` | `containerItemData${number}` | `containerPosition${number}` | `containerColumn${number}` | "containersDidLayout" | "extraData" | "numColumns" | "lastItemKeys" | "totalSize" | "alignItemsPaddingTop" | "stylePaddingTop" | "scrollAdjust" | "scrollAdjustUserOffset" | "headerSize" | "footerSize" | "maintainVisibleContentPosition" | "debugRawScroll" | "debugComputedScroll" | "otherAxisSize" | "snapToOffsets" | "scrollSize";
9
9
  interface StateContext {
10
10
  listeners: Map<ListenerType, Set<(value: any) => void>>;
11
11
  values: Map<ListenerType, any>;
@@ -26,7 +26,7 @@ declare class ScrollAdjustHandler {
26
26
  setMounted(): void;
27
27
  }
28
28
 
29
- type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof ScrollView> | ComponentProps<typeof Animated.ScrollView>> = Omit<TScrollView, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
29
+ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof ScrollView> | ComponentProps<typeof Animated.ScrollView> | ComponentProps<typeof Animated$1.ScrollView>> = Omit<TScrollView, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
30
30
  /**
31
31
  * If true, aligns items at the end of the list.
32
32
  * @default false
@@ -122,7 +122,7 @@ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof Scroll
122
122
  * If true, auto-scrolls to end when new items are added.
123
123
  * @default false
124
124
  */
125
- maintainScrollAtEnd?: boolean;
125
+ maintainScrollAtEnd?: boolean | MaintainScrollAtEndOptions;
126
126
  /**
127
127
  * Distance threshold in percentage of screen size to trigger maintainScrollAtEnd.
128
128
  * @default 0.1
@@ -232,7 +232,13 @@ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof Scroll
232
232
  onLoad?: (info: {
233
233
  elapsedTimeInMs: number;
234
234
  }) => void;
235
+ snapToIndices?: number[];
235
236
  };
237
+ interface MaintainScrollAtEndOptions {
238
+ onLayout?: boolean;
239
+ onItemLayout?: boolean;
240
+ onDataChange?: boolean;
241
+ }
236
242
  interface ColumnWrapperStyle {
237
243
  rowGap?: number;
238
244
  gap?: number;
@@ -309,6 +315,7 @@ interface InternalState {
309
315
  refScroller: React.RefObject<ScrollView>;
310
316
  loadStartTime: number;
311
317
  initialScroll: ScrollIndexWithOffsetPosition | undefined;
318
+ lastLayout: LayoutRectangle | undefined;
312
319
  props: {
313
320
  alignItemsAtEnd: boolean;
314
321
  data: readonly any[];
@@ -316,7 +323,7 @@ interface InternalState {
316
323
  getEstimatedItemSize: ((index: number, item: any) => number) | undefined;
317
324
  horizontal: boolean;
318
325
  keyExtractor: ((item: any, index: number) => string) | undefined;
319
- maintainScrollAtEnd: boolean;
326
+ maintainScrollAtEnd: boolean | MaintainScrollAtEndOptions;
320
327
  maintainScrollAtEndThreshold: number | undefined;
321
328
  maintainVisibleContentPosition: boolean;
322
329
  onEndReached: (((info: {
@@ -351,6 +358,7 @@ interface InternalState {
351
358
  numColumns: number;
352
359
  initialContainerPoolRatio: number;
353
360
  stylePaddingTop: number | undefined;
361
+ snapToIndices: number[] | undefined;
354
362
  };
355
363
  }
356
364
  interface ViewableRange<T> {
@@ -371,6 +379,7 @@ type ScrollState = {
371
379
  endBuffered: number;
372
380
  isAtEnd: boolean;
373
381
  isAtStart: boolean;
382
+ positions: Map<string, number>;
374
383
  scroll: number;
375
384
  scrollLength: number;
376
385
  start: number;
@@ -578,7 +587,7 @@ declare const LegendList: <T>(props: Omit<Omit<react_native.ScrollViewProps, "sc
578
587
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
579
588
  ListHeaderComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
580
589
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
581
- maintainScrollAtEnd?: boolean;
590
+ maintainScrollAtEnd?: boolean | MaintainScrollAtEndOptions;
582
591
  maintainScrollAtEndThreshold?: number;
583
592
  maintainVisibleContentPosition?: boolean;
584
593
  numColumns?: number;
@@ -612,6 +621,7 @@ declare const LegendList: <T>(props: Omit<Omit<react_native.ScrollViewProps, "sc
612
621
  onLoad?: (info: {
613
622
  elapsedTimeInMs: number;
614
623
  }) => void;
624
+ snapToIndices?: number[];
615
625
  } & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode;
616
626
 
617
627
  interface LazyLegendListProps<ItemT, ListT> extends Omit<LegendListProps<ItemT>, "data" | "keyExtractor" | "renderItem"> {
@@ -646,7 +656,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
646
656
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
647
657
  ListHeaderComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
648
658
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
649
- maintainScrollAtEnd?: boolean;
659
+ maintainScrollAtEnd?: boolean | MaintainScrollAtEndOptions;
650
660
  maintainScrollAtEndThreshold?: number;
651
661
  maintainVisibleContentPosition?: boolean;
652
662
  numColumns?: number;
@@ -680,6 +690,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
680
690
  onLoad?: (info: {
681
691
  elapsedTimeInMs: number;
682
692
  }) => void;
693
+ snapToIndices?: number[];
683
694
  } & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode) | react_native.Animated.AnimatedComponent<(<T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
684
695
  alignItemsAtEnd?: boolean;
685
696
  columnWrapperStyle?: ColumnWrapperStyle;
@@ -708,7 +719,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
708
719
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
709
720
  ListHeaderComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
710
721
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
711
- maintainScrollAtEnd?: boolean;
722
+ maintainScrollAtEnd?: boolean | MaintainScrollAtEndOptions;
712
723
  maintainScrollAtEndThreshold?: number;
713
724
  maintainVisibleContentPosition?: boolean;
714
725
  numColumns?: number;
@@ -742,6 +753,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
742
753
  onLoad?: (info: {
743
754
  elapsedTimeInMs: number;
744
755
  }) => void;
756
+ snapToIndices?: number[];
745
757
  } & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode)> | (<ItemT_1>(props: _legendapp_list_reanimated.AnimatedLegendListProps<ItemT_1> & {
746
758
  ref?: React$1.Ref<LegendListRef>;
747
759
  }) => React$1.ReactElement | null) = <T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
@@ -772,7 +784,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
772
784
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
773
785
  ListHeaderComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
774
786
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
775
- maintainScrollAtEnd?: boolean;
787
+ maintainScrollAtEnd?: boolean | MaintainScrollAtEndOptions;
776
788
  maintainScrollAtEndThreshold?: number;
777
789
  maintainVisibleContentPosition?: boolean;
778
790
  numColumns?: number;
@@ -806,6 +818,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
806
818
  onLoad?: (info: {
807
819
  elapsedTimeInMs: number;
808
820
  }) => void;
821
+ snapToIndices?: number[];
809
822
  } & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode>(props: LazyLegendListProps<ItemT, ListT> & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode;
810
823
 
811
824
  declare function useViewability(callback: ViewabilityCallback, configId?: string): void;
@@ -818,4 +831,4 @@ declare function useListScrollSize(): {
818
831
  height: number;
819
832
  };
820
833
 
821
- export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InternalState, LazyLegendList, type LazyLegendListProps, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type OnViewableItemsChanged, 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, useViewability, useViewabilityAmount };
834
+ export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InternalState, LazyLegendList, type LazyLegendListProps, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type MaintainScrollAtEndOptions, type OnViewableItemsChanged, 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, useViewability, useViewabilityAmount };
package/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import * as React$1 from 'react';
2
2
  import { ComponentProps, ReactNode, Dispatch, SetStateAction } from 'react';
3
3
  import * as react_native from 'react-native';
4
- import { View, ScrollView, StyleProp, ViewStyle, ScrollViewProps, NativeSyntheticEvent, NativeScrollEvent, ScrollViewComponent, ScrollResponderMixin } from 'react-native';
5
- import Animated from 'react-native-reanimated';
4
+ import { View, ScrollView, Animated, StyleProp, ViewStyle, ScrollViewProps, LayoutRectangle, NativeSyntheticEvent, NativeScrollEvent, ScrollViewComponent, ScrollResponderMixin } from 'react-native';
5
+ import Animated$1 from 'react-native-reanimated';
6
6
  import * as _legendapp_list_reanimated from '@legendapp/list/reanimated';
7
7
 
8
- type ListenerType = "numContainers" | "numContainersPooled" | `containerItemKey${number}` | `containerItemData${number}` | `containerPosition${number}` | `containerColumn${number}` | "containersDidLayout" | "extraData" | "numColumns" | "lastItemKeys" | "totalSize" | "alignItemsPaddingTop" | "stylePaddingTop" | "scrollAdjust" | "scrollAdjustUserOffset" | "headerSize" | "footerSize" | "maintainVisibleContentPosition" | "debugRawScroll" | "debugComputedScroll" | "otherAxisSize" | "scrollSize";
8
+ type ListenerType = "numContainers" | "numContainersPooled" | `containerItemKey${number}` | `containerItemData${number}` | `containerPosition${number}` | `containerColumn${number}` | "containersDidLayout" | "extraData" | "numColumns" | "lastItemKeys" | "totalSize" | "alignItemsPaddingTop" | "stylePaddingTop" | "scrollAdjust" | "scrollAdjustUserOffset" | "headerSize" | "footerSize" | "maintainVisibleContentPosition" | "debugRawScroll" | "debugComputedScroll" | "otherAxisSize" | "snapToOffsets" | "scrollSize";
9
9
  interface StateContext {
10
10
  listeners: Map<ListenerType, Set<(value: any) => void>>;
11
11
  values: Map<ListenerType, any>;
@@ -26,7 +26,7 @@ declare class ScrollAdjustHandler {
26
26
  setMounted(): void;
27
27
  }
28
28
 
29
- type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof ScrollView> | ComponentProps<typeof Animated.ScrollView>> = Omit<TScrollView, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
29
+ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof ScrollView> | ComponentProps<typeof Animated.ScrollView> | ComponentProps<typeof Animated$1.ScrollView>> = Omit<TScrollView, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
30
30
  /**
31
31
  * If true, aligns items at the end of the list.
32
32
  * @default false
@@ -122,7 +122,7 @@ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof Scroll
122
122
  * If true, auto-scrolls to end when new items are added.
123
123
  * @default false
124
124
  */
125
- maintainScrollAtEnd?: boolean;
125
+ maintainScrollAtEnd?: boolean | MaintainScrollAtEndOptions;
126
126
  /**
127
127
  * Distance threshold in percentage of screen size to trigger maintainScrollAtEnd.
128
128
  * @default 0.1
@@ -232,7 +232,13 @@ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof Scroll
232
232
  onLoad?: (info: {
233
233
  elapsedTimeInMs: number;
234
234
  }) => void;
235
+ snapToIndices?: number[];
235
236
  };
237
+ interface MaintainScrollAtEndOptions {
238
+ onLayout?: boolean;
239
+ onItemLayout?: boolean;
240
+ onDataChange?: boolean;
241
+ }
236
242
  interface ColumnWrapperStyle {
237
243
  rowGap?: number;
238
244
  gap?: number;
@@ -309,6 +315,7 @@ interface InternalState {
309
315
  refScroller: React.RefObject<ScrollView>;
310
316
  loadStartTime: number;
311
317
  initialScroll: ScrollIndexWithOffsetPosition | undefined;
318
+ lastLayout: LayoutRectangle | undefined;
312
319
  props: {
313
320
  alignItemsAtEnd: boolean;
314
321
  data: readonly any[];
@@ -316,7 +323,7 @@ interface InternalState {
316
323
  getEstimatedItemSize: ((index: number, item: any) => number) | undefined;
317
324
  horizontal: boolean;
318
325
  keyExtractor: ((item: any, index: number) => string) | undefined;
319
- maintainScrollAtEnd: boolean;
326
+ maintainScrollAtEnd: boolean | MaintainScrollAtEndOptions;
320
327
  maintainScrollAtEndThreshold: number | undefined;
321
328
  maintainVisibleContentPosition: boolean;
322
329
  onEndReached: (((info: {
@@ -351,6 +358,7 @@ interface InternalState {
351
358
  numColumns: number;
352
359
  initialContainerPoolRatio: number;
353
360
  stylePaddingTop: number | undefined;
361
+ snapToIndices: number[] | undefined;
354
362
  };
355
363
  }
356
364
  interface ViewableRange<T> {
@@ -371,6 +379,7 @@ type ScrollState = {
371
379
  endBuffered: number;
372
380
  isAtEnd: boolean;
373
381
  isAtStart: boolean;
382
+ positions: Map<string, number>;
374
383
  scroll: number;
375
384
  scrollLength: number;
376
385
  start: number;
@@ -578,7 +587,7 @@ declare const LegendList: <T>(props: Omit<Omit<react_native.ScrollViewProps, "sc
578
587
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
579
588
  ListHeaderComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
580
589
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
581
- maintainScrollAtEnd?: boolean;
590
+ maintainScrollAtEnd?: boolean | MaintainScrollAtEndOptions;
582
591
  maintainScrollAtEndThreshold?: number;
583
592
  maintainVisibleContentPosition?: boolean;
584
593
  numColumns?: number;
@@ -612,6 +621,7 @@ declare const LegendList: <T>(props: Omit<Omit<react_native.ScrollViewProps, "sc
612
621
  onLoad?: (info: {
613
622
  elapsedTimeInMs: number;
614
623
  }) => void;
624
+ snapToIndices?: number[];
615
625
  } & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode;
616
626
 
617
627
  interface LazyLegendListProps<ItemT, ListT> extends Omit<LegendListProps<ItemT>, "data" | "keyExtractor" | "renderItem"> {
@@ -646,7 +656,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
646
656
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
647
657
  ListHeaderComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
648
658
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
649
- maintainScrollAtEnd?: boolean;
659
+ maintainScrollAtEnd?: boolean | MaintainScrollAtEndOptions;
650
660
  maintainScrollAtEndThreshold?: number;
651
661
  maintainVisibleContentPosition?: boolean;
652
662
  numColumns?: number;
@@ -680,6 +690,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
680
690
  onLoad?: (info: {
681
691
  elapsedTimeInMs: number;
682
692
  }) => void;
693
+ snapToIndices?: number[];
683
694
  } & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode) | react_native.Animated.AnimatedComponent<(<T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
684
695
  alignItemsAtEnd?: boolean;
685
696
  columnWrapperStyle?: ColumnWrapperStyle;
@@ -708,7 +719,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
708
719
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
709
720
  ListHeaderComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
710
721
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
711
- maintainScrollAtEnd?: boolean;
722
+ maintainScrollAtEnd?: boolean | MaintainScrollAtEndOptions;
712
723
  maintainScrollAtEndThreshold?: number;
713
724
  maintainVisibleContentPosition?: boolean;
714
725
  numColumns?: number;
@@ -742,6 +753,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
742
753
  onLoad?: (info: {
743
754
  elapsedTimeInMs: number;
744
755
  }) => void;
756
+ snapToIndices?: number[];
745
757
  } & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode)> | (<ItemT_1>(props: _legendapp_list_reanimated.AnimatedLegendListProps<ItemT_1> & {
746
758
  ref?: React$1.Ref<LegendListRef>;
747
759
  }) => React$1.ReactElement | null) = <T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
@@ -772,7 +784,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
772
784
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
773
785
  ListHeaderComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
774
786
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
775
- maintainScrollAtEnd?: boolean;
787
+ maintainScrollAtEnd?: boolean | MaintainScrollAtEndOptions;
776
788
  maintainScrollAtEndThreshold?: number;
777
789
  maintainVisibleContentPosition?: boolean;
778
790
  numColumns?: number;
@@ -806,6 +818,7 @@ declare const LazyLegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_
806
818
  onLoad?: (info: {
807
819
  elapsedTimeInMs: number;
808
820
  }) => void;
821
+ snapToIndices?: number[];
809
822
  } & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode>(props: LazyLegendListProps<ItemT, ListT> & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode;
810
823
 
811
824
  declare function useViewability(callback: ViewabilityCallback, configId?: string): void;
@@ -818,4 +831,4 @@ declare function useListScrollSize(): {
818
831
  height: number;
819
832
  };
820
833
 
821
- export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InternalState, LazyLegendList, type LazyLegendListProps, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type OnViewableItemsChanged, 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, useViewability, useViewabilityAmount };
834
+ export { type ColumnWrapperStyle, type GetRenderedItem, type GetRenderedItemResult, type InternalState, LazyLegendList, type LazyLegendListProps, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type MaintainScrollAtEndOptions, type OnViewableItemsChanged, 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, useViewability, useViewabilityAmount };
package/index.js CHANGED
@@ -573,6 +573,13 @@ function ScrollAdjust() {
573
573
  }
574
574
  );
575
575
  }
576
+
577
+ // src/SnapWrapper.tsx
578
+ function SnapWrapper({ ScrollComponent, ...props }) {
579
+ const [snapToOffsets] = useArr$(["snapToOffsets"]);
580
+ console.log("snapToOffsets", snapToOffsets);
581
+ return /* @__PURE__ */ React.createElement(ScrollComponent, { ...props, snapToOffsets });
582
+ }
576
583
  function useSyncLayout({
577
584
  onChange
578
585
  }) {
@@ -647,6 +654,7 @@ var ListComponent = typedMemo(function ListComponent2({
647
654
  renderScrollComponent,
648
655
  scrollAdjustHandler,
649
656
  onLayoutHeader,
657
+ snapToIndices,
650
658
  ...rest
651
659
  }) {
652
660
  const ctx = useStateContext();
@@ -664,10 +672,12 @@ var ListComponent = typedMemo(function ListComponent2({
664
672
  }, 0);
665
673
  }
666
674
  }, [canRender]);
675
+ const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
667
676
  return /* @__PURE__ */ React3__namespace.createElement(
668
- ScrollComponent,
677
+ SnapOrScroll,
669
678
  {
670
679
  ...rest,
680
+ ScrollComponent: snapToIndices ? ScrollComponent : void 0,
671
681
  style,
672
682
  maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
673
683
  contentContainerStyle: [
@@ -932,26 +942,27 @@ function requestAdjust(ctx, state, positionDiff) {
932
942
  };
933
943
  state.scroll += positionDiff;
934
944
  state.scrollForNextCalculateItemsInView = void 0;
935
- if (peek$(ctx, "containersDidLayout")) {
945
+ const didLayout = peek$(ctx, "containersDidLayout");
946
+ if (didLayout) {
936
947
  doit();
948
+ const threshold = state.scroll - positionDiff / 2;
949
+ if (!state.ignoreScrollFromMVCP) {
950
+ state.ignoreScrollFromMVCP = {};
951
+ }
952
+ if (positionDiff > 0) {
953
+ state.ignoreScrollFromMVCP.lt = threshold;
954
+ } else {
955
+ state.ignoreScrollFromMVCP.gt = threshold;
956
+ }
957
+ if (state.ignoreScrollFromMVCPTimeout) {
958
+ clearTimeout(state.ignoreScrollFromMVCPTimeout);
959
+ }
960
+ state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
961
+ state.ignoreScrollFromMVCP = void 0;
962
+ }, 100);
937
963
  } else {
938
964
  requestAnimationFrame(doit);
939
965
  }
940
- const threshold = state.scroll - positionDiff / 2;
941
- if (!state.ignoreScrollFromMVCP) {
942
- state.ignoreScrollFromMVCP = {};
943
- }
944
- if (positionDiff > 0) {
945
- state.ignoreScrollFromMVCP.lt = threshold;
946
- } else {
947
- state.ignoreScrollFromMVCP.gt = threshold;
948
- }
949
- if (state.ignoreScrollFromMVCPTimeout) {
950
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
951
- }
952
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
953
- state.ignoreScrollFromMVCP = void 0;
954
- }, 100);
955
966
  }
956
967
  }
957
968
 
@@ -1119,6 +1130,21 @@ function setDidLayout(ctx, state) {
1119
1130
  }
1120
1131
  }
1121
1132
 
1133
+ // src/updateSnapToOffsets.ts
1134
+ function updateSnapToOffsets(ctx, state) {
1135
+ const {
1136
+ positions,
1137
+ props: { snapToIndices }
1138
+ } = state;
1139
+ const snapToOffsets = Array(snapToIndices.length);
1140
+ for (let i = 0; i < snapToIndices.length; i++) {
1141
+ const idx = snapToIndices[i];
1142
+ const key = getId(state, idx);
1143
+ snapToOffsets[i] = positions.get(key);
1144
+ }
1145
+ set$(ctx, "snapToOffsets", snapToOffsets);
1146
+ }
1147
+
1122
1148
  // src/setPaddingTop.ts
1123
1149
  function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1124
1150
  if (stylePaddingTop !== void 0) {
@@ -1189,7 +1215,16 @@ function addTotalSize(ctx, state, key, add) {
1189
1215
  // src/updateAllPositions.ts
1190
1216
  function updateAllPositions(ctx, state, dataChanged) {
1191
1217
  var _a, _b, _c, _d, _e;
1192
- const { averageSizes, columns, indexByKey, positions, firstFullyOnScreenIndex, idCache, sizesKnown } = state;
1218
+ const {
1219
+ averageSizes,
1220
+ columns,
1221
+ indexByKey,
1222
+ positions,
1223
+ firstFullyOnScreenIndex,
1224
+ idCache,
1225
+ sizesKnown,
1226
+ props: { snapToIndices }
1227
+ } = state;
1193
1228
  const data = state.props.data;
1194
1229
  const numColumns = peek$(ctx, "numColumns");
1195
1230
  const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
@@ -1269,6 +1304,9 @@ function updateAllPositions(ctx, state, dataChanged) {
1269
1304
  }
1270
1305
  }
1271
1306
  updateTotalSize(ctx, state);
1307
+ if (snapToIndices) {
1308
+ updateSnapToOffsets(ctx, state);
1309
+ }
1272
1310
  }
1273
1311
 
1274
1312
  // src/viewability.ts
@@ -1845,9 +1883,12 @@ function getRenderedItem(ctx, state, key) {
1845
1883
  }
1846
1884
 
1847
1885
  // src/handleLayout.ts
1848
- function handleLayout(ctx, state, size, setCanRender) {
1849
- const scrollLength = size[state.props.horizontal ? "width" : "height"];
1850
- const otherAxisSize = size[state.props.horizontal ? "height" : "width"];
1886
+ function handleLayout(ctx, state, layout, setCanRender) {
1887
+ const { maintainScrollAtEnd } = state.props;
1888
+ const scrollLength = layout[state.props.horizontal ? "width" : "height"];
1889
+ const otherAxisSize = layout[state.props.horizontal ? "height" : "width"];
1890
+ const needsCalculate = !state.lastLayout || scrollLength > state.scrollLength || state.lastLayout.x !== layout.x || state.lastLayout.y !== layout.y;
1891
+ state.lastLayout = layout;
1851
1892
  const didChange = scrollLength !== state.scrollLength;
1852
1893
  const prevOtherAxisSize = state.otherAxisSize;
1853
1894
  state.scrollLength = scrollLength;
@@ -1855,13 +1896,15 @@ function handleLayout(ctx, state, size, setCanRender) {
1855
1896
  state.lastBatchingAction = Date.now();
1856
1897
  state.scrollForNextCalculateItemsInView = void 0;
1857
1898
  doInitialAllocateContainers(ctx, state);
1858
- if (didChange) {
1899
+ if (needsCalculate) {
1859
1900
  calculateItemsInView(ctx, state, { doMVCP: true });
1860
1901
  }
1861
1902
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
1862
- set$(ctx, "scrollSize", { width: size.width, height: size.height });
1903
+ set$(ctx, "scrollSize", { width: layout.width, height: layout.height });
1904
+ }
1905
+ if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
1906
+ doMaintainScrollAtEnd(ctx, state, false);
1863
1907
  }
1864
- doMaintainScrollAtEnd(ctx, state, false);
1865
1908
  updateAlignItemsPaddingTop(ctx, state);
1866
1909
  checkAtBottom(ctx, state);
1867
1910
  checkAtTop(state);
@@ -1874,7 +1917,6 @@ function handleLayout(ctx, state, size, setCanRender) {
1874
1917
  `List ${state.props.horizontal ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
1875
1918
  );
1876
1919
  }
1877
- calculateItemsInView(ctx, state, { doMVCP: true });
1878
1920
  setCanRender(true);
1879
1921
  }
1880
1922
 
@@ -1920,7 +1962,14 @@ function updateScroll(ctx, state, newScroll) {
1920
1962
  function updateItemSizes(ctx, state, itemUpdates) {
1921
1963
  var _a;
1922
1964
  const {
1923
- props: { horizontal, maintainVisibleContentPosition, suggestEstimatedItemSize, onItemSizeChanged, data }
1965
+ props: {
1966
+ horizontal,
1967
+ maintainVisibleContentPosition,
1968
+ suggestEstimatedItemSize,
1969
+ onItemSizeChanged,
1970
+ data,
1971
+ maintainScrollAtEnd
1972
+ }
1924
1973
  } = state;
1925
1974
  if (!data) return;
1926
1975
  let needsRecalculate = false;
@@ -1990,12 +2039,13 @@ function updateItemSizes(ctx, state, itemUpdates) {
1990
2039
  calculateItemsInView(ctx, state, { doMVCP: true });
1991
2040
  }
1992
2041
  if (shouldMaintainScrollAtEnd) {
1993
- doMaintainScrollAtEnd(ctx, state, false);
2042
+ if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2043
+ doMaintainScrollAtEnd(ctx, state, false);
2044
+ }
1994
2045
  }
1995
2046
  }
1996
2047
  }
1997
2048
  function updateItemSize(ctx, state, itemKey, sizeObj) {
1998
- var _a, _b;
1999
2049
  if (IsNewArchitecture) {
2000
2050
  const { sizesKnown } = state;
2001
2051
  const numContainers = ctx.values.get("numContainers");
@@ -2006,8 +2056,11 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2006
2056
  changes.push({ itemKey, sizeObj });
2007
2057
  } else if (!sizesKnown.has(containerItemKey) && containerItemKey !== void 0) {
2008
2058
  const containerRef = ctx.viewRefs.get(i);
2009
- if (containerRef) {
2010
- const measured = (_b = (_a = containerRef.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
2059
+ if (containerRef == null ? void 0 : containerRef.current) {
2060
+ let measured;
2061
+ containerRef.current.measure((x, y, width, height) => {
2062
+ measured = { x, y, width, height };
2063
+ });
2011
2064
  if (measured) {
2012
2065
  changes.push({ itemKey: containerItemKey, sizeObj: measured });
2013
2066
  }
@@ -2110,6 +2163,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2110
2163
  initialContainerPoolRatio = 2,
2111
2164
  viewabilityConfig,
2112
2165
  viewabilityConfigCallbackPairs,
2166
+ snapToIndices,
2113
2167
  onViewableItemsChanged,
2114
2168
  onStartReached,
2115
2169
  onEndReached,
@@ -2177,7 +2231,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2177
2231
  props: {},
2178
2232
  refScroller: void 0,
2179
2233
  loadStartTime: Date.now(),
2180
- initialScroll
2234
+ initialScroll,
2235
+ lastLayout: void 0
2181
2236
  };
2182
2237
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
2183
2238
  set$(ctx, "extraData", extraData);
@@ -2210,7 +2265,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2210
2265
  viewabilityConfigCallbackPairs: void 0,
2211
2266
  numColumns: numColumnsProp,
2212
2267
  initialContainerPoolRatio,
2213
- stylePaddingTop: stylePaddingTopState
2268
+ stylePaddingTop: stylePaddingTopState,
2269
+ snapToIndices
2214
2270
  };
2215
2271
  state.refScroller = refScroller;
2216
2272
  const checkResetContainers = (isFirst2) => {
@@ -2219,7 +2275,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2219
2275
  state2.props.data = dataProp;
2220
2276
  if (!isFirst2) {
2221
2277
  calculateItemsInView(ctx, state2, { dataChanged: true, doMVCP: true });
2222
- const didMaintainScrollAtEnd = doMaintainScrollAtEnd(ctx, state2, false);
2278
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2279
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state2, false);
2223
2280
  if (!didMaintainScrollAtEnd && dataProp.length > state2.props.data.length) {
2224
2281
  state2.isEndReached = false;
2225
2282
  }
@@ -2273,9 +2330,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2273
2330
  }
2274
2331
  }
2275
2332
  React3.useLayoutEffect(() => {
2276
- var _a2, _b;
2277
2333
  if (IsNewArchitecture) {
2278
- const measured = (_b = (_a2 = refScroller.current) == null ? void 0 : _a2.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a2);
2334
+ let measured;
2335
+ refScroller.current.measure((x, y, width, height) => {
2336
+ measured = { x, y, width, height };
2337
+ });
2279
2338
  if (measured) {
2280
2339
  const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
2281
2340
  if (size) {
@@ -2302,6 +2361,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2302
2361
  }
2303
2362
  }
2304
2363
  }, []);
2364
+ React3.useLayoutEffect(() => {
2365
+ if (snapToIndices) {
2366
+ updateSnapToOffsets(ctx, state);
2367
+ }
2368
+ }, [snapToIndices]);
2305
2369
  React3.useLayoutEffect(() => {
2306
2370
  const didAllocateContainers = doInitialAllocateContainersCallback();
2307
2371
  if (!didAllocateContainers) {
@@ -2376,6 +2440,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2376
2440
  endBuffered: state2.endBuffered,
2377
2441
  isAtEnd: state2.isAtEnd,
2378
2442
  isAtStart: state2.isAtStart,
2443
+ positions: state2.positions,
2379
2444
  scroll: state2.scroll,
2380
2445
  scrollLength: state2.scrollLength,
2381
2446
  start: state2.startNoBuffer,
@@ -2479,7 +2544,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2479
2544
  style,
2480
2545
  contentContainerStyle,
2481
2546
  scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
2482
- onLayoutHeader
2547
+ onLayoutHeader,
2548
+ snapToIndices
2483
2549
  }
2484
2550
  ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3__namespace.createElement(DebugView, { state: refState.current }));
2485
2551
  });
package/index.mjs CHANGED
@@ -552,6 +552,13 @@ function ScrollAdjust() {
552
552
  }
553
553
  );
554
554
  }
555
+
556
+ // src/SnapWrapper.tsx
557
+ function SnapWrapper({ ScrollComponent, ...props }) {
558
+ const [snapToOffsets] = useArr$(["snapToOffsets"]);
559
+ console.log("snapToOffsets", snapToOffsets);
560
+ return /* @__PURE__ */ React.createElement(ScrollComponent, { ...props, snapToOffsets });
561
+ }
555
562
  function useSyncLayout({
556
563
  onChange
557
564
  }) {
@@ -626,6 +633,7 @@ var ListComponent = typedMemo(function ListComponent2({
626
633
  renderScrollComponent,
627
634
  scrollAdjustHandler,
628
635
  onLayoutHeader,
636
+ snapToIndices,
629
637
  ...rest
630
638
  }) {
631
639
  const ctx = useStateContext();
@@ -643,10 +651,12 @@ var ListComponent = typedMemo(function ListComponent2({
643
651
  }, 0);
644
652
  }
645
653
  }, [canRender]);
654
+ const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
646
655
  return /* @__PURE__ */ React3.createElement(
647
- ScrollComponent,
656
+ SnapOrScroll,
648
657
  {
649
658
  ...rest,
659
+ ScrollComponent: snapToIndices ? ScrollComponent : void 0,
650
660
  style,
651
661
  maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
652
662
  contentContainerStyle: [
@@ -911,26 +921,27 @@ function requestAdjust(ctx, state, positionDiff) {
911
921
  };
912
922
  state.scroll += positionDiff;
913
923
  state.scrollForNextCalculateItemsInView = void 0;
914
- if (peek$(ctx, "containersDidLayout")) {
924
+ const didLayout = peek$(ctx, "containersDidLayout");
925
+ if (didLayout) {
915
926
  doit();
927
+ const threshold = state.scroll - positionDiff / 2;
928
+ if (!state.ignoreScrollFromMVCP) {
929
+ state.ignoreScrollFromMVCP = {};
930
+ }
931
+ if (positionDiff > 0) {
932
+ state.ignoreScrollFromMVCP.lt = threshold;
933
+ } else {
934
+ state.ignoreScrollFromMVCP.gt = threshold;
935
+ }
936
+ if (state.ignoreScrollFromMVCPTimeout) {
937
+ clearTimeout(state.ignoreScrollFromMVCPTimeout);
938
+ }
939
+ state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
940
+ state.ignoreScrollFromMVCP = void 0;
941
+ }, 100);
916
942
  } else {
917
943
  requestAnimationFrame(doit);
918
944
  }
919
- const threshold = state.scroll - positionDiff / 2;
920
- if (!state.ignoreScrollFromMVCP) {
921
- state.ignoreScrollFromMVCP = {};
922
- }
923
- if (positionDiff > 0) {
924
- state.ignoreScrollFromMVCP.lt = threshold;
925
- } else {
926
- state.ignoreScrollFromMVCP.gt = threshold;
927
- }
928
- if (state.ignoreScrollFromMVCPTimeout) {
929
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
930
- }
931
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
932
- state.ignoreScrollFromMVCP = void 0;
933
- }, 100);
934
945
  }
935
946
  }
936
947
 
@@ -1098,6 +1109,21 @@ function setDidLayout(ctx, state) {
1098
1109
  }
1099
1110
  }
1100
1111
 
1112
+ // src/updateSnapToOffsets.ts
1113
+ function updateSnapToOffsets(ctx, state) {
1114
+ const {
1115
+ positions,
1116
+ props: { snapToIndices }
1117
+ } = state;
1118
+ const snapToOffsets = Array(snapToIndices.length);
1119
+ for (let i = 0; i < snapToIndices.length; i++) {
1120
+ const idx = snapToIndices[i];
1121
+ const key = getId(state, idx);
1122
+ snapToOffsets[i] = positions.get(key);
1123
+ }
1124
+ set$(ctx, "snapToOffsets", snapToOffsets);
1125
+ }
1126
+
1101
1127
  // src/setPaddingTop.ts
1102
1128
  function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1103
1129
  if (stylePaddingTop !== void 0) {
@@ -1168,7 +1194,16 @@ function addTotalSize(ctx, state, key, add) {
1168
1194
  // src/updateAllPositions.ts
1169
1195
  function updateAllPositions(ctx, state, dataChanged) {
1170
1196
  var _a, _b, _c, _d, _e;
1171
- const { averageSizes, columns, indexByKey, positions, firstFullyOnScreenIndex, idCache, sizesKnown } = state;
1197
+ const {
1198
+ averageSizes,
1199
+ columns,
1200
+ indexByKey,
1201
+ positions,
1202
+ firstFullyOnScreenIndex,
1203
+ idCache,
1204
+ sizesKnown,
1205
+ props: { snapToIndices }
1206
+ } = state;
1172
1207
  const data = state.props.data;
1173
1208
  const numColumns = peek$(ctx, "numColumns");
1174
1209
  const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
@@ -1248,6 +1283,9 @@ function updateAllPositions(ctx, state, dataChanged) {
1248
1283
  }
1249
1284
  }
1250
1285
  updateTotalSize(ctx, state);
1286
+ if (snapToIndices) {
1287
+ updateSnapToOffsets(ctx, state);
1288
+ }
1251
1289
  }
1252
1290
 
1253
1291
  // src/viewability.ts
@@ -1824,9 +1862,12 @@ function getRenderedItem(ctx, state, key) {
1824
1862
  }
1825
1863
 
1826
1864
  // src/handleLayout.ts
1827
- function handleLayout(ctx, state, size, setCanRender) {
1828
- const scrollLength = size[state.props.horizontal ? "width" : "height"];
1829
- const otherAxisSize = size[state.props.horizontal ? "height" : "width"];
1865
+ function handleLayout(ctx, state, layout, setCanRender) {
1866
+ const { maintainScrollAtEnd } = state.props;
1867
+ const scrollLength = layout[state.props.horizontal ? "width" : "height"];
1868
+ const otherAxisSize = layout[state.props.horizontal ? "height" : "width"];
1869
+ const needsCalculate = !state.lastLayout || scrollLength > state.scrollLength || state.lastLayout.x !== layout.x || state.lastLayout.y !== layout.y;
1870
+ state.lastLayout = layout;
1830
1871
  const didChange = scrollLength !== state.scrollLength;
1831
1872
  const prevOtherAxisSize = state.otherAxisSize;
1832
1873
  state.scrollLength = scrollLength;
@@ -1834,13 +1875,15 @@ function handleLayout(ctx, state, size, setCanRender) {
1834
1875
  state.lastBatchingAction = Date.now();
1835
1876
  state.scrollForNextCalculateItemsInView = void 0;
1836
1877
  doInitialAllocateContainers(ctx, state);
1837
- if (didChange) {
1878
+ if (needsCalculate) {
1838
1879
  calculateItemsInView(ctx, state, { doMVCP: true });
1839
1880
  }
1840
1881
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
1841
- set$(ctx, "scrollSize", { width: size.width, height: size.height });
1882
+ set$(ctx, "scrollSize", { width: layout.width, height: layout.height });
1883
+ }
1884
+ if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
1885
+ doMaintainScrollAtEnd(ctx, state, false);
1842
1886
  }
1843
- doMaintainScrollAtEnd(ctx, state, false);
1844
1887
  updateAlignItemsPaddingTop(ctx, state);
1845
1888
  checkAtBottom(ctx, state);
1846
1889
  checkAtTop(state);
@@ -1853,7 +1896,6 @@ function handleLayout(ctx, state, size, setCanRender) {
1853
1896
  `List ${state.props.horizontal ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
1854
1897
  );
1855
1898
  }
1856
- calculateItemsInView(ctx, state, { doMVCP: true });
1857
1899
  setCanRender(true);
1858
1900
  }
1859
1901
 
@@ -1899,7 +1941,14 @@ function updateScroll(ctx, state, newScroll) {
1899
1941
  function updateItemSizes(ctx, state, itemUpdates) {
1900
1942
  var _a;
1901
1943
  const {
1902
- props: { horizontal, maintainVisibleContentPosition, suggestEstimatedItemSize, onItemSizeChanged, data }
1944
+ props: {
1945
+ horizontal,
1946
+ maintainVisibleContentPosition,
1947
+ suggestEstimatedItemSize,
1948
+ onItemSizeChanged,
1949
+ data,
1950
+ maintainScrollAtEnd
1951
+ }
1903
1952
  } = state;
1904
1953
  if (!data) return;
1905
1954
  let needsRecalculate = false;
@@ -1969,12 +2018,13 @@ function updateItemSizes(ctx, state, itemUpdates) {
1969
2018
  calculateItemsInView(ctx, state, { doMVCP: true });
1970
2019
  }
1971
2020
  if (shouldMaintainScrollAtEnd) {
1972
- doMaintainScrollAtEnd(ctx, state, false);
2021
+ if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2022
+ doMaintainScrollAtEnd(ctx, state, false);
2023
+ }
1973
2024
  }
1974
2025
  }
1975
2026
  }
1976
2027
  function updateItemSize(ctx, state, itemKey, sizeObj) {
1977
- var _a, _b;
1978
2028
  if (IsNewArchitecture) {
1979
2029
  const { sizesKnown } = state;
1980
2030
  const numContainers = ctx.values.get("numContainers");
@@ -1985,8 +2035,11 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
1985
2035
  changes.push({ itemKey, sizeObj });
1986
2036
  } else if (!sizesKnown.has(containerItemKey) && containerItemKey !== void 0) {
1987
2037
  const containerRef = ctx.viewRefs.get(i);
1988
- if (containerRef) {
1989
- const measured = (_b = (_a = containerRef.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
2038
+ if (containerRef == null ? void 0 : containerRef.current) {
2039
+ let measured;
2040
+ containerRef.current.measure((x, y, width, height) => {
2041
+ measured = { x, y, width, height };
2042
+ });
1990
2043
  if (measured) {
1991
2044
  changes.push({ itemKey: containerItemKey, sizeObj: measured });
1992
2045
  }
@@ -2089,6 +2142,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2089
2142
  initialContainerPoolRatio = 2,
2090
2143
  viewabilityConfig,
2091
2144
  viewabilityConfigCallbackPairs,
2145
+ snapToIndices,
2092
2146
  onViewableItemsChanged,
2093
2147
  onStartReached,
2094
2148
  onEndReached,
@@ -2156,7 +2210,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2156
2210
  props: {},
2157
2211
  refScroller: void 0,
2158
2212
  loadStartTime: Date.now(),
2159
- initialScroll
2213
+ initialScroll,
2214
+ lastLayout: void 0
2160
2215
  };
2161
2216
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
2162
2217
  set$(ctx, "extraData", extraData);
@@ -2189,7 +2244,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2189
2244
  viewabilityConfigCallbackPairs: void 0,
2190
2245
  numColumns: numColumnsProp,
2191
2246
  initialContainerPoolRatio,
2192
- stylePaddingTop: stylePaddingTopState
2247
+ stylePaddingTop: stylePaddingTopState,
2248
+ snapToIndices
2193
2249
  };
2194
2250
  state.refScroller = refScroller;
2195
2251
  const checkResetContainers = (isFirst2) => {
@@ -2198,7 +2254,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2198
2254
  state2.props.data = dataProp;
2199
2255
  if (!isFirst2) {
2200
2256
  calculateItemsInView(ctx, state2, { dataChanged: true, doMVCP: true });
2201
- const didMaintainScrollAtEnd = doMaintainScrollAtEnd(ctx, state2, false);
2257
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2258
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state2, false);
2202
2259
  if (!didMaintainScrollAtEnd && dataProp.length > state2.props.data.length) {
2203
2260
  state2.isEndReached = false;
2204
2261
  }
@@ -2252,9 +2309,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2252
2309
  }
2253
2310
  }
2254
2311
  useLayoutEffect(() => {
2255
- var _a2, _b;
2256
2312
  if (IsNewArchitecture) {
2257
- const measured = (_b = (_a2 = refScroller.current) == null ? void 0 : _a2.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a2);
2313
+ let measured;
2314
+ refScroller.current.measure((x, y, width, height) => {
2315
+ measured = { x, y, width, height };
2316
+ });
2258
2317
  if (measured) {
2259
2318
  const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
2260
2319
  if (size) {
@@ -2281,6 +2340,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2281
2340
  }
2282
2341
  }
2283
2342
  }, []);
2343
+ useLayoutEffect(() => {
2344
+ if (snapToIndices) {
2345
+ updateSnapToOffsets(ctx, state);
2346
+ }
2347
+ }, [snapToIndices]);
2284
2348
  useLayoutEffect(() => {
2285
2349
  const didAllocateContainers = doInitialAllocateContainersCallback();
2286
2350
  if (!didAllocateContainers) {
@@ -2355,6 +2419,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2355
2419
  endBuffered: state2.endBuffered,
2356
2420
  isAtEnd: state2.isAtEnd,
2357
2421
  isAtStart: state2.isAtStart,
2422
+ positions: state2.positions,
2358
2423
  scroll: state2.scroll,
2359
2424
  scrollLength: state2.scrollLength,
2360
2425
  start: state2.startNoBuffer,
@@ -2458,7 +2523,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2458
2523
  style,
2459
2524
  contentContainerStyle,
2460
2525
  scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
2461
- onLayoutHeader
2526
+ onLayoutHeader,
2527
+ snapToIndices
2462
2528
  }
2463
2529
  ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3.createElement(DebugView, { state: refState.current }));
2464
2530
  });
@@ -32,7 +32,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
32
32
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
33
33
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
34
34
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
35
- maintainScrollAtEnd?: boolean;
35
+ maintainScrollAtEnd?: boolean | _legendapp_list.MaintainScrollAtEndOptions;
36
36
  maintainScrollAtEndThreshold?: number;
37
37
  maintainVisibleContentPosition?: boolean;
38
38
  numColumns?: number;
@@ -66,6 +66,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
66
66
  onLoad?: (info: {
67
67
  elapsedTimeInMs: number;
68
68
  }) => void;
69
+ snapToIndices?: number[];
69
70
  } & React.RefAttributes<LegendListRef>) => React.ReactNode) | react_native.Animated.AnimatedComponent<(<T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
70
71
  alignItemsAtEnd?: boolean;
71
72
  columnWrapperStyle?: _legendapp_list.ColumnWrapperStyle;
@@ -94,7 +95,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
94
95
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
95
96
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
96
97
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
97
- maintainScrollAtEnd?: boolean;
98
+ maintainScrollAtEnd?: boolean | _legendapp_list.MaintainScrollAtEndOptions;
98
99
  maintainScrollAtEndThreshold?: number;
99
100
  maintainVisibleContentPosition?: boolean;
100
101
  numColumns?: number;
@@ -128,6 +129,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
128
129
  onLoad?: (info: {
129
130
  elapsedTimeInMs: number;
130
131
  }) => void;
132
+ snapToIndices?: number[];
131
133
  } & React.RefAttributes<LegendListRef>) => React.ReactNode)> | (<ItemT_1>(props: _legendapp_list_reanimated.AnimatedLegendListProps<ItemT_1> & {
132
134
  ref?: React.Ref<LegendListRef>;
133
135
  }) => React.ReactElement | null) = <T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
@@ -158,7 +160,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
158
160
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
159
161
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
160
162
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
161
- maintainScrollAtEnd?: boolean;
163
+ maintainScrollAtEnd?: boolean | _legendapp_list.MaintainScrollAtEndOptions;
162
164
  maintainScrollAtEndThreshold?: number;
163
165
  maintainVisibleContentPosition?: boolean;
164
166
  numColumns?: number;
@@ -192,6 +194,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
192
194
  onLoad?: (info: {
193
195
  elapsedTimeInMs: number;
194
196
  }) => void;
197
+ snapToIndices?: number[];
195
198
  } & React.RefAttributes<LegendListRef>) => React.ReactNode>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
196
199
  alignItemsAtEnd?: boolean;
197
200
  columnWrapperStyle?: _legendapp_list.ColumnWrapperStyle;
@@ -220,7 +223,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
220
223
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
221
224
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
222
225
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
223
- maintainScrollAtEnd?: boolean;
226
+ maintainScrollAtEnd?: boolean | _legendapp_list.MaintainScrollAtEndOptions;
224
227
  maintainScrollAtEndThreshold?: number;
225
228
  maintainVisibleContentPosition?: boolean;
226
229
  numColumns?: number;
@@ -254,6 +257,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
254
257
  onLoad?: (info: {
255
258
  elapsedTimeInMs: number;
256
259
  }) => void;
260
+ snapToIndices?: number[];
257
261
  } & {
258
262
  LegendList?: ListT;
259
263
  } & React.RefAttributes<LegendListRef>) => React.ReactNode;
@@ -32,7 +32,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
32
32
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
33
33
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
34
34
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
35
- maintainScrollAtEnd?: boolean;
35
+ maintainScrollAtEnd?: boolean | _legendapp_list.MaintainScrollAtEndOptions;
36
36
  maintainScrollAtEndThreshold?: number;
37
37
  maintainVisibleContentPosition?: boolean;
38
38
  numColumns?: number;
@@ -66,6 +66,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
66
66
  onLoad?: (info: {
67
67
  elapsedTimeInMs: number;
68
68
  }) => void;
69
+ snapToIndices?: number[];
69
70
  } & React.RefAttributes<LegendListRef>) => React.ReactNode) | react_native.Animated.AnimatedComponent<(<T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
70
71
  alignItemsAtEnd?: boolean;
71
72
  columnWrapperStyle?: _legendapp_list.ColumnWrapperStyle;
@@ -94,7 +95,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
94
95
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
95
96
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
96
97
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
97
- maintainScrollAtEnd?: boolean;
98
+ maintainScrollAtEnd?: boolean | _legendapp_list.MaintainScrollAtEndOptions;
98
99
  maintainScrollAtEndThreshold?: number;
99
100
  maintainVisibleContentPosition?: boolean;
100
101
  numColumns?: number;
@@ -128,6 +129,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
128
129
  onLoad?: (info: {
129
130
  elapsedTimeInMs: number;
130
131
  }) => void;
132
+ snapToIndices?: number[];
131
133
  } & React.RefAttributes<LegendListRef>) => React.ReactNode)> | (<ItemT_1>(props: _legendapp_list_reanimated.AnimatedLegendListProps<ItemT_1> & {
132
134
  ref?: React.Ref<LegendListRef>;
133
135
  }) => React.ReactElement | null) = <T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
@@ -158,7 +160,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
158
160
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
159
161
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
160
162
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
161
- maintainScrollAtEnd?: boolean;
163
+ maintainScrollAtEnd?: boolean | _legendapp_list.MaintainScrollAtEndOptions;
162
164
  maintainScrollAtEndThreshold?: number;
163
165
  maintainVisibleContentPosition?: boolean;
164
166
  numColumns?: number;
@@ -192,6 +194,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
192
194
  onLoad?: (info: {
193
195
  elapsedTimeInMs: number;
194
196
  }) => void;
197
+ snapToIndices?: number[];
195
198
  } & React.RefAttributes<LegendListRef>) => React.ReactNode>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews" | "children"> & {
196
199
  alignItemsAtEnd?: boolean;
197
200
  columnWrapperStyle?: _legendapp_list.ColumnWrapperStyle;
@@ -220,7 +223,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
220
223
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
221
224
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
222
225
  ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
223
- maintainScrollAtEnd?: boolean;
226
+ maintainScrollAtEnd?: boolean | _legendapp_list.MaintainScrollAtEndOptions;
224
227
  maintainScrollAtEndThreshold?: number;
225
228
  maintainVisibleContentPosition?: boolean;
226
229
  numColumns?: number;
@@ -254,6 +257,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
254
257
  onLoad?: (info: {
255
258
  elapsedTimeInMs: number;
256
259
  }) => void;
260
+ snapToIndices?: number[];
257
261
  } & {
258
262
  LegendList?: ListT;
259
263
  } & React.RefAttributes<LegendListRef>) => React.ReactNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "2.0.0-next.1",
3
+ "version": "2.0.0-next.3",
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,