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

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 (260) hide show
  1. package/{dist/index.d.mts → index.d.mts} +28 -21
  2. package/{dist/index.d.ts → index.d.ts} +28 -21
  3. package/{dist/index.js → index.js} +808 -760
  4. package/{dist/index.mjs → index.mjs} +808 -760
  5. package/{dist → integrations}/animated.d.mts +2 -1
  6. package/{dist → integrations}/animated.d.ts +2 -1
  7. package/{dist → integrations}/animated.js +2 -2
  8. package/{dist → integrations}/animated.mjs +2 -2
  9. package/{dist → integrations}/keyboard-controller.d.mts +4 -0
  10. package/{dist → integrations}/keyboard-controller.d.ts +4 -0
  11. package/{dist → integrations}/keyboard-controller.js +4 -4
  12. package/{dist → integrations}/keyboard-controller.mjs +4 -4
  13. package/{dist → integrations}/reanimated.js +7 -7
  14. package/{dist → integrations}/reanimated.mjs +7 -7
  15. package/package.json +34 -88
  16. package/.claude/settings.local.json +0 -8
  17. package/.cursor/rules/changelog.mdc +0 -60
  18. package/.github/FUNDING.yml +0 -15
  19. package/.gitignore +0 -5
  20. package/.prettierrc.json +0 -5
  21. package/.vscode/settings.json +0 -14
  22. package/CLAUDE.md +0 -126
  23. package/biome.json +0 -46
  24. package/bun.lock +0 -1289
  25. package/bunfig.toml +0 -2
  26. package/dist/CHANGELOG.md +0 -119
  27. package/dist/LICENSE +0 -21
  28. package/dist/README.md +0 -139
  29. package/dist/package.json +0 -35
  30. package/example/README.md +0 -40
  31. package/example/api/data/genres.json +0 -23
  32. package/example/api/data/playlist/10402-10749.json +0 -1
  33. package/example/api/data/playlist/10402-10770.json +0 -1
  34. package/example/api/data/playlist/10402-37.json +0 -1
  35. package/example/api/data/playlist/10749-10752.json +0 -1
  36. package/example/api/data/playlist/10749-10770.json +0 -1
  37. package/example/api/data/playlist/10749-37.json +0 -1
  38. package/example/api/data/playlist/10749-878.json +0 -1
  39. package/example/api/data/playlist/10751-10402.json +0 -1
  40. package/example/api/data/playlist/10751-10752.json +0 -1
  41. package/example/api/data/playlist/10751-37.json +0 -1
  42. package/example/api/data/playlist/10751-53.json +0 -1
  43. package/example/api/data/playlist/10751-878.json +0 -1
  44. package/example/api/data/playlist/10751-9648.json +0 -1
  45. package/example/api/data/playlist/10752-37.json +0 -1
  46. package/example/api/data/playlist/12-10402.json +0 -1
  47. package/example/api/data/playlist/12-10749.json +0 -1
  48. package/example/api/data/playlist/12-18.json +0 -1
  49. package/example/api/data/playlist/12-27.json +0 -1
  50. package/example/api/data/playlist/12-35.json +0 -1
  51. package/example/api/data/playlist/14-36.json +0 -1
  52. package/example/api/data/playlist/14-878.json +0 -1
  53. package/example/api/data/playlist/16-10751.json +0 -1
  54. package/example/api/data/playlist/16-10770.json +0 -1
  55. package/example/api/data/playlist/16-35.json +0 -1
  56. package/example/api/data/playlist/16-36.json +0 -1
  57. package/example/api/data/playlist/16-53.json +0 -1
  58. package/example/api/data/playlist/18-10751.json +0 -1
  59. package/example/api/data/playlist/18-10752.json +0 -1
  60. package/example/api/data/playlist/18-37.json +0 -1
  61. package/example/api/data/playlist/18-53.json +0 -1
  62. package/example/api/data/playlist/18-878.json +0 -1
  63. package/example/api/data/playlist/27-10749.json +0 -1
  64. package/example/api/data/playlist/27-10770.json +0 -1
  65. package/example/api/data/playlist/28-10749.json +0 -1
  66. package/example/api/data/playlist/28-10751.json +0 -1
  67. package/example/api/data/playlist/28-10770.json +0 -1
  68. package/example/api/data/playlist/28-16.json +0 -1
  69. package/example/api/data/playlist/28-18.json +0 -1
  70. package/example/api/data/playlist/28-36.json +0 -1
  71. package/example/api/data/playlist/28-37.json +0 -1
  72. package/example/api/data/playlist/28-53.json +0 -1
  73. package/example/api/data/playlist/28-80.json +0 -1
  74. package/example/api/data/playlist/28-99.json +0 -1
  75. package/example/api/data/playlist/35-10749.json +0 -1
  76. package/example/api/data/playlist/35-10751.json +0 -1
  77. package/example/api/data/playlist/35-10752.json +0 -1
  78. package/example/api/data/playlist/35-27.json +0 -1
  79. package/example/api/data/playlist/35-36.json +0 -1
  80. package/example/api/data/playlist/35-53.json +0 -1
  81. package/example/api/data/playlist/35-80.json +0 -1
  82. package/example/api/data/playlist/36-37.json +0 -1
  83. package/example/api/data/playlist/36-878.json +0 -1
  84. package/example/api/data/playlist/36-9648.json +0 -1
  85. package/example/api/data/playlist/53-10752.json +0 -1
  86. package/example/api/data/playlist/80-10770.json +0 -1
  87. package/example/api/data/playlist/80-14.json +0 -1
  88. package/example/api/data/playlist/80-18.json +0 -1
  89. package/example/api/data/playlist/80-37.json +0 -1
  90. package/example/api/data/playlist/878-37.json +0 -1
  91. package/example/api/data/playlist/9648-10770.json +0 -1
  92. package/example/api/data/playlist/9648-37.json +0 -1
  93. package/example/api/data/playlist/9648-53.json +0 -1
  94. package/example/api/data/playlist/9648-878.json +0 -1
  95. package/example/api/data/playlist/99-10749.json +0 -1
  96. package/example/api/data/playlist/99-14.json +0 -1
  97. package/example/api/data/playlist/99-18.json +0 -1
  98. package/example/api/data/playlist/99-27.json +0 -1
  99. package/example/api/data/playlist/99-53.json +0 -1
  100. package/example/api/data/playlist/99-9648.json +0 -1
  101. package/example/api/data/playlist/index.ts +0 -73
  102. package/example/api/data/rows.json +0 -1
  103. package/example/api/index.ts +0 -36
  104. package/example/app/(tabs)/_layout.tsx +0 -60
  105. package/example/app/(tabs)/cards.tsx +0 -81
  106. package/example/app/(tabs)/index.tsx +0 -205
  107. package/example/app/(tabs)/moviesL.tsx +0 -7
  108. package/example/app/(tabs)/moviesLR.tsx +0 -7
  109. package/example/app/+not-found.tsx +0 -32
  110. package/example/app/_layout.tsx +0 -34
  111. package/example/app/accurate-scrollto/index.tsx +0 -125
  112. package/example/app/accurate-scrollto-2/index.tsx +0 -52
  113. package/example/app/accurate-scrollto-huge/index.tsx +0 -128
  114. package/example/app/add-to-end/index.tsx +0 -82
  115. package/example/app/ai-chat/index.tsx +0 -236
  116. package/example/app/bidirectional-infinite-list/index.tsx +0 -133
  117. package/example/app/cards-columns/index.tsx +0 -37
  118. package/example/app/cards-flashlist/index.tsx +0 -122
  119. package/example/app/cards-flatlist/index.tsx +0 -94
  120. package/example/app/cards-no-recycle/index.tsx +0 -110
  121. package/example/app/cards-renderItem.tsx +0 -354
  122. package/example/app/chat-example/index.tsx +0 -167
  123. package/example/app/chat-infinite/index.tsx +0 -239
  124. package/example/app/chat-keyboard/index.tsx +0 -248
  125. package/example/app/chat-resize-outer/index.tsx +0 -247
  126. package/example/app/columns/index.tsx +0 -78
  127. package/example/app/countries/index.tsx +0 -182
  128. package/example/app/countries-flashlist/index.tsx +0 -163
  129. package/example/app/countries-reorder/index.tsx +0 -187
  130. package/example/app/extra-data/index.tsx +0 -86
  131. package/example/app/filter-elements/filter-data-provider.tsx +0 -55
  132. package/example/app/filter-elements/index.tsx +0 -118
  133. package/example/app/initial-scroll-index/index.tsx +0 -106
  134. package/example/app/initial-scroll-index/renderFixedItem.tsx +0 -215
  135. package/example/app/initial-scroll-index-free-height/index.tsx +0 -70
  136. package/example/app/initial-scroll-index-keyed/index.tsx +0 -62
  137. package/example/app/lazy-list/index.tsx +0 -123
  138. package/example/app/movies-flashlist/index.tsx +0 -7
  139. package/example/app/mutable-cells/index.tsx +0 -104
  140. package/example/app/video-feed/index.tsx +0 -119
  141. package/example/app.config.js +0 -22
  142. package/example/app.json +0 -45
  143. package/example/assets/fonts/SpaceMono-Regular.ttf +0 -0
  144. package/example/assets/images/adaptive-icon.png +0 -0
  145. package/example/assets/images/favicon.png +0 -0
  146. package/example/assets/images/icon.png +0 -0
  147. package/example/assets/images/partial-react-logo.png +0 -0
  148. package/example/assets/images/react-logo.png +0 -0
  149. package/example/assets/images/react-logo@2x.png +0 -0
  150. package/example/assets/images/react-logo@3x.png +0 -0
  151. package/example/assets/images/splash-icon.png +0 -0
  152. package/example/autoscroll.sh +0 -101
  153. package/example/bun.lock +0 -2266
  154. package/example/bunfig.toml +0 -2
  155. package/example/components/Breathe.tsx +0 -54
  156. package/example/components/Circle.tsx +0 -69
  157. package/example/components/Collapsible.tsx +0 -44
  158. package/example/components/ExternalLink.tsx +0 -24
  159. package/example/components/HapticTab.tsx +0 -18
  160. package/example/components/HelloWave.tsx +0 -37
  161. package/example/components/Movies.tsx +0 -179
  162. package/example/components/ParallaxScrollView.tsx +0 -81
  163. package/example/components/ThemedText.tsx +0 -60
  164. package/example/components/ThemedView.tsx +0 -14
  165. package/example/components/__tests__/ThemedText-test.tsx +0 -10
  166. package/example/components/__tests__/__snapshots__/ThemedText-test.tsx.snap +0 -24
  167. package/example/components/ui/IconSymbol.ios.tsx +0 -32
  168. package/example/components/ui/IconSymbol.tsx +0 -43
  169. package/example/components/ui/TabBarBackground.ios.tsx +0 -22
  170. package/example/components/ui/TabBarBackground.tsx +0 -6
  171. package/example/constants/Colors.ts +0 -26
  172. package/example/constants/constants.ts +0 -5
  173. package/example/constants/useScrollTest.ts +0 -19
  174. package/example/hooks/useColorScheme.ts +0 -1
  175. package/example/hooks/useColorScheme.web.ts +0 -8
  176. package/example/hooks/useThemeColor.ts +0 -22
  177. package/example/ios/.xcode.env +0 -11
  178. package/example/ios/Podfile +0 -64
  179. package/example/ios/Podfile.lock +0 -2767
  180. package/example/ios/Podfile.properties.json +0 -5
  181. package/example/ios/listtest/AppDelegate.swift +0 -70
  182. package/example/ios/listtest/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png +0 -0
  183. package/example/ios/listtest/Images.xcassets/AppIcon.appiconset/Contents.json +0 -14
  184. package/example/ios/listtest/Images.xcassets/Contents.json +0 -6
  185. package/example/ios/listtest/Images.xcassets/SplashScreenBackground.colorset/Contents.json +0 -20
  186. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/Contents.json +0 -23
  187. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image.png +0 -0
  188. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image@2x.png +0 -0
  189. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image@3x.png +0 -0
  190. package/example/ios/listtest/Info.plist +0 -85
  191. package/example/ios/listtest/PrivacyInfo.xcprivacy +0 -48
  192. package/example/ios/listtest/SplashScreen.storyboard +0 -42
  193. package/example/ios/listtest/Supporting/Expo.plist +0 -12
  194. package/example/ios/listtest/listtest-Bridging-Header.h +0 -3
  195. package/example/ios/listtest/listtest.entitlements +0 -5
  196. package/example/ios/listtest.xcodeproj/project.pbxproj +0 -547
  197. package/example/ios/listtest.xcodeproj/xcshareddata/xcschemes/listtest.xcscheme +0 -88
  198. package/example/ios/listtest.xcworkspace/contents.xcworkspacedata +0 -10
  199. package/example/metro.config.js +0 -16
  200. package/example/package.json +0 -73
  201. package/example/scripts/reset-project.js +0 -84
  202. package/example/tsconfig.json +0 -26
  203. package/posttsup.ts +0 -24
  204. package/src/Container.tsx +0 -176
  205. package/src/Containers.tsx +0 -85
  206. package/src/ContextContainer.ts +0 -145
  207. package/src/DebugView.tsx +0 -83
  208. package/src/LazyLegendList.tsx +0 -41
  209. package/src/LeanView.tsx +0 -18
  210. package/src/LegendList.tsx +0 -558
  211. package/src/ListComponent.tsx +0 -191
  212. package/src/ScrollAdjust.tsx +0 -24
  213. package/src/ScrollAdjustHandler.ts +0 -26
  214. package/src/Separator.tsx +0 -14
  215. package/src/animated.tsx +0 -6
  216. package/src/calculateItemsInView.ts +0 -363
  217. package/src/calculateOffsetForIndex.ts +0 -23
  218. package/src/calculateOffsetWithOffsetPosition.ts +0 -26
  219. package/src/checkAllSizesKnown.ts +0 -17
  220. package/src/checkAtBottom.ts +0 -36
  221. package/src/checkAtTop.ts +0 -27
  222. package/src/checkThreshold.ts +0 -30
  223. package/src/constants.ts +0 -11
  224. package/src/createColumnWrapperStyle.ts +0 -16
  225. package/src/doInitialAllocateContainers.ts +0 -40
  226. package/src/doMaintainScrollAtEnd.ts +0 -34
  227. package/src/findAvailableContainers.ts +0 -98
  228. package/src/finishScrollTo.ts +0 -8
  229. package/src/getId.ts +0 -21
  230. package/src/getItemSize.ts +0 -52
  231. package/src/getRenderedItem.ts +0 -34
  232. package/src/getScrollVelocity.ts +0 -47
  233. package/src/handleLayout.ts +0 -70
  234. package/src/helpers.ts +0 -39
  235. package/src/index.ts +0 -11
  236. package/src/keyboard-controller.tsx +0 -63
  237. package/src/onScroll.ts +0 -66
  238. package/src/prepareMVCP.ts +0 -50
  239. package/src/reanimated.tsx +0 -63
  240. package/src/requestAdjust.ts +0 -41
  241. package/src/scrollTo.ts +0 -40
  242. package/src/scrollToIndex.ts +0 -34
  243. package/src/setDidLayout.ts +0 -25
  244. package/src/setPaddingTop.ts +0 -28
  245. package/src/state.tsx +0 -304
  246. package/src/types.ts +0 -610
  247. package/src/updateAlignItemsPaddingTop.ts +0 -18
  248. package/src/updateAllPositions.ts +0 -130
  249. package/src/updateItemSize.ts +0 -203
  250. package/src/updateTotalSize.ts +0 -44
  251. package/src/useAnimatedValue.ts +0 -6
  252. package/src/useCombinedRef.ts +0 -22
  253. package/src/useInit.ts +0 -17
  254. package/src/useSyncLayout.tsx +0 -68
  255. package/src/useValue$.ts +0 -53
  256. package/src/viewability.ts +0 -279
  257. package/tsconfig.json +0 -59
  258. package/tsup.config.ts +0 -21
  259. package/{dist → integrations}/reanimated.d.mts +1 -1
  260. package/{dist → integrations}/reanimated.d.ts +1 -1
@@ -1,73 +0,0 @@
1
- {
2
- "name": "list-test",
3
- "license": "MIT",
4
- "main": "expo-router/entry",
5
- "version": "1.0.0",
6
- "scripts": {
7
- "start": "expo start",
8
- "android": "expo run:android",
9
- "android:release": "RELEASE=TRUE expo run:android --variant release",
10
- "android-o": "OLD_ARCH=TRUE expo run:android",
11
- "android-o:release": "RELEASE=TRUE OLD_ARCH=TRUE expo run:android --variant release",
12
- "ios": "expo run:ios",
13
- "ios-o": "OLD_ARCH=TRUE expo run:ios",
14
- "web": "expo start --web",
15
- "test": "jest --watchAll",
16
- "lint": "expo lint",
17
- "prebuild:clean": "rm -rf ios android && npx expo prebuild --clean && npx expo prebuild",
18
- "prebuild-o:clean": "rm -rf ios android && OLD_ARCH=TRUE npx expo prebuild --clean && OLD_ARCH=TRUE npx expo prebuild"
19
- },
20
- "jest": {
21
- "preset": "jest-expo"
22
- },
23
- "dependencies": {
24
- "@expo/vector-icons": "^14.1.0",
25
- "@legendapp/motion": "^2.4.0",
26
- "@legendapp/state": "^3.0.0-beta.19",
27
- "@react-navigation/bottom-tabs": "^7.3.10",
28
- "@react-navigation/native": "^7.1.6",
29
- "@shopify/flash-list": "1.7.6",
30
- "babel-plugin-react-compiler": "^19.1.0-rc.2",
31
- "countries-list": "^3.1.1",
32
- "expo": "^53.0.11",
33
- "expo-atlas": "^0.4.0",
34
- "expo-blur": "~14.1.5",
35
- "expo-constants": "~17.1.6",
36
- "expo-dev-client": "~5.2.0",
37
- "expo-font": "~13.3.1",
38
- "expo-haptics": "~14.1.4",
39
- "expo-linear-gradient": "~14.1.5",
40
- "expo-linking": "~7.1.5",
41
- "expo-router": "~5.1.0",
42
- "expo-splash-screen": "~0.30.9",
43
- "expo-status-bar": "~2.2.3",
44
- "expo-symbols": "~0.4.5",
45
- "expo-system-ui": "~5.0.8",
46
- "expo-web-browser": "~14.1.6",
47
- "react": "19.0.0",
48
- "react-compiler-runtime": "^19.1.0-rc.2",
49
- "react-dom": "19.0.0",
50
- "react-native": "0.79.3",
51
- "react-native-gesture-handler": "~2.24.0",
52
- "react-native-keyboard-controller": "^1.17.4",
53
- "react-native-reanimated": "~3.17.4",
54
- "react-native-redash": "^18.1.3",
55
- "react-native-safe-area-context": "5.4.0",
56
- "react-native-screens": "~4.11.1",
57
- "react-native-web": "^0.20.0",
58
- "react-native-webview": "13.13.5"
59
- },
60
- "devDependencies": {
61
- "@babel/core": "^7.27.4",
62
- "@react-native-community/cli": "latest",
63
- "@types/expo__vector-icons": "^10.0.2",
64
- "@types/jest": "^29.5.14",
65
- "@types/react": "~19.0.10",
66
- "@types/react-test-renderer": "^19.0.0",
67
- "jest": "~29.7.0",
68
- "jest-expo": "~53.0.7",
69
- "react-test-renderer": "19.0.0",
70
- "typescript": "~5.8.3"
71
- },
72
- "private": true
73
- }
@@ -1,84 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * This script is used to reset the project to a blank state.
5
- * It moves the /app, /components, /hooks, /scripts, and /constants directories to /app-example and creates a new /app directory with an index.tsx and _layout.tsx file.
6
- * You can remove the `reset-project` script from package.json and safely delete this file after running it.
7
- */
8
-
9
- const fs = require("fs");
10
- const path = require("path");
11
-
12
- const root = process.cwd();
13
- const oldDirs = ["app", "components", "hooks", "constants", "scripts"];
14
- const newDir = "app-example";
15
- const newAppDir = "app";
16
- const newDirPath = path.join(root, newDir);
17
-
18
- const indexContent = `import { Text, View } from "react-native";
19
-
20
- export default function Index() {
21
- return (
22
- <View
23
- style={{
24
- flex: 1,
25
- justifyContent: "center",
26
- alignItems: "center",
27
- }}
28
- >
29
- <Text>Edit app/index.tsx to edit this screen.</Text>
30
- </View>
31
- );
32
- }
33
- `;
34
-
35
- const layoutContent = `import { Stack } from "expo-router";
36
-
37
- export default function RootLayout() {
38
- return <Stack />;
39
- }
40
- `;
41
-
42
- const moveDirectories = async () => {
43
- try {
44
- // Create the app-example directory
45
- await fs.promises.mkdir(newDirPath, { recursive: true });
46
- console.log(`📁 /${newDir} directory created.`);
47
-
48
- // Move old directories to new app-example directory
49
- for (const dir of oldDirs) {
50
- const oldDirPath = path.join(root, dir);
51
- const newDirPath = path.join(root, newDir, dir);
52
- if (fs.existsSync(oldDirPath)) {
53
- await fs.promises.rename(oldDirPath, newDirPath);
54
- console.log(`➡️ /${dir} moved to /${newDir}/${dir}.`);
55
- } else {
56
- console.log(`➡️ /${dir} does not exist, skipping.`);
57
- }
58
- }
59
-
60
- // Create new /app directory
61
- const newAppDirPath = path.join(root, newAppDir);
62
- await fs.promises.mkdir(newAppDirPath, { recursive: true });
63
- console.log("\n📁 New /app directory created.");
64
-
65
- // Create index.tsx
66
- const indexPath = path.join(newAppDirPath, "index.tsx");
67
- await fs.promises.writeFile(indexPath, indexContent);
68
- console.log("📄 app/index.tsx created.");
69
-
70
- // Create _layout.tsx
71
- const layoutPath = path.join(newAppDirPath, "_layout.tsx");
72
- await fs.promises.writeFile(layoutPath, layoutContent);
73
- console.log("📄 app/_layout.tsx created.");
74
-
75
- console.log("\n✅ Project reset complete. Next steps:");
76
- console.log(
77
- "1. Run `npx expo start` to start a development server.\n2. Edit app/index.tsx to edit the main screen.\n3. Delete the /app-example directory when you're done referencing it."
78
- );
79
- } catch (error) {
80
- console.error(`Error during script execution: ${error}`);
81
- }
82
- };
83
-
84
- moveDirectories();
@@ -1,26 +0,0 @@
1
- {
2
- "extends": "expo/tsconfig.base",
3
- "compilerOptions": {
4
- "strict": true,
5
- "paths": {
6
- "@/*": [
7
- "./*"
8
- ],
9
- "@legendapp/list": [
10
- "../src/index"
11
- ],
12
- "@legendapp/list/keyboard-controller": [
13
- "../src/keyboard-controller"
14
- ],
15
- "@legendapp/list/reanimated": [
16
- "../src/reanimated"
17
- ]
18
- }
19
- },
20
- "include": [
21
- "**/*.ts",
22
- "**/*.tsx",
23
- ".expo/types/**/*.ts",
24
- "expo-env.d.ts"
25
- ],
26
- }
package/posttsup.ts DELETED
@@ -1,24 +0,0 @@
1
- import pkg from './package.json';
2
-
3
- async function copy(...files: string[]) {
4
- return files.map((file) => Bun.write('dist/' + file.replace('src/', ''), Bun.file(file), { createPath: true }));
5
- }
6
-
7
- copy('LICENSE', 'CHANGELOG.md', 'README.md');
8
-
9
- const exports: Record<string, string | { import?: string; require?: string; types: string }> = {
10
- './package.json': './package.json',
11
- };
12
-
13
- const pkgOut = pkg as Record<string, any>;
14
-
15
- pkg.private = false;
16
- pkgOut.exports = exports;
17
- delete pkgOut.devDependencies;
18
- delete pkgOut.overrides;
19
- delete pkgOut.scripts;
20
- delete pkgOut.engines;
21
- delete pkgOut.exports;
22
- delete pkgOut.commitlint;
23
-
24
- Bun.write('dist/package.json', JSON.stringify(pkg, undefined, 2));
package/src/Container.tsx DELETED
@@ -1,176 +0,0 @@
1
- // biome-ignore lint/style/useImportType: Leaving this out makes it crash in some environments
2
- import * as React from "react";
3
- import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
4
- import type { DimensionValue, LayoutChangeEvent, StyleProp, View, ViewStyle } from "react-native";
5
- import { ContextContainer, type ContextContainerType } from "./ContextContainer";
6
- import { LeanView } from "./LeanView";
7
- import { Separator } from "./Separator";
8
- import { IsNewArchitecture, POSITION_OUT_OF_VIEW } from "./constants";
9
- import { isNullOrUndefined } from "./helpers";
10
- import { useArr$, useStateContext } from "./state";
11
- import type { GetRenderedItem } from "./types";
12
-
13
- export const Container = <ItemT,>({
14
- id,
15
- recycleItems,
16
- horizontal,
17
- getRenderedItem,
18
- updateItemSize,
19
- ItemSeparatorComponent,
20
- }: {
21
- id: number;
22
- recycleItems?: boolean;
23
- horizontal: boolean;
24
- getRenderedItem: GetRenderedItem;
25
- updateItemSize: (itemKey: string, size: { width: number; height: number }) => void;
26
- ItemSeparatorComponent?: React.ComponentType<{ leadingItem: ItemT }>;
27
- }) => {
28
- const ctx = useStateContext();
29
- const columnWrapperStyle = ctx.columnWrapperStyle;
30
-
31
- const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, extraData] = useArr$([
32
- `containerColumn${id}`,
33
- `containerItemData${id}`,
34
- `containerItemKey${id}`,
35
- `containerPosition${id}`,
36
- "numColumns",
37
- "extraData",
38
- ]);
39
-
40
- const refLastSize = useRef<{ width: number; height: number }>();
41
- const ref = useRef<View>(null);
42
- const [layoutRenderCount, forceLayoutRender] = useState(0);
43
-
44
- const otherAxisPos: DimensionValue | undefined = numColumns > 1 ? `${((column - 1) / numColumns) * 100}%` : 0;
45
- const otherAxisSize: DimensionValue | undefined = numColumns > 1 ? `${(1 / numColumns) * 100}%` : undefined;
46
- let didLayout = false;
47
-
48
- let paddingStyles: ViewStyle | undefined;
49
- if (columnWrapperStyle) {
50
- // Extract gap properties from columnWrapperStyle if available
51
- const { columnGap, rowGap, gap } = columnWrapperStyle;
52
-
53
- // Create padding styles for both horizontal and vertical layouts with multiple columns
54
- if (horizontal) {
55
- paddingStyles = {
56
- paddingRight: columnGap || gap || undefined,
57
- paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : undefined,
58
- };
59
- } else {
60
- paddingStyles = {
61
- paddingBottom: rowGap || gap || undefined,
62
- paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : undefined,
63
- };
64
- }
65
- }
66
-
67
- const style: StyleProp<ViewStyle> = horizontal
68
- ? {
69
- flexDirection: ItemSeparatorComponent ? "row" : undefined,
70
- position: "absolute",
71
- top: otherAxisPos,
72
- height: otherAxisSize,
73
- left: position,
74
- ...(paddingStyles || {}),
75
- }
76
- : {
77
- position: "absolute",
78
- left: otherAxisPos,
79
- right: numColumns > 1 ? null : 0,
80
- width: otherAxisSize,
81
- top: position,
82
- ...(paddingStyles || {}),
83
- };
84
-
85
- const renderedItemInfo = useMemo(
86
- () => (itemKey !== undefined ? getRenderedItem(itemKey) : null),
87
- [itemKey, data, extraData],
88
- );
89
- const { index, renderedItem } = renderedItemInfo || {};
90
-
91
- const triggerLayout = useCallback(() => {
92
- forceLayoutRender((v) => v + 1);
93
- }, []);
94
-
95
- const contextValue = useMemo<ContextContainerType>(() => {
96
- ctx.viewRefs.set(id, ref);
97
- return { containerId: id, itemKey, index: index!, value: data, triggerLayout };
98
- }, [id, itemKey, index, data]);
99
-
100
- const onLayout = (event: LayoutChangeEvent) => {
101
- if (!isNullOrUndefined(itemKey)) {
102
- didLayout = true;
103
- let layout: { width: number; height: number } = event.nativeEvent.layout;
104
- const size = layout[horizontal ? "width" : "height"];
105
-
106
- const doUpdate = () => {
107
- refLastSize.current = { width: layout.width, height: layout.height };
108
- updateItemSize(itemKey, layout);
109
- };
110
-
111
- if (IsNewArchitecture || size > 0) {
112
- doUpdate();
113
- } else {
114
- // On old architecture, the size can be 0 sometimes, maybe when not fully rendered?
115
- // So we need to make sure it's actually rendered and measure it to make sure it's actually 0.
116
- ref.current?.measure?.((x, y, width, height) => {
117
- layout = { width, height };
118
- doUpdate();
119
- });
120
- }
121
- }
122
- };
123
-
124
- if (IsNewArchitecture) {
125
- // New architecture supports unstable_getBoundingClientRect for getting layout synchronously
126
- useLayoutEffect(() => {
127
- if (!isNullOrUndefined(itemKey)) {
128
- // @ts-expect-error unstable_getBoundingClientRect is unstable and only on Fabric
129
- const measured = ref.current?.unstable_getBoundingClientRect?.();
130
- if (measured) {
131
- const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
132
-
133
- if (size) {
134
- updateItemSize(itemKey, measured);
135
- }
136
- }
137
- }
138
- }, [itemKey, layoutRenderCount]);
139
- } else {
140
- // Since old architecture cannot use unstable_getBoundingClientRect it needs to ensure that
141
- // all containers updateItemSize even if the container did not resize.
142
- useEffect(() => {
143
- // Catch a bug where a container is reused and is the exact same size as the previous item
144
- // so it does not fire an onLayout, so we need to trigger it manually.
145
- // TODO: There must be a better way to do this?
146
- if (!isNullOrUndefined(itemKey)) {
147
- const timeout = setTimeout(() => {
148
- if (!didLayout && refLastSize.current) {
149
- updateItemSize(itemKey, refLastSize.current);
150
- }
151
- }, 16);
152
- return () => {
153
- clearTimeout(timeout);
154
- };
155
- }
156
- }, [itemKey]);
157
- }
158
-
159
- // Use a reactive View to ensure the container element itself
160
- // is not rendered when style changes, only the style prop.
161
- // This is a big perf boost to do less work rendering.
162
- return (
163
- <LeanView style={style} onLayout={onLayout} ref={ref} key={recycleItems ? undefined : itemKey}>
164
- <ContextContainer.Provider value={contextValue}>
165
- {renderedItem}
166
- {renderedItemInfo && ItemSeparatorComponent && (
167
- <Separator
168
- itemKey={itemKey}
169
- ItemSeparatorComponent={ItemSeparatorComponent}
170
- leadingItem={renderedItemInfo.item}
171
- />
172
- )}
173
- </ContextContainer.Provider>
174
- </LeanView>
175
- );
176
- };
@@ -1,85 +0,0 @@
1
- // biome-ignore lint/style/useImportType: Leaving this out makes it crash in some environments
2
- import * as React from "react";
3
- import { Animated, type StyleProp, type ViewStyle } from "react-native";
4
- import { Container } from "./Container";
5
- import { IsNewArchitecture } from "./constants";
6
- import { useArr$, useStateContext } from "./state";
7
- import { type GetRenderedItem, typedMemo } from "./types";
8
- import { useValue$ } from "./useValue$";
9
-
10
- interface ContainersProps<ItemT> {
11
- horizontal: boolean;
12
- recycleItems: boolean;
13
- ItemSeparatorComponent?: React.ComponentType<{ leadingItem: ItemT }>;
14
- waitForInitialLayout: boolean | undefined;
15
- updateItemSize: (itemKey: string, size: { width: number; height: number }) => void;
16
- getRenderedItem: GetRenderedItem;
17
- }
18
-
19
- export const Containers = typedMemo(function Containers<ItemT>({
20
- horizontal,
21
- recycleItems,
22
- ItemSeparatorComponent,
23
- waitForInitialLayout,
24
- updateItemSize,
25
- getRenderedItem,
26
- }: ContainersProps<ItemT>) {
27
- const ctx = useStateContext();
28
- const columnWrapperStyle = ctx.columnWrapperStyle;
29
- const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
30
- const animSize = useValue$("totalSize", {
31
- // Use a microtask if increasing the size significantly, otherwise use a timeout
32
- delay: (value, prevValue) => (!prevValue || value - prevValue > 20 ? 0 : 200),
33
- });
34
- const animOpacity =
35
- waitForInitialLayout && !IsNewArchitecture
36
- ? useValue$("containersDidLayout", { getValue: (value) => (value ? 1 : 0) })
37
- : undefined;
38
- const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
39
-
40
- const containers: React.ReactNode[] = [];
41
- for (let i = 0; i < numContainers; i++) {
42
- containers.push(
43
- <Container
44
- id={i}
45
- key={i}
46
- recycleItems={recycleItems}
47
- horizontal={horizontal}
48
- getRenderedItem={getRenderedItem}
49
- updateItemSize={updateItemSize}
50
- // specifying inline separator makes Containers rerender on each data change
51
- // should we do memo of ItemSeparatorComponent?
52
- ItemSeparatorComponent={ItemSeparatorComponent}
53
- />,
54
- );
55
- }
56
-
57
- const style: StyleProp<ViewStyle> = horizontal
58
- ? { width: animSize, opacity: animOpacity, minHeight: otherAxisSize }
59
- : { height: animSize, opacity: animOpacity, minWidth: otherAxisSize };
60
-
61
- if (columnWrapperStyle && numColumns > 1) {
62
- // Extract gap properties from columnWrapperStyle if available
63
- const { columnGap, rowGap, gap } = columnWrapperStyle;
64
-
65
- const gapX = columnGap || gap || 0;
66
- const gapY = rowGap || gap || 0;
67
- if (horizontal) {
68
- if (gapY) {
69
- style.marginVertical = -gapY / 2;
70
- }
71
- if (gapX) {
72
- style.marginRight = -gapX;
73
- }
74
- } else {
75
- if (gapX) {
76
- style.marginHorizontal = -gapX;
77
- }
78
- if (gapY) {
79
- style.marginBottom = -gapY;
80
- }
81
- }
82
- }
83
-
84
- return <Animated.View style={style}>{containers}</Animated.View>;
85
- });
@@ -1,145 +0,0 @@
1
- import {
2
- type Dispatch,
3
- type SetStateAction,
4
- createContext,
5
- useCallback,
6
- useContext,
7
- useEffect,
8
- useRef,
9
- useState,
10
- } from "react";
11
- import { isFunction } from "./helpers";
12
- import { useArr$, useSelector$, useStateContext } from "./state";
13
- import type { LegendListRecyclingState, ViewabilityAmountCallback, ViewabilityCallback } from "./types";
14
- import { useInit } from "./useInit";
15
-
16
- export interface ContextContainerType {
17
- containerId: number;
18
- itemKey: string;
19
- index: number;
20
- value: any;
21
- triggerLayout: () => void;
22
- }
23
-
24
- export const ContextContainer = createContext<ContextContainerType>(null as any);
25
-
26
- export function useViewability(callback: ViewabilityCallback, configId?: string) {
27
- const ctx = useStateContext();
28
- const { containerId } = useContext(ContextContainer);
29
-
30
- const key = containerId + (configId ?? "");
31
-
32
- useInit(() => {
33
- const value = ctx.mapViewabilityValues.get(key);
34
- if (value) {
35
- callback(value);
36
- }
37
- });
38
-
39
- ctx.mapViewabilityCallbacks.set(key, callback);
40
-
41
- useEffect(
42
- () => () => {
43
- ctx.mapViewabilityCallbacks.delete(key);
44
- },
45
- [],
46
- );
47
- }
48
-
49
- export function useViewabilityAmount(callback: ViewabilityAmountCallback) {
50
- const ctx = useStateContext();
51
- const { containerId } = useContext(ContextContainer);
52
-
53
- useInit(() => {
54
- const value = ctx.mapViewabilityAmountValues.get(containerId);
55
- if (value) {
56
- callback(value);
57
- }
58
- });
59
-
60
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
61
-
62
- useEffect(
63
- () => () => {
64
- ctx.mapViewabilityAmountCallbacks.delete(containerId);
65
- },
66
- [],
67
- );
68
- }
69
-
70
- export function useRecyclingEffect(effect: (info: LegendListRecyclingState<unknown>) => void | (() => void)) {
71
- const { index, value } = useContext(ContextContainer);
72
- const prevValues = useRef<{ prevIndex: number | undefined; prevItem: any }>({
73
- prevIndex: undefined,
74
- prevItem: undefined,
75
- });
76
-
77
- useEffect(() => {
78
- let ret: void | (() => void) = undefined;
79
- // Only run effect if there's a previous value
80
- if (prevValues.current.prevIndex !== undefined && prevValues.current.prevItem !== undefined) {
81
- ret = effect({
82
- index,
83
- item: value,
84
- prevIndex: prevValues.current.prevIndex,
85
- prevItem: prevValues.current.prevItem,
86
- });
87
- }
88
-
89
- // Update refs for next render
90
- prevValues.current = {
91
- prevIndex: index,
92
- prevItem: value,
93
- };
94
-
95
- return ret;
96
- }, [index, value]);
97
- }
98
-
99
- export function useRecyclingState<ItemT>(valueOrFun: ((info: LegendListRecyclingState<ItemT>) => ItemT) | ItemT) {
100
- const { index, value, itemKey, triggerLayout } = useContext(ContextContainer);
101
- const refState = useRef<{ itemKey: string | null; value: ItemT | null }>({
102
- itemKey: null,
103
- value: null,
104
- });
105
- const [_, setRenderNum] = useState(0);
106
- const state = refState.current;
107
-
108
- if (state.itemKey !== itemKey) {
109
- state.itemKey = itemKey;
110
- // Reset local state in ref
111
- state.value = isFunction(valueOrFun)
112
- ? valueOrFun({
113
- index,
114
- item: value,
115
- prevIndex: undefined,
116
- prevItem: undefined,
117
- })
118
- : valueOrFun;
119
- }
120
-
121
- const setState: Dispatch<SetStateAction<ItemT>> = useCallback(
122
- (newState: SetStateAction<ItemT>) => {
123
- // Update local state in ref
124
- state.value = isFunction(newState) ? (newState as (prevState: ItemT) => ItemT)(state.value!) : newState;
125
- // Trigger item to re-render
126
- setRenderNum((v) => v + 1);
127
- // Trigger container to re-render to update item size
128
- triggerLayout();
129
- },
130
- [triggerLayout, state],
131
- );
132
-
133
- return [state.value, setState] as const;
134
- }
135
-
136
- export function useIsLastItem(): boolean {
137
- const { itemKey } = useContext(ContextContainer);
138
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => lastItemKeys?.includes(itemKey) || false);
139
- return isLast;
140
- }
141
-
142
- export function useListScrollSize(): { width: number; height: number } {
143
- const [scrollSize] = useArr$(["scrollSize"]);
144
- return scrollSize;
145
- }