@legendapp/list 1.0.0-beta.9 → 1.0.1

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
@@ -0,0 +1,5 @@
1
+ # 1.0.0
2
+
3
+ Initial release! Major changes if you're coming from a beta version:
4
+
5
+ - Item hooks like `useRecyclingState` are no longer render props, but can be imported from `@legendapp/list`
package/README.md CHANGED
@@ -1,76 +1,131 @@
1
1
  # Legend List
2
2
 
3
- Legend List aims to be a drop-in replacement for FlatList with much better performance and supporting dynamically sized items.
3
+ **Legend List** is a high-performance list component for **React Native**, written purely in Typescript with no native dependencies. It is a drop-in replacement for `FlatList` and `FlashList` with better performance, especially when handling dynamically sized items.
4
4
 
5
- ## Caution: Experimental
5
+ <video src="https://github.com/user-attachments/assets/8641e305-ab06-4fb3-a96a-fd220df84985"></video>
6
6
 
7
- This is an early release to test and gather feedback. It's not used in production yet and needs more work to reach parity with FlatList features.
7
+ ---
8
8
 
9
- ## Features
9
+ ## 🤔 Why Legend List?
10
10
 
11
- In addition to normal FlatList features:
11
+ * **Performance:** Designed from the ground up and heavily optimized for performance, it is faster than FlatList and other list libraries in most scenarios.
12
+ * **Dynamic Item Sizes:** Natively supports items with varying heights without performance hits.
13
+ * **Drop-in Replacement:** API compatibility with `FlatList` and `FlashList` for easier migration.
14
+ * **100% JS:** No native module linking required, ensuring easy integration and compatibility across platforms.
15
+ * **Lightweight:** Our goal is to keep LegendList as small of a dependency as possible. For more advanced use cases, we plan on supporting optional plugins. This ensures that we keep the package size as small as possible.
16
+ * **Bidirectional infinite lists:** Supports infinite scrolling in both directions with no flashes or scroll jumping
17
+ * **Chat UIs without inverted:** Chat UIs can align their content to the bottom and maintain scroll at end, so that the list doesn't need to be inverted, which causes weird behavior (in animations, etc...)
12
18
 
13
- - Dynamic layouts supported. Just use the `estimatedItemSize` prop to give a close estimate so that layouts aren't too far off, and positions will adjust while rendering.
14
- - `maintainScrollAtEnd`: If true and scroll is within `maintainScrollAtEndThreshold * screen height` then changing items or heights will scroll to the bottom. This can be useful for chat interfaces.
15
- - `recycleItems` prop enables toggling recycling of list items. If enabled it will reuse item components for improved performance, but it will reuse any local state in items. So if you have local state in items you likely want this disabled.
19
+ For more information, listen to the Legend List episode of the [React Native Radio Podcast](https://infinite.red/react-native-radio/rnr-325-legend-list-with-jay-meistrich) and the [livestream with Expo](https://www.youtube.com/watch?v=XpZMveUCke8).
16
20
 
17
- ## Documentation
21
+ ---
22
+ ## ✨ Additional Features
18
23
 
19
- See the [documentation site](https://www.legendapp.com/open-source/list) for the full documentation.
24
+ Beyond standard `FlatList` capabilities:
20
25
 
21
- ## Usage
26
+ * `recycleItems`: (boolean) Toggles item component recycling.
27
+ * `true`: Reuses item components for optimal performance. Be cautious if your item components contain local state, as it might be reused unexpectedly.
28
+ * `false` (default): Creates new item components every time. Less performant but safer if items have complex internal state.
29
+ * `maintainScrollAtEnd`: (boolean) If `true` and the user is scrolled near the bottom (within `maintainScrollAtEndThreshold * screen height`), the list automatically scrolls to the end when items are added or heights change. Useful for chat interfaces.
30
+ * `alignItemsAtEnd`: (boolean) Useful for chat UIs, content smaller than the View will be aligned to the bottom of the list.
22
31
 
23
- ## Install
32
+ ---
24
33
 
25
- `bun add @legendapp/list` or `npm install @legendapp/list` or `yarn add @legendapp/list`
34
+ ## 📚 Documentation
26
35
 
27
- ### Props
36
+ For comprehensive documentation, guides, and the full API reference, please visit:
28
37
 
29
- We suggest using all of the required props and additionally `keyExtractor` to improve performance when adding/removing items.
38
+ ➡️ **[Legend List Documentation Site](https://www.legendapp.com/open-source/list)**
30
39
 
31
- #### Required
40
+ ---
32
41
 
33
- ```ts
34
- interface PropsRequired {
35
- data: ArrayLike<any> & T[];
36
- renderItem: (props: LegendListRenderItemInfo<T>) => ReactNode;
37
- estimatedItemSize: number;
38
- }
42
+ ## 💻 Usage
43
+
44
+ ### Installation
45
+
46
+ ```bash
47
+ # Using Bun
48
+ bun add @legendapp/list
49
+
50
+ # Using npm
51
+ npm install @legendapp/list
52
+
53
+ # Using Yarn
54
+ yarn add @legendapp/list
39
55
  ```
40
56
 
41
- #### Optional
42
-
43
- ```ts
44
- interface PropsOptional {
45
- initialScrollOffset?: number;
46
- initialScrollIndex?: number;
47
- drawDistance?: number;
48
- recycleItems?: boolean;
49
- onEndReachedThreshold?: number | null | undefined;
50
- maintainScrollAtEnd?: boolean;
51
- maintainScrollAtEndThreshold?: number;
52
- onEndReached?: ((info: { distanceFromEnd: number }) => void) | null | undefined;
53
- keyExtractor?: (item: T, index: number) => string;
57
+ ### Example
58
+ ```tsx
59
+ import React, { useRef } from "react"
60
+ import { View, Image, Text, StyleSheet } from "react-native"
61
+ import { LegendList, LegendListRef, LegendListRenderItemProps } from "@legendapp/list"
62
+
63
+ // Define the type for your data items
64
+ interface UserData {
65
+ id: string;
66
+ name: string;
67
+ photoUri: string;
54
68
  }
69
+
70
+ const LegendListExample = () => {
71
+ // Optional: Ref for accessing list methods (e.g., scrollTo)
72
+ const listRef = useRef<LegendListRef | null>(null)
73
+
74
+ const data = []
75
+
76
+ const renderItem = ({ item }: LegendListRenderItemProps<UserData>) => {
77
+ return (
78
+ <View>
79
+ <Image source={{ uri: item.photoUri }} />
80
+ <Text>{item.name}</Text>
81
+ </View>
82
+ )
83
+ }
84
+
85
+ return (
86
+ <LegendList
87
+ // Required Props
88
+ data={data}
89
+ renderItem={renderItem}
90
+
91
+ // Recommended props (Improves performance)
92
+ keyExtractor={(item) => item.id}
93
+ recycleItems={true}
94
+
95
+ ref={listRef}
96
+ />
97
+ )
98
+ }
99
+
100
+ export default LegendListExample
101
+
55
102
  ```
56
103
 
57
- ## How to build
104
+ ---
105
+
106
+ ## How to Build
58
107
 
59
- `npm run build` will build the package to the `dist` folder.
108
+ 1. `bun i`
109
+ 2. `bun run build` will build the package to the `dist` folder.
60
110
 
61
- ## How to run example
111
+ ## Running the Example
62
112
 
63
113
  1. `cd example`
64
- 2. `npm i`
65
- 3. `npm run bootstrap-start`
114
+ 2. `bun i`
115
+ 3. `bun run ios`
66
116
 
67
117
  ## PRs gladly accepted!
68
118
 
69
- There's not a lot of code here so hopefully it's easy to contribute. If you want to add a missing feature or fix a bug please post an issue to see if development is already in progress so we can make sure to not duplicate work 😀.
119
+ There's not a ton of code so hopefully it's easy to contribute. If you want to add a missing feature or fix a bug please post an issue to see if development is already in progress so we can make sure to not duplicate work 😀.
70
120
 
71
- ## TODO list
121
+ ## Upcoming Roadmap
72
122
 
73
- See [Road to v1](https://github.com/LegendApp/legend-list/issues/28)
123
+ - [] Column spans
124
+ - [] overrideItemLayout
125
+ - [] Sticky headers
126
+ - [] Masonry layout
127
+ - [] getItemType
128
+ - [] React DOM implementation
74
129
 
75
130
  ## Community
76
131
 
package/animated.d.mts CHANGED
@@ -1,9 +1,59 @@
1
- import * as react from 'react';
1
+ import * as React$1 from 'react';
2
2
  import * as _legendapp_list from '@legendapp/list';
3
+ import * as react_native from 'react-native';
3
4
  import { Animated } from 'react-native';
4
5
 
5
- declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: _legendapp_list.LegendListProps<T> & {
6
- ref?: react.ForwardedRef<_legendapp_list.LegendListRef>;
7
- }) => react.ReactElement)>;
6
+ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices"> & {
7
+ alignItemsAtEnd?: boolean;
8
+ columnWrapperStyle?: _legendapp_list.ColumnWrapperStyle;
9
+ data: readonly T[];
10
+ drawDistance?: number;
11
+ estimatedItemSize?: number;
12
+ extraData?: any;
13
+ getEstimatedItemSize?: ((index: number, item: T) => number) | undefined;
14
+ initialContainerPoolRatio?: number | undefined;
15
+ initialScrollOffset?: number;
16
+ initialScrollIndex?: number;
17
+ ItemSeparatorComponent?: React$1.ComponentType<{
18
+ leadingItem: T;
19
+ }> | undefined;
20
+ keyExtractor?: ((item: T, index: number) => string) | undefined;
21
+ ListEmptyComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
22
+ ListFooterComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
23
+ ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
24
+ ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
25
+ ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
26
+ maintainScrollAtEnd?: boolean;
27
+ maintainScrollAtEndThreshold?: number;
28
+ maintainVisibleContentPosition?: boolean;
29
+ numColumns?: number;
30
+ onEndReached?: ((info: {
31
+ distanceFromEnd: number;
32
+ }) => void) | null | undefined;
33
+ onEndReachedThreshold?: number | null | undefined;
34
+ onItemSizeChanged?: ((info: {
35
+ size: number;
36
+ previous: number;
37
+ index: number;
38
+ itemKey: string;
39
+ itemData: T;
40
+ }) => void) | undefined;
41
+ onRefresh?: () => void;
42
+ onStartReached?: ((info: {
43
+ distanceFromStart: number;
44
+ }) => void) | null | undefined;
45
+ onStartReachedThreshold?: number | null | undefined;
46
+ onViewableItemsChanged?: _legendapp_list.OnViewableItemsChanged | undefined;
47
+ progressViewOffset?: number;
48
+ recycleItems?: boolean;
49
+ refScrollView?: React.Ref<react_native.ScrollView>;
50
+ refreshing?: boolean;
51
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React$1.ReactNode) | undefined;
52
+ renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
53
+ suggestEstimatedItemSize?: boolean;
54
+ viewabilityConfig?: _legendapp_list.ViewabilityConfig;
55
+ viewabilityConfigCallbackPairs?: _legendapp_list.ViewabilityConfigCallbackPairs | undefined;
56
+ waitForInitialLayout?: boolean;
57
+ } & React$1.RefAttributes<_legendapp_list.LegendListRef>) => React.ReactNode)>;
8
58
 
9
59
  export { AnimatedLegendList };
package/animated.d.ts CHANGED
@@ -1,9 +1,59 @@
1
- import * as react from 'react';
1
+ import * as React$1 from 'react';
2
2
  import * as _legendapp_list from '@legendapp/list';
3
+ import * as react_native from 'react-native';
3
4
  import { Animated } from 'react-native';
4
5
 
5
- declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: _legendapp_list.LegendListProps<T> & {
6
- ref?: react.ForwardedRef<_legendapp_list.LegendListRef>;
7
- }) => react.ReactElement)>;
6
+ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices"> & {
7
+ alignItemsAtEnd?: boolean;
8
+ columnWrapperStyle?: _legendapp_list.ColumnWrapperStyle;
9
+ data: readonly T[];
10
+ drawDistance?: number;
11
+ estimatedItemSize?: number;
12
+ extraData?: any;
13
+ getEstimatedItemSize?: ((index: number, item: T) => number) | undefined;
14
+ initialContainerPoolRatio?: number | undefined;
15
+ initialScrollOffset?: number;
16
+ initialScrollIndex?: number;
17
+ ItemSeparatorComponent?: React$1.ComponentType<{
18
+ leadingItem: T;
19
+ }> | undefined;
20
+ keyExtractor?: ((item: T, index: number) => string) | undefined;
21
+ ListEmptyComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
22
+ ListFooterComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
23
+ ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
24
+ ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
25
+ ListHeaderComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
26
+ maintainScrollAtEnd?: boolean;
27
+ maintainScrollAtEndThreshold?: number;
28
+ maintainVisibleContentPosition?: boolean;
29
+ numColumns?: number;
30
+ onEndReached?: ((info: {
31
+ distanceFromEnd: number;
32
+ }) => void) | null | undefined;
33
+ onEndReachedThreshold?: number | null | undefined;
34
+ onItemSizeChanged?: ((info: {
35
+ size: number;
36
+ previous: number;
37
+ index: number;
38
+ itemKey: string;
39
+ itemData: T;
40
+ }) => void) | undefined;
41
+ onRefresh?: () => void;
42
+ onStartReached?: ((info: {
43
+ distanceFromStart: number;
44
+ }) => void) | null | undefined;
45
+ onStartReachedThreshold?: number | null | undefined;
46
+ onViewableItemsChanged?: _legendapp_list.OnViewableItemsChanged | undefined;
47
+ progressViewOffset?: number;
48
+ recycleItems?: boolean;
49
+ refScrollView?: React.Ref<react_native.ScrollView>;
50
+ refreshing?: boolean;
51
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React$1.ReactNode) | undefined;
52
+ renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
53
+ suggestEstimatedItemSize?: boolean;
54
+ viewabilityConfig?: _legendapp_list.ViewabilityConfig;
55
+ viewabilityConfigCallbackPairs?: _legendapp_list.ViewabilityConfigCallbackPairs | undefined;
56
+ waitForInitialLayout?: boolean;
57
+ } & React$1.RefAttributes<_legendapp_list.LegendListRef>) => React.ReactNode)>;
8
58
 
9
59
  export { AnimatedLegendList };