diff --git a/.vscode/settings.json b/.vscode/settings.json index 5e248e34..4f25438d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,7 +24,7 @@ "editor.formatOnSave": true, "editor.defaultFormatter": "astro-build.astro-vscode" }, - "cSpell.words": ["Flashlist", "Lato"], + "cSpell.words": ["Legendlist", "Lato"], "i18n-ally.localesPaths": ["src/translations/"], "i18n-ally.keystyle": "nested", "i18n-ally.disabled": false, // make sure to disable i18n-ally in your global setting and only enable it for such projects diff --git a/README.md b/README.md index 649f0fd1..1e2f4b4d 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ We value the feedback and contributions of our users, and we encourage you to le - [Expo](https://docs.expo.io/) - [Expo Router](https://docs.expo.dev/router/introduction/) - [Nativewind](https://www.nativewind.dev/v4/overview) -- [Flash list](https://github.com/Shopify/flash-list) +- [Legend list](https://github.com/LegendApp/legend-list) - [React Query](https://tanstack.com/query/v4) - [Axios](https://axios-http.com/docs/intro) - [React Hook Form](https://react-hook-form.com/) diff --git a/cli/README.md b/cli/README.md index efa649dd..f1803574 100644 --- a/cli/README.md +++ b/cli/README.md @@ -104,7 +104,7 @@ We value the feedback and contributions of our users, and we encourage you to le - [Expo](https://docs.expo.io/) - [Expo Router](https://docs.expo.dev/router/introduction/) - [Nativewind](https://www.nativewind.dev/) -- [Flash list](https://github.com/Shopify/flash-list) +- [Legend List](https://github.com/LegendApp/legend-list) - [React Query](https://tanstack.com/query/v4) - [Axios](https://axios-http.com/docs/intro) - [React Hook Form](https://react-hook-form.com/) diff --git a/docs/src/content/docs/overview.md b/docs/src/content/docs/overview.md index 39350040..3d6a7af5 100644 --- a/docs/src/content/docs/overview.md +++ b/docs/src/content/docs/overview.md @@ -89,7 +89,7 @@ We value the feedback and contributions of our users, and we encourage you to le - [Expo](https://docs.expo.io/) - [Expo Router](https://docs.expo.dev/router/introduction/) - [Nativewind](https://www.nativewind.dev/v4/overview) -- [Flash list](https://github.com/Shopify/flash-list) +- [Legend List](https://github.com/LegendApp/legend-list) - [React Query](https://tanstack.com/query/v4) - [Axios](https://axios-http.com/docs/intro) - [React Hook Form](https://react-hook-form.com/) diff --git a/package.json b/package.json index 01443205..fa3da87c 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "@expo/metro-runtime": "^4.0.1", "@gorhom/bottom-sheet": "^5.0.5", "@hookform/resolvers": "^3.9.0", - "@shopify/flash-list": "1.7.3", + "@legendapp/list": "^2.0.0", "@tanstack/react-query": "^5.52.1", "app-icon-badge": "^0.1.2", "axios": "^1.7.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 122e3a54..db2e555c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,9 +17,9 @@ importers: '@hookform/resolvers': specifier: ^3.9.0 version: 3.9.0(react-hook-form@7.53.0(react@18.3.1)) - '@shopify/flash-list': - specifier: 1.7.3 - version: 1.7.3(@babel/runtime@7.26.0)(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1) + '@legendapp/list': + specifier: ^2.0.0 + version: 2.0.0(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1) '@tanstack/react-query': specifier: ^5.52.1 version: 5.52.1(react@18.3.1) @@ -1544,6 +1544,12 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@legendapp/list@2.0.0': + resolution: {integrity: sha512-GOh1x9U0VE5zCcZ/sDyvCBKyvA4ZQMOOKipWFxHdlURYATC1gs9TLVrBAO3gENgG1b0VlllUIr7foxGFj/tHoA==} + peerDependencies: + react: '*' + react-native: '*' + '@motionone/animation@10.18.0': resolution: {integrity: sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==} @@ -1780,13 +1786,6 @@ packages: '@segment/loosely-validate-event@2.0.0': resolution: {integrity: sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==} - '@shopify/flash-list@1.7.3': - resolution: {integrity: sha512-RLhNptm02aqpqZvjj9pJPcU+EVYxOAJhPRCmDOaUbUP86+636w+plsbjpBPSYGvPZhPj56RtZ9FBlvolPeEmYA==} - peerDependencies: - '@babel/runtime': '*' - react: '*' - react-native: '*' - '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -4961,9 +4960,11 @@ packages: lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. lodash.isequal@4.5.0: resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. lodash.isplainobject@4.0.6: resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} @@ -6114,12 +6115,6 @@ packages: resolution: {integrity: sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==} engines: {node: '>= 4'} - recyclerlistview@4.2.1: - resolution: {integrity: sha512-NtVYjofwgUCt1rEsTp6jHQg/47TWjnO92TU2kTVgJ9wsc/ely4HnizHHa+f/dI7qaw4+zcSogElrLjhMltN2/g==} - peerDependencies: - react: '>= 15.2.1' - react-native: '>= 0.30.0' - redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -6900,9 +6895,6 @@ packages: esbuild: optional: true - ts-object-utils@0.0.5: - resolution: {integrity: sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA==} - tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -7082,6 +7074,11 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 + use-sync-external-store@1.5.0: + resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + utif2@4.1.0: resolution: {integrity: sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==} @@ -9352,6 +9349,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@legendapp/list@2.0.0(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1)': + dependencies: + react: 18.3.1 + react-native: 0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1) + use-sync-external-store: 1.5.0(react@18.3.1) + '@motionone/animation@10.18.0': dependencies: '@motionone/easing': 10.18.0 @@ -9702,14 +9705,6 @@ snapshots: component-type: 1.2.2 join-component: 1.1.0 - '@shopify/flash-list@1.7.3(@babel/runtime@7.26.0)(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.26.0 - react: 18.3.1 - react-native: 0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1) - recyclerlistview: 4.2.1(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1) - tslib: 2.8.1 - '@sinclair/typebox@0.27.8': {} '@sinonjs/commons@3.0.1': @@ -11428,7 +11423,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -11447,20 +11442,20 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -11471,14 +11466,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.3.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -11518,7 +11513,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -11547,7 +11542,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -14939,14 +14934,6 @@ snapshots: source-map: 0.6.1 tslib: 2.8.1 - recyclerlistview@4.2.1(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1): - dependencies: - lodash.debounce: 4.0.8 - prop-types: 15.8.1 - react: 18.3.1 - react-native: 0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1) - ts-object-utils: 0.0.5 - redent@3.0.0: dependencies: indent-string: 4.0.0 @@ -15754,8 +15741,6 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.0) - ts-object-utils@0.0.5: {} - tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -15918,6 +15903,10 @@ snapshots: dependencies: react: 18.3.1 + use-sync-external-store@1.5.0(react@18.3.1): + dependencies: + react: 18.3.1 + utif2@4.1.0: dependencies: pako: 1.0.11 diff --git a/src/app/(app)/index.tsx b/src/app/(app)/index.tsx index 9e69163e..692ec111 100644 --- a/src/app/(app)/index.tsx +++ b/src/app/(app)/index.tsx @@ -1,15 +1,21 @@ -import { FlashList } from '@shopify/flash-list'; +import { type LegendListRenderItemProps } from '@legendapp/list'; import React from 'react'; import type { Post } from '@/api'; import { usePosts } from '@/api'; import { Card } from '@/components/card'; -import { EmptyList, FocusAwareStatusBar, Text, View } from '@/components/ui'; +import { + EmptyList, + FocusAwareStatusBar, + List, + Text, + View, +} from '@/components/ui'; export default function Feed() { const { data, isPending, isError } = usePosts(); const renderItem = React.useCallback( - ({ item }: { item: Post }) => , + ({ item }: LegendListRenderItemProps) => , [] ); @@ -23,12 +29,16 @@ export default function Feed() { return ( - `item-${index}`} + keyExtractor={(item: Post, index: number) => + item.id?.toString() || `item-${index}` + } ListEmptyComponent={} estimatedItemSize={300} + recycleItems + maintainVisibleContentPosition /> ); diff --git a/src/components/ui/list.tsx b/src/components/ui/list.tsx index 68ebc724..edf21f72 100644 --- a/src/components/ui/list.tsx +++ b/src/components/ui/list.tsx @@ -1,4 +1,4 @@ -import { FlashList as NFlashList } from '@shopify/flash-list'; +import { LegendList } from '@legendapp/list'; import React from 'react'; import { ActivityIndicator, View } from 'react-native'; import Svg, { Circle, Path } from 'react-native-svg'; @@ -8,7 +8,7 @@ type Props = { isLoading: boolean; }; -export const List = NFlashList; +export const List = LegendList; export const EmptyList = React.memo(({ isLoading }: Props) => { return ( diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx index 2d82b166..d50d04b7 100644 --- a/src/components/ui/select.tsx +++ b/src/components/ui/select.tsx @@ -3,7 +3,7 @@ import { BottomSheetFlatList, type BottomSheetModal, } from '@gorhom/bottom-sheet'; -import { FlashList } from '@shopify/flash-list'; +import { LegendList } from '@legendapp/list'; import { useColorScheme } from 'nativewind'; import * as React from 'react'; import type { FieldValues } from 'react-hook-form'; @@ -56,7 +56,7 @@ const selectTv = tv({ }, }); -const List = Platform.OS === 'web' ? FlashList : BottomSheetFlatList; +const List = Platform.OS === 'web' ? LegendList : BottomSheetFlatList; export type OptionType = { label: string; value: string | number };