@legendapp/list 2.0.0-next.2 → 2.0.0-next.21

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.
Files changed (264) hide show
  1. package/{dist/animated.d.mts → animated.d.mts} +10 -3
  2. package/{dist/animated.d.ts → animated.d.ts} +10 -3
  3. package/{dist/animated.js → animated.js} +2 -2
  4. package/{dist/animated.mjs → animated.mjs} +2 -2
  5. package/{dist/index.d.mts → index.d.mts} +86 -167
  6. package/{dist/index.d.ts → index.d.ts} +86 -167
  7. package/{dist/index.js → index.js} +1594 -1098
  8. package/{dist/index.mjs → index.mjs} +1596 -1100
  9. package/keyboard-controller.d.mts +148 -0
  10. package/keyboard-controller.d.ts +148 -0
  11. package/{dist/keyboard-controller.js → keyboard-controller.js} +4 -4
  12. package/{dist/keyboard-controller.mjs → keyboard-controller.mjs} +4 -4
  13. package/package.json +34 -88
  14. package/{dist/reanimated.d.mts → reanimated.d.mts} +2 -2
  15. package/{dist/reanimated.d.ts → reanimated.d.ts} +2 -2
  16. package/reanimated.js +60 -0
  17. package/reanimated.mjs +53 -0
  18. package/.claude/settings.local.json +0 -8
  19. package/.cursor/rules/changelog.mdc +0 -60
  20. package/.github/FUNDING.yml +0 -15
  21. package/.gitignore +0 -5
  22. package/.prettierrc.json +0 -5
  23. package/.vscode/settings.json +0 -14
  24. package/CLAUDE.md +0 -126
  25. package/biome.json +0 -46
  26. package/bun.lock +0 -1289
  27. package/bunfig.toml +0 -2
  28. package/dist/CHANGELOG.md +0 -119
  29. package/dist/LICENSE +0 -21
  30. package/dist/README.md +0 -139
  31. package/dist/keyboard-controller.d.mts +0 -261
  32. package/dist/keyboard-controller.d.ts +0 -261
  33. package/dist/package.json +0 -35
  34. package/dist/reanimated.js +0 -58
  35. package/dist/reanimated.mjs +0 -51
  36. package/example/README.md +0 -40
  37. package/example/api/data/genres.json +0 -23
  38. package/example/api/data/playlist/10402-10749.json +0 -1
  39. package/example/api/data/playlist/10402-10770.json +0 -1
  40. package/example/api/data/playlist/10402-37.json +0 -1
  41. package/example/api/data/playlist/10749-10752.json +0 -1
  42. package/example/api/data/playlist/10749-10770.json +0 -1
  43. package/example/api/data/playlist/10749-37.json +0 -1
  44. package/example/api/data/playlist/10749-878.json +0 -1
  45. package/example/api/data/playlist/10751-10402.json +0 -1
  46. package/example/api/data/playlist/10751-10752.json +0 -1
  47. package/example/api/data/playlist/10751-37.json +0 -1
  48. package/example/api/data/playlist/10751-53.json +0 -1
  49. package/example/api/data/playlist/10751-878.json +0 -1
  50. package/example/api/data/playlist/10751-9648.json +0 -1
  51. package/example/api/data/playlist/10752-37.json +0 -1
  52. package/example/api/data/playlist/12-10402.json +0 -1
  53. package/example/api/data/playlist/12-10749.json +0 -1
  54. package/example/api/data/playlist/12-18.json +0 -1
  55. package/example/api/data/playlist/12-27.json +0 -1
  56. package/example/api/data/playlist/12-35.json +0 -1
  57. package/example/api/data/playlist/14-36.json +0 -1
  58. package/example/api/data/playlist/14-878.json +0 -1
  59. package/example/api/data/playlist/16-10751.json +0 -1
  60. package/example/api/data/playlist/16-10770.json +0 -1
  61. package/example/api/data/playlist/16-35.json +0 -1
  62. package/example/api/data/playlist/16-36.json +0 -1
  63. package/example/api/data/playlist/16-53.json +0 -1
  64. package/example/api/data/playlist/18-10751.json +0 -1
  65. package/example/api/data/playlist/18-10752.json +0 -1
  66. package/example/api/data/playlist/18-37.json +0 -1
  67. package/example/api/data/playlist/18-53.json +0 -1
  68. package/example/api/data/playlist/18-878.json +0 -1
  69. package/example/api/data/playlist/27-10749.json +0 -1
  70. package/example/api/data/playlist/27-10770.json +0 -1
  71. package/example/api/data/playlist/28-10749.json +0 -1
  72. package/example/api/data/playlist/28-10751.json +0 -1
  73. package/example/api/data/playlist/28-10770.json +0 -1
  74. package/example/api/data/playlist/28-16.json +0 -1
  75. package/example/api/data/playlist/28-18.json +0 -1
  76. package/example/api/data/playlist/28-36.json +0 -1
  77. package/example/api/data/playlist/28-37.json +0 -1
  78. package/example/api/data/playlist/28-53.json +0 -1
  79. package/example/api/data/playlist/28-80.json +0 -1
  80. package/example/api/data/playlist/28-99.json +0 -1
  81. package/example/api/data/playlist/35-10749.json +0 -1
  82. package/example/api/data/playlist/35-10751.json +0 -1
  83. package/example/api/data/playlist/35-10752.json +0 -1
  84. package/example/api/data/playlist/35-27.json +0 -1
  85. package/example/api/data/playlist/35-36.json +0 -1
  86. package/example/api/data/playlist/35-53.json +0 -1
  87. package/example/api/data/playlist/35-80.json +0 -1
  88. package/example/api/data/playlist/36-37.json +0 -1
  89. package/example/api/data/playlist/36-878.json +0 -1
  90. package/example/api/data/playlist/36-9648.json +0 -1
  91. package/example/api/data/playlist/53-10752.json +0 -1
  92. package/example/api/data/playlist/80-10770.json +0 -1
  93. package/example/api/data/playlist/80-14.json +0 -1
  94. package/example/api/data/playlist/80-18.json +0 -1
  95. package/example/api/data/playlist/80-37.json +0 -1
  96. package/example/api/data/playlist/878-37.json +0 -1
  97. package/example/api/data/playlist/9648-10770.json +0 -1
  98. package/example/api/data/playlist/9648-37.json +0 -1
  99. package/example/api/data/playlist/9648-53.json +0 -1
  100. package/example/api/data/playlist/9648-878.json +0 -1
  101. package/example/api/data/playlist/99-10749.json +0 -1
  102. package/example/api/data/playlist/99-14.json +0 -1
  103. package/example/api/data/playlist/99-18.json +0 -1
  104. package/example/api/data/playlist/99-27.json +0 -1
  105. package/example/api/data/playlist/99-53.json +0 -1
  106. package/example/api/data/playlist/99-9648.json +0 -1
  107. package/example/api/data/playlist/index.ts +0 -73
  108. package/example/api/data/rows.json +0 -1
  109. package/example/api/index.ts +0 -36
  110. package/example/app/(tabs)/_layout.tsx +0 -60
  111. package/example/app/(tabs)/cards.tsx +0 -81
  112. package/example/app/(tabs)/index.tsx +0 -205
  113. package/example/app/(tabs)/moviesL.tsx +0 -7
  114. package/example/app/(tabs)/moviesLR.tsx +0 -7
  115. package/example/app/+not-found.tsx +0 -32
  116. package/example/app/_layout.tsx +0 -34
  117. package/example/app/accurate-scrollto/index.tsx +0 -125
  118. package/example/app/accurate-scrollto-2/index.tsx +0 -52
  119. package/example/app/accurate-scrollto-huge/index.tsx +0 -128
  120. package/example/app/add-to-end/index.tsx +0 -82
  121. package/example/app/ai-chat/index.tsx +0 -236
  122. package/example/app/bidirectional-infinite-list/index.tsx +0 -133
  123. package/example/app/cards-columns/index.tsx +0 -37
  124. package/example/app/cards-flashlist/index.tsx +0 -122
  125. package/example/app/cards-flatlist/index.tsx +0 -94
  126. package/example/app/cards-no-recycle/index.tsx +0 -110
  127. package/example/app/cards-renderItem.tsx +0 -354
  128. package/example/app/chat-example/index.tsx +0 -167
  129. package/example/app/chat-infinite/index.tsx +0 -239
  130. package/example/app/chat-keyboard/index.tsx +0 -248
  131. package/example/app/chat-resize-outer/index.tsx +0 -247
  132. package/example/app/columns/index.tsx +0 -78
  133. package/example/app/countries/index.tsx +0 -182
  134. package/example/app/countries-flashlist/index.tsx +0 -163
  135. package/example/app/countries-reorder/index.tsx +0 -187
  136. package/example/app/extra-data/index.tsx +0 -86
  137. package/example/app/filter-elements/filter-data-provider.tsx +0 -55
  138. package/example/app/filter-elements/index.tsx +0 -118
  139. package/example/app/initial-scroll-index/index.tsx +0 -106
  140. package/example/app/initial-scroll-index/renderFixedItem.tsx +0 -215
  141. package/example/app/initial-scroll-index-free-height/index.tsx +0 -70
  142. package/example/app/initial-scroll-index-keyed/index.tsx +0 -62
  143. package/example/app/lazy-list/index.tsx +0 -123
  144. package/example/app/movies-flashlist/index.tsx +0 -7
  145. package/example/app/mutable-cells/index.tsx +0 -104
  146. package/example/app/video-feed/index.tsx +0 -119
  147. package/example/app.config.js +0 -22
  148. package/example/app.json +0 -45
  149. package/example/assets/fonts/SpaceMono-Regular.ttf +0 -0
  150. package/example/assets/images/adaptive-icon.png +0 -0
  151. package/example/assets/images/favicon.png +0 -0
  152. package/example/assets/images/icon.png +0 -0
  153. package/example/assets/images/partial-react-logo.png +0 -0
  154. package/example/assets/images/react-logo.png +0 -0
  155. package/example/assets/images/react-logo@2x.png +0 -0
  156. package/example/assets/images/react-logo@3x.png +0 -0
  157. package/example/assets/images/splash-icon.png +0 -0
  158. package/example/autoscroll.sh +0 -101
  159. package/example/bun.lock +0 -2266
  160. package/example/bunfig.toml +0 -2
  161. package/example/components/Breathe.tsx +0 -54
  162. package/example/components/Circle.tsx +0 -69
  163. package/example/components/Collapsible.tsx +0 -44
  164. package/example/components/ExternalLink.tsx +0 -24
  165. package/example/components/HapticTab.tsx +0 -18
  166. package/example/components/HelloWave.tsx +0 -37
  167. package/example/components/Movies.tsx +0 -179
  168. package/example/components/ParallaxScrollView.tsx +0 -81
  169. package/example/components/ThemedText.tsx +0 -60
  170. package/example/components/ThemedView.tsx +0 -14
  171. package/example/components/__tests__/ThemedText-test.tsx +0 -10
  172. package/example/components/__tests__/__snapshots__/ThemedText-test.tsx.snap +0 -24
  173. package/example/components/ui/IconSymbol.ios.tsx +0 -32
  174. package/example/components/ui/IconSymbol.tsx +0 -43
  175. package/example/components/ui/TabBarBackground.ios.tsx +0 -22
  176. package/example/components/ui/TabBarBackground.tsx +0 -6
  177. package/example/constants/Colors.ts +0 -26
  178. package/example/constants/constants.ts +0 -5
  179. package/example/constants/useScrollTest.ts +0 -19
  180. package/example/hooks/useColorScheme.ts +0 -1
  181. package/example/hooks/useColorScheme.web.ts +0 -8
  182. package/example/hooks/useThemeColor.ts +0 -22
  183. package/example/ios/.xcode.env +0 -11
  184. package/example/ios/Podfile +0 -64
  185. package/example/ios/Podfile.lock +0 -2767
  186. package/example/ios/Podfile.properties.json +0 -5
  187. package/example/ios/listtest/AppDelegate.swift +0 -70
  188. package/example/ios/listtest/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png +0 -0
  189. package/example/ios/listtest/Images.xcassets/AppIcon.appiconset/Contents.json +0 -14
  190. package/example/ios/listtest/Images.xcassets/Contents.json +0 -6
  191. package/example/ios/listtest/Images.xcassets/SplashScreenBackground.colorset/Contents.json +0 -20
  192. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/Contents.json +0 -23
  193. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image.png +0 -0
  194. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image@2x.png +0 -0
  195. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image@3x.png +0 -0
  196. package/example/ios/listtest/Info.plist +0 -85
  197. package/example/ios/listtest/PrivacyInfo.xcprivacy +0 -48
  198. package/example/ios/listtest/SplashScreen.storyboard +0 -42
  199. package/example/ios/listtest/Supporting/Expo.plist +0 -12
  200. package/example/ios/listtest/listtest-Bridging-Header.h +0 -3
  201. package/example/ios/listtest/listtest.entitlements +0 -5
  202. package/example/ios/listtest.xcodeproj/project.pbxproj +0 -547
  203. package/example/ios/listtest.xcodeproj/xcshareddata/xcschemes/listtest.xcscheme +0 -88
  204. package/example/ios/listtest.xcworkspace/contents.xcworkspacedata +0 -10
  205. package/example/metro.config.js +0 -16
  206. package/example/package.json +0 -73
  207. package/example/scripts/reset-project.js +0 -84
  208. package/example/tsconfig.json +0 -26
  209. package/posttsup.ts +0 -24
  210. package/src/Container.tsx +0 -176
  211. package/src/Containers.tsx +0 -85
  212. package/src/ContextContainer.ts +0 -145
  213. package/src/DebugView.tsx +0 -83
  214. package/src/LazyLegendList.tsx +0 -41
  215. package/src/LeanView.tsx +0 -18
  216. package/src/LegendList.tsx +0 -558
  217. package/src/ListComponent.tsx +0 -191
  218. package/src/ScrollAdjust.tsx +0 -24
  219. package/src/ScrollAdjustHandler.ts +0 -26
  220. package/src/Separator.tsx +0 -14
  221. package/src/animated.tsx +0 -6
  222. package/src/calculateItemsInView.ts +0 -363
  223. package/src/calculateOffsetForIndex.ts +0 -23
  224. package/src/calculateOffsetWithOffsetPosition.ts +0 -26
  225. package/src/checkAllSizesKnown.ts +0 -17
  226. package/src/checkAtBottom.ts +0 -36
  227. package/src/checkAtTop.ts +0 -27
  228. package/src/checkThreshold.ts +0 -30
  229. package/src/constants.ts +0 -11
  230. package/src/createColumnWrapperStyle.ts +0 -16
  231. package/src/doInitialAllocateContainers.ts +0 -40
  232. package/src/doMaintainScrollAtEnd.ts +0 -34
  233. package/src/findAvailableContainers.ts +0 -98
  234. package/src/finishScrollTo.ts +0 -8
  235. package/src/getId.ts +0 -21
  236. package/src/getItemSize.ts +0 -52
  237. package/src/getRenderedItem.ts +0 -34
  238. package/src/getScrollVelocity.ts +0 -47
  239. package/src/handleLayout.ts +0 -70
  240. package/src/helpers.ts +0 -39
  241. package/src/index.ts +0 -11
  242. package/src/keyboard-controller.tsx +0 -63
  243. package/src/onScroll.ts +0 -66
  244. package/src/prepareMVCP.ts +0 -50
  245. package/src/reanimated.tsx +0 -63
  246. package/src/requestAdjust.ts +0 -41
  247. package/src/scrollTo.ts +0 -40
  248. package/src/scrollToIndex.ts +0 -34
  249. package/src/setDidLayout.ts +0 -25
  250. package/src/setPaddingTop.ts +0 -28
  251. package/src/state.tsx +0 -304
  252. package/src/types.ts +0 -610
  253. package/src/updateAlignItemsPaddingTop.ts +0 -18
  254. package/src/updateAllPositions.ts +0 -130
  255. package/src/updateItemSize.ts +0 -203
  256. package/src/updateTotalSize.ts +0 -44
  257. package/src/useAnimatedValue.ts +0 -6
  258. package/src/useCombinedRef.ts +0 -22
  259. package/src/useInit.ts +0 -17
  260. package/src/useSyncLayout.tsx +0 -68
  261. package/src/useValue$.ts +0 -53
  262. package/src/viewability.ts +0 -279
  263. package/tsconfig.json +0 -59
  264. package/tsup.config.ts +0 -21
@@ -1,110 +0,0 @@
1
- import { type Item, renderItem } from "@/app/cards-renderItem";
2
- import { DO_SCROLL_TEST, DRAW_DISTANCE, ESTIMATED_ITEM_LENGTH } from "@/constants/constants";
3
- import { useScrollTest } from "@/constants/useScrollTest";
4
- import { LegendList, type LegendListRef } from "@legendapp/list";
5
- import { useRef, useState } from "react";
6
- import { LogBox, Platform, StyleSheet, Text, View } from "react-native";
7
-
8
- LogBox.ignoreLogs(["Open debugger"]);
9
-
10
- interface CardsProps {
11
- numColumns?: number;
12
- }
13
-
14
- export default function Cards({ numColumns = 1 }: CardsProps) {
15
- const listRef = useRef<LegendListRef>(null);
16
-
17
- const [data, setData] = useState<Item[]>(
18
- () =>
19
- Array.from({ length: 1000 }, (_, i) => ({
20
- id: i.toString(),
21
- })) as any[],
22
- );
23
-
24
- if (DO_SCROLL_TEST) {
25
- useScrollTest((offset) => {
26
- listRef.current?.scrollToOffset({
27
- offset: offset,
28
- animated: true,
29
- });
30
- });
31
- }
32
-
33
- return (
34
- <View style={[StyleSheet.absoluteFill, styles.outerContainer]} key="legendlist">
35
- <LegendList
36
- ref={listRef}
37
- style={[StyleSheet.absoluteFill, styles.scrollContainer]}
38
- contentContainerStyle={styles.listContainer}
39
- data={data}
40
- renderItem={renderItem}
41
- keyExtractor={(item) => `id${item.id}`}
42
- estimatedItemSize={ESTIMATED_ITEM_LENGTH}
43
- drawDistance={DRAW_DISTANCE}
44
- recycleItems={false}
45
- numColumns={numColumns}
46
- // initialScrollIndex={50}
47
- // alignItemsAtEnd
48
- // maintainScrollAtEnd
49
- // onEndReached={({ distanceFromEnd }) => {
50
- // console.log("onEndReached", distanceFromEnd);
51
- // }}
52
- ListHeaderComponent={<View />}
53
- ListHeaderComponentStyle={styles.listHeader}
54
- ListFooterComponent={<View />}
55
- ListFooterComponentStyle={styles.listHeader}
56
- ListEmptyComponent={
57
- <View style={styles.listEmpty}>
58
- <Text style={{ color: "white" }}>Empty</Text>
59
- </View>
60
- }
61
- // viewabilityConfigCallbackPairs={[
62
- // {
63
- // viewabilityConfig: { id: "viewability", viewAreaCoveragePercentThreshold: 50 },
64
- // // onViewableItemsChanged: ({ viewableItems, changed }) => {
65
- // // console.log(
66
- // // 'onViewableItems',
67
- // // viewableItems.map((v) => v.key),
68
- // // );
69
- // // // console.log('onViewableChanged', changed);
70
- // // },
71
- // },
72
- // ]}
73
-
74
- // initialScrollOffset={20000}
75
- // initialScrollIndex={500}
76
- // inverted
77
- // horizontal
78
- />
79
- </View>
80
- );
81
- }
82
-
83
- const styles = StyleSheet.create({
84
- listHeader: {
85
- alignSelf: "center",
86
- height: 100,
87
- width: 100,
88
- backgroundColor: "#456AAA",
89
- borderRadius: 12,
90
- marginHorizontal: 8,
91
- marginVertical: 8,
92
- },
93
- listEmpty: {
94
- flex: 1,
95
- justifyContent: "center",
96
- alignItems: "center",
97
- backgroundColor: "#6789AB",
98
- paddingVertical: 16,
99
- },
100
- outerContainer: {
101
- backgroundColor: "#456",
102
- bottom: Platform.OS === "ios" ? 82 : 0,
103
- },
104
- scrollContainer: {},
105
- listContainer: {
106
- width: 400,
107
- maxWidth: "100%",
108
- marginHorizontal: "auto",
109
- },
110
- });
@@ -1,354 +0,0 @@
1
- import { MaterialIcons } from "@expo/vector-icons";
2
- import { LegendList, type LegendListRenderItemProps, useRecyclingState } from "@legendapp/list";
3
- import { memo, useRef, useState } from "react";
4
- import { Animated, Image, Platform, Pressable, StyleSheet, Text, UIManager, View } from "react-native";
5
- import { RectButton } from "react-native-gesture-handler";
6
- import Swipeable, { type SwipeableMethods } from "react-native-gesture-handler/ReanimatedSwipeable";
7
-
8
- export interface Item {
9
- id: string;
10
- }
11
- const demoNestedList = false;
12
-
13
- // Generate random metadata
14
- const randomAvatars = Array.from({ length: 20 }, (_, i) => `https://i.pravatar.cc/150?img=${i + 1}`);
15
-
16
- export const randomNames = [
17
- "Alex Thompson",
18
- "Jordan Lee",
19
- "Sam Parker",
20
- "Taylor Kim",
21
- "Morgan Chen",
22
- "Riley Zhang",
23
- "Casey Williams",
24
- "Quinn Anderson",
25
- "Blake Martinez",
26
- "Avery Rodriguez",
27
- "Drew Campbell",
28
- "Jamie Foster",
29
- "Skylar Patel",
30
- "Charlie Wright",
31
- "Sage Mitchell",
32
- "River Johnson",
33
- "Phoenix Garcia",
34
- "Jordan Taylor",
35
- "Reese Cooper",
36
- "Morgan Bailey",
37
- ];
38
-
39
- // Array of lorem ipsum sentences to randomly choose from
40
- export const loremSentences = [
41
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
42
- "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
43
- "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
44
- "Duis aute irure dolor in reprehenderit in voluptate velit esse.",
45
- "Excepteur sint occaecat cupidatat non proident, sunt in culpa.",
46
- "Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit.",
47
- "Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet.",
48
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
49
- "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
50
- "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
51
- "Duis aute irure dolor in reprehenderit in voluptate velit esse.",
52
- "Excepteur sint occaecat cupidatat non proident, sunt in culpa.",
53
- "Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit.",
54
- "Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet.",
55
- ];
56
-
57
- if (Platform.OS === "android") {
58
- if (UIManager.setLayoutAnimationEnabledExperimental) {
59
- UIManager.setLayoutAnimationEnabledExperimental(true);
60
- }
61
- }
62
-
63
- const renderRightActions = () => {
64
- return (
65
- <RectButton
66
- style={{
67
- width: 80,
68
- height: "100%",
69
- backgroundColor: "#4CAF50",
70
- justifyContent: "center",
71
- alignItems: "center",
72
- borderTopRightRadius: 12,
73
- borderBottomRightRadius: 12,
74
- shadowColor: "#000",
75
- shadowOffset: { width: 2, height: 0 },
76
- shadowOpacity: 0.1,
77
- shadowRadius: 4,
78
- }}
79
- onPress={() => {
80
- console.log("Marked as complete");
81
- }}
82
- >
83
- <MaterialIcons name="check-circle" size={24} color="white" />
84
- <Text
85
- style={{
86
- color: "white",
87
- fontSize: 12,
88
- marginTop: 4,
89
- fontWeight: "600",
90
- }}
91
- >
92
- Complete
93
- </Text>
94
- </RectButton>
95
- );
96
- };
97
-
98
- // Inline Separator makes containers rerender each data change
99
- const Separator = () => <View style={{ height: 10 }} />;
100
-
101
- export const ItemCard = memo(
102
- ({
103
- item,
104
- index,
105
- extraData,
106
- numSentences: numSentencesProp,
107
- }: LegendListRenderItemProps<Item> & { numSentences: number | ((index: number) => number) }) => {
108
- const refSwipeable = useRef<SwipeableMethods>();
109
-
110
- // A useState that resets when the item is recycled
111
- const [isExpanded, setIsExpanded] = extraData?.recycleState ? useRecyclingState(() => false) : useState(false);
112
-
113
- const swipeableState = useRef(false);
114
-
115
- // console.log(Math.round(performance.now()), "renderItem", index);
116
-
117
- // A callback when the item is recycled
118
- // useRecyclingEffect?.(({ item, prevItem, index, prevIndex }) => {
119
- // if (swipeableState.current) {
120
- // // this is expensive operation, run .close() only if the swipeable is open
121
- // refSwipeable?.current?.close();
122
- // }
123
- // });
124
-
125
- // A callback when the item viewability (from viewabilityConfig) changes
126
- // useViewability?.("viewability", ({ item, isViewable, index }) => {
127
- // // console.log('viewable', viewToken.index, viewToken.isViewable);
128
- // });
129
-
130
- // @ts-ignore
131
- // const opacity = useViewabilityAmount ? useAnimatedValue(1) : 1;
132
- // useViewabilityAmount?.(({ sizeVisible, size, percentOfScroller }) => {
133
- // // @ts-ignore
134
- // // opacity.setValue(Math.max(0, Math.min(1, sizeVisible / Math.min(400, size || 400)) ** 1.5));
135
- // // console.log('viewable', sizeVisible, size, percentOfScroller);
136
- // });
137
-
138
- // Math.abs needed for negative indices
139
- const indexForData = Math.abs(item.id.includes("new") ? 100 + +item.id.replace("new", "") : +item.id);
140
-
141
- // Generate 1-5 random sentences
142
- const numSentences = numSentencesProp
143
- ? typeof numSentencesProp === "function"
144
- ? numSentencesProp(indexForData)
145
- : numSentencesProp
146
- : ((indexForData * 7919) % 4) + 1; // Using prime number 7919 for better distribution
147
- // const indexForData =
148
- // item.id === "0" ? 0 : item.id === "1" ? 1 : item.id === "new0" ? 2 : 3;
149
- // const numSentences =
150
- // item.id === "0" ? 1 : item.id === "1" ? 2 : item.id === "new0" ? 4 : 8;
151
- const randomText = Array.from(
152
- { length: numSentences },
153
- (_, i) => loremSentences[i % loremSentences.length],
154
- ).join(" ");
155
-
156
- // Use randomIndex to deterministically select random data
157
- const avatarUrl = randomAvatars[indexForData % randomAvatars.length];
158
- const authorName = randomNames[indexForData % randomNames.length];
159
- const timestamp = `${Math.max(1, indexForData % 24)}h ago`;
160
-
161
- if (index === 1 && demoNestedList) {
162
- return (
163
- <Animated.View style={[styles.nestedListContainer]}>
164
- <LegendList
165
- showsHorizontalScrollIndicator={false}
166
- horizontal
167
- estimatedItemSize={400}
168
- keyExtractor={(item) => item.text}
169
- data={[
170
- {
171
- id: "1",
172
- text: "List Item 1",
173
- },
174
- {
175
- id: "2",
176
- text: "List Item 2",
177
- },
178
- {
179
- id: "3",
180
- text: "List Item 3",
181
- },
182
- ]}
183
- ItemSeparatorComponent={Separator}
184
- renderItem={({ item }) => (
185
- <View style={styles.nestedListItem}>
186
- <Text>{item.text}</Text>
187
- </View>
188
- )}
189
- />
190
- </Animated.View>
191
- );
192
- }
193
-
194
- return (
195
- <View style={{ ...styles.itemOuterContainer }}>
196
- <Swipeable
197
- renderRightActions={renderRightActions}
198
- overshootRight={true}
199
- containerStyle={styles.swipeableContainer}
200
- ref={refSwipeable as any}
201
- onSwipeableWillOpen={() => {
202
- swipeableState.current = true;
203
- }}
204
- onSwipeableWillClose={() => {
205
- swipeableState.current = false;
206
- }}
207
- >
208
- <Pressable
209
- onPress={(e) => {
210
- // LinearTransition.easing(Easing.ease);
211
-
212
- e.stopPropagation();
213
- setIsExpanded(!isExpanded);
214
- }}
215
- >
216
- <View
217
- style={[
218
- styles.itemContainer,
219
- {
220
- // padding: 16,
221
- backgroundColor: "#ffffff",
222
- borderRadius: 12,
223
- shadowColor: "#000",
224
- shadowOffset: { width: 0, height: 2 },
225
- shadowOpacity: 0.1,
226
- shadowRadius: 4,
227
- // marginVertical: 8,
228
- overflow: "hidden",
229
- },
230
- ]}
231
- >
232
- <View style={styles.headerContainer}>
233
- <Image source={{ uri: avatarUrl }} style={styles.avatar} />
234
- <View style={styles.headerText}>
235
- <Text style={styles.authorName}>
236
- {authorName} {item.id}
237
- </Text>
238
- <Text style={styles.timestamp}>{timestamp}</Text>
239
- </View>
240
- </View>
241
-
242
- <Text style={styles.itemTitle}>Item #{item.id}</Text>
243
- <Text
244
- style={styles.itemBody}
245
- // numberOfLines={isExpanded ? undefined : 10}
246
- >
247
- {randomText}
248
- {isExpanded ? randomText : null}
249
- </Text>
250
- <View style={styles.itemFooter}>
251
- <Text style={styles.footerText}>❤️ 42</Text>
252
- <Text style={styles.footerText}>💬 12</Text>
253
- <Text style={styles.footerText}>🔄 8</Text>
254
- </View>
255
- </View>
256
- {/* <Breathe /> */}
257
- </Pressable>
258
- </Swipeable>
259
- </View>
260
- );
261
- },
262
- );
263
-
264
- export const renderItem = (props: LegendListRenderItemProps<Item>) => <ItemCard {...props} />;
265
-
266
- const styles = StyleSheet.create({
267
- nestedListContainer: {
268
- paddingVertical: 8,
269
- paddingHorizontal: 8,
270
- height: 200,
271
- },
272
- nestedListItem: {
273
- backgroundColor: "white",
274
- height: 200,
275
- width: 200,
276
- justifyContent: "center",
277
- alignItems: "center",
278
- },
279
- itemOuterContainer: {
280
- paddingVertical: 8,
281
- paddingHorizontal: 8,
282
- //width: 380,
283
- //marginLeft: 6,
284
- },
285
- itemContainer: {
286
- padding: 16,
287
- // borderBottomWidth: 1,
288
- // borderBottomColor: "#ccc",
289
- },
290
- titleContainer: {
291
- flexDirection: "row",
292
- alignItems: "center",
293
- gap: 8,
294
- },
295
- stepContainer: {
296
- gap: 8,
297
- marginBottom: 8,
298
- },
299
- listContainer: {
300
- paddingHorizontal: 16,
301
- },
302
- itemTitle: {
303
- fontSize: 18,
304
- fontWeight: "bold",
305
- marginBottom: 8,
306
- color: "#1a1a1a",
307
- },
308
- itemBody: {
309
- fontSize: 14,
310
- color: "#666666",
311
- lineHeight: 20,
312
- // flex: 1,
313
- },
314
- itemFooter: {
315
- flexDirection: "row",
316
- justifyContent: "flex-start",
317
- gap: 16,
318
- marginTop: 12,
319
- paddingTop: 12,
320
- borderTopWidth: 1,
321
- borderTopColor: "#f0f0f0",
322
- },
323
- footerText: {
324
- fontSize: 14,
325
- color: "#888888",
326
- },
327
- headerContainer: {
328
- flexDirection: "row",
329
- alignItems: "center",
330
- marginBottom: 12,
331
- },
332
- avatar: {
333
- width: 40,
334
- height: 40,
335
- borderRadius: 20,
336
- marginRight: 12,
337
- },
338
- headerText: {
339
- flex: 1,
340
- },
341
- authorName: {
342
- fontSize: 16,
343
- fontWeight: "600",
344
- color: "#1a1a1a",
345
- },
346
- timestamp: {
347
- fontSize: 12,
348
- color: "#888888",
349
- marginTop: 2,
350
- },
351
- swipeableContainer: { backgroundColor: "#4CAF50", borderRadius: 12 },
352
- });
353
-
354
- export default renderItem;
@@ -1,167 +0,0 @@
1
- import { LegendList } from "@legendapp/list";
2
- import { useHeaderHeight } from "@react-navigation/elements";
3
- import { useState } from "react";
4
- import { Button, KeyboardAvoidingView, Platform, StyleSheet, Text, TextInput, View } from "react-native";
5
- import { SafeAreaView } from "react-native-safe-area-context";
6
-
7
- type Message = {
8
- id: string;
9
- text: string;
10
- sender: "user" | "bot";
11
- timeStamp: number;
12
- };
13
-
14
- let idCounter = 0;
15
- const MS_PER_SECOND = 1000;
16
-
17
- const defaultChatMessages: Message[] = [
18
- {
19
- id: String(idCounter++),
20
- text: "Hi, I have a question",
21
- sender: "user",
22
- timeStamp: Date.now() - MS_PER_SECOND * 5,
23
- },
24
- { id: String(idCounter++), text: "Hello", sender: "bot", timeStamp: Date.now() - MS_PER_SECOND * 4 },
25
- { id: String(idCounter++), text: "How can I help you?", sender: "bot", timeStamp: Date.now() - MS_PER_SECOND * 3 },
26
- ];
27
-
28
- const ChatExample = () => {
29
- const [messages, setMessages] = useState<Message[]>(defaultChatMessages);
30
- const [inputText, setInputText] = useState("");
31
- const headerHeight = Platform.OS === "ios" ? useHeaderHeight() : 80;
32
-
33
- const sendMessage = () => {
34
- const text = inputText || "Empty message";
35
- if (text.trim()) {
36
- setMessages((messages) => [
37
- ...messages,
38
- { id: String(idCounter++), text: text, sender: "user", timeStamp: Date.now() },
39
- ]);
40
- setInputText("");
41
- setTimeout(() => {
42
- setMessages((messages) => [
43
- ...messages,
44
- {
45
- id: String(idCounter++),
46
- text: `Answer: ${text.toUpperCase()}`,
47
- sender: "bot",
48
- timeStamp: Date.now(),
49
- },
50
- ]);
51
- }, 300);
52
- }
53
- };
54
-
55
- return (
56
- <SafeAreaView style={styles.container} edges={["bottom"]}>
57
- <KeyboardAvoidingView
58
- style={styles.container}
59
- behavior="padding"
60
- keyboardVerticalOffset={headerHeight}
61
- contentContainerStyle={{ flex: 1 }}
62
- >
63
- <LegendList
64
- data={messages}
65
- contentContainerStyle={styles.contentContainer}
66
- keyExtractor={(item) => item.id}
67
- estimatedItemSize={10} // A size that's way too small to check the behavior is correct
68
- initialScrollIndex={messages.length - 1}
69
- maintainVisibleContentPosition
70
- maintainScrollAtEnd
71
- alignItemsAtEnd
72
- renderItem={({ item }) => (
73
- <>
74
- <View
75
- style={[
76
- styles.messageContainer,
77
- item.sender === "bot" ? styles.botMessageContainer : styles.userMessageContainer,
78
- item.sender === "bot" ? styles.botStyle : styles.userStyle,
79
- ]}
80
- >
81
- <Text style={[styles.messageText, item.sender === "user" && styles.userMessageText]}>
82
- {item.text}
83
- </Text>
84
- </View>
85
- <View
86
- style={[styles.timeStamp, item.sender === "bot" ? styles.botStyle : styles.userStyle]}
87
- >
88
- <Text style={styles.timeStampText}>
89
- {new Date(item.timeStamp).toLocaleTimeString()}
90
- </Text>
91
- </View>
92
- </>
93
- )}
94
- />
95
- <View style={styles.inputContainer}>
96
- <TextInput
97
- style={styles.input}
98
- value={inputText}
99
- onChangeText={setInputText}
100
- placeholder="Type a message"
101
- />
102
- <Button title="Send" onPress={sendMessage} />
103
- </View>
104
- </KeyboardAvoidingView>
105
- </SafeAreaView>
106
- );
107
- };
108
-
109
- const styles = StyleSheet.create({
110
- container: {
111
- flex: 1,
112
- backgroundColor: "#fff",
113
- },
114
- contentContainer: {
115
- paddingHorizontal: 16,
116
- },
117
- messageContainer: {
118
- padding: 16,
119
- borderRadius: 16,
120
- marginVertical: 4,
121
- },
122
- messageText: {
123
- fontSize: 16,
124
- },
125
- userMessageText: {
126
- color: "white",
127
- },
128
- inputContainer: {
129
- flexDirection: "row",
130
- alignItems: "center",
131
- padding: 10,
132
- borderTopWidth: 1,
133
- borderColor: "#ccc",
134
- },
135
- botMessageContainer: {
136
- backgroundColor: "#f1f1f1",
137
- },
138
- userMessageContainer: {
139
- backgroundColor: "#007AFF",
140
- },
141
- botStyle: {
142
- maxWidth: "75%",
143
- alignSelf: "flex-start",
144
- },
145
- userStyle: {
146
- maxWidth: "75%",
147
- alignSelf: "flex-end",
148
- alignItems: "flex-end",
149
- },
150
- input: {
151
- flex: 1,
152
- borderWidth: 1,
153
- borderColor: "#ccc",
154
- borderRadius: 5,
155
- padding: 10,
156
- marginRight: 10,
157
- },
158
- timeStamp: {
159
- marginVertical: 5,
160
- },
161
- timeStampText: {
162
- fontSize: 12,
163
- color: "#888",
164
- },
165
- });
166
-
167
- export default ChatExample;