From 1e7efb13d190cf22d4bdcaf5bab8944647755620 Mon Sep 17 00:00:00 2001 From: liaoxuan Date: Mon, 18 Mar 2024 20:31:35 +0800 Subject: [PATCH] feat: optimize ui --- App.tsx | 15 +++--- app.json | 4 +- components/StyledTextInput.tsx | 2 +- components/StyledToast.tsx | 3 +- components/topic/ReplyItem.tsx | 18 +++---- components/topic/TopicInfo.tsx | 14 +++--- components/topic/TopicItem.tsx | 18 ++++--- package.json | 10 ++-- screens/CustomizeThemeScreen.tsx | 8 +-- screens/HomeScreen.tsx | 86 +++++++++++++++++--------------- screens/HotestTopicsScreen.tsx | 1 - screens/LoginScreen.tsx | 3 +- screens/MemberDetailScreen.tsx | 18 +++++-- screens/MyFollowingScreen.tsx | 39 +++++++-------- screens/NodeTopicsScreen.tsx | 9 +++- screens/NotificationsScreen.tsx | 47 ++++++++--------- screens/RecentTopicScreen.tsx | 2 +- screens/SearchScreen.tsx | 23 ++++++--- servicies/helper.ts | 2 +- utils/query.ts | 32 ++++++++++-- utils/tw.ts | 9 ++-- yarn.lock | 34 ++++++------- 22 files changed, 215 insertions(+), 182 deletions(-) diff --git a/App.tsx b/App.tsx index 5dff65a..70bf97f 100644 --- a/App.tsx +++ b/App.tsx @@ -5,7 +5,7 @@ import * as SplashScreen from 'expo-splash-screen' import { StatusBar } from 'expo-status-bar' import { Provider, useAtom, useAtomValue } from 'jotai' import { waitForAll } from 'jotai/utils' -import { ReactElement, ReactNode, Suspense, useMemo } from 'react' +import { ReactElement, ReactNode, Suspense } from 'react' import { LogBox } from 'react-native' import 'react-native-gesture-handler' import { SafeAreaProvider } from 'react-native-safe-area-context' @@ -88,19 +88,16 @@ function AppInitializer({ children }: { children: ReactNode }) { ]) ) - useMemo(() => { - tw.setColorScheme(colorScheme) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + useDeviceContext(tw, { + observeDeviceColorSchemeChanges: false, + initialColorScheme: colorScheme, + }) + k.node.all.useQuery() k.member.checkin.useQuery({ enabled: !!profile && enabledAutoCheckin, }) - k.node.all.useQuery() - - useDeviceContext(tw, { withDeviceColorScheme: false }) - return children as ReactElement } diff --git a/app.json b/app.json index 541d386..7e286e9 100644 --- a/app.json +++ b/app.json @@ -2,7 +2,7 @@ "expo": { "name": "V2Fun", "slug": "v2ex", - "version": "1.7.0", + "version": "1.7.1", "scheme": "v2fun", "jsEngine": "jsc", "icon": "./assets/icon.png", @@ -20,7 +20,7 @@ "ios": { "supportsTablet": true, "bundleIdentifier": "com.liaoliao666.v2ex", - "buildNumber": "1.7.0.1" + "buildNumber": "1.7.1.1" }, "android": { "adaptiveIcon": { diff --git a/components/StyledTextInput.tsx b/components/StyledTextInput.tsx index a9f8b69..381c73d 100644 --- a/components/StyledTextInput.tsx +++ b/components/StyledTextInput.tsx @@ -16,7 +16,7 @@ const StyledTextInput = forwardRef< ref={ref} autoCapitalize="none" placeholderTextColor={colors.default} - selectionColor={tw.color(`text-[${colors.primary}]`)} + selectionColor={colors.primary} {...props} style={tw.style( `bg-[${colors.base200}] h-9 px-3 rounded-lg text-[${colors.foreground}]`, diff --git a/components/StyledToast.tsx b/components/StyledToast.tsx index d6c1500..3f34d23 100644 --- a/components/StyledToast.tsx +++ b/components/StyledToast.tsx @@ -42,7 +42,8 @@ function getToastProps(props: ToastConfigParams) { style: tw`rounded-lg border-[${color}] bg-[${bgColor}] border border-solid border-l border-l-[${color}]`, contentContainerStyle: tw`overflow-hidden pl-0`, text1Style: tw.style( - `${fontSize.medium} font-semibold text-[${colors.foreground}]` + `${fontSize.medium} text-[${colors.foreground}]`, + props.text2 ? `font-semibold` : `font-normal` ), text2Style: tw`${fontSize.small} text-[${colors.default}]`, renderLeadingIcon: () => ( diff --git a/components/topic/ReplyItem.tsx b/components/topic/ReplyItem.tsx index f8e464e..4c05c1f 100644 --- a/components/topic/ReplyItem.tsx +++ b/components/topic/ReplyItem.tsx @@ -54,9 +54,7 @@ function ReplyItem({ inModalScreen?: boolean onLayout?: ViewProps['onLayout'] }) { - const [isParsing, setIsParsing] = useState( - store.get(enabledParseContentAtom)! - ) + const [isParsed, setIsParsed] = useState(store.get(enabledParseContentAtom)!) const { colors, fontSize } = useAtomValue(uiAtom) @@ -145,13 +143,13 @@ function ReplyItem({ reply.parsed_content && ( { - setIsParsing(!isParsing) + setIsParsed(!isParsed) }} > - {isParsing ? `显示原始回复` : `隐藏原始回复`} + {isParsed ? `显示原始回复` : `隐藏原始回复`} ), ])} @@ -161,7 +159,7 @@ function ReplyItem({ void children: ReactNode }) { - const [isParsing, setIsParsing] = useState( - store.get(enabledParseContentAtom)! - ) + const [isParsed, setIsParsed] = useState(store.get(enabledParseContentAtom)!) const hasParsedText = !!topic.parsed_content || topic.supplements?.some(o => !!o.parsed_content) @@ -86,13 +84,13 @@ export default function TopicInfo({ , hasParsedText && ( { - setIsParsing(!isParsing) + setIsParsed(!isParsed) }} > - {isParsing ? `显示原始内容` : `隐藏原始内容`} + {isParsed ? `显示原始内容` : `隐藏原始内容`} ), ])} @@ -136,7 +134,7 @@ export default function TopicInfo({ { - const replyCount = maxBy(data.pages, 'reply_count')?.reply_count || 0 + const isReaded = useIsMatchedQuery(query => { + if (query.queryHash === hashKey(k.topic.detail.getKey({ id: topic.id }))) { + const data = query.state.data as inferData + const replyCount = maxBy(data?.pages, 'reply_count')?.reply_count || 0 return replyCount >= topic.reply_count - }, - enabled: false, + } + return false }) + const { colors, fontSize } = useAtomValue(uiAtom) return ( - - Aa - + Aa JSX.Element ; value indicates the value represented by the mark, while active indicates wether a thumb is currently standing on the mark /> - - Aa - + Aa {renderSubtitle('浅色')} diff --git a/screens/HomeScreen.tsx b/screens/HomeScreen.tsx index 979aa27..814ab7c 100644 --- a/screens/HomeScreen.tsx +++ b/screens/HomeScreen.tsx @@ -1,5 +1,6 @@ import { Feather } from '@expo/vector-icons' import { DrawerActions } from '@react-navigation/native' +import { InfiniteData } from '@tanstack/react-query' import { useAtom, useAtomValue } from 'jotai' import { findIndex, uniqBy } from 'lodash-es' import { @@ -94,24 +95,24 @@ export default withQuerySuspense(HomeScreen, { function HomeScreen() { const colorScheme = useAtomValue(colorSchemeAtom) - const fontScale = useAtomValue(fontScaleAtom) - const tabs = useAtomValue(homeTabsAtom) + const [index, setIndex] = useAtom(homeTabIndexAtom) + const { colors, fontSize } = useAtomValue(uiAtom) const layout = useWindowDimensions() - const [index, setIndex] = useAtom(homeTabIndexAtom) - const headerHeight = useNavBarHeight() + TAB_BAR_HEIGHT + const [refs] = useState>>({}) + function handleInexChange(i: number, forceFetch = false) { const activeTab = tabs[i] const activeTabKey = activeTab.key const activeQueryKey: any = activeTab.type === 'node' ? k.node.topics.getKey({ name: activeTabKey }) - : activeTab.key === RECENT_TAB_KEY + : activeTabKey === RECENT_TAB_KEY ? k.topic.recent.getKey() : k.topic.tab.getKey({ tab: activeTabKey }) const query = queryClient.getQueryCache().find({ @@ -121,7 +122,17 @@ function HomeScreen() { if (query?.state.error) { errorResetMap[activeTabKey]?.() } else if (query?.getObserversCount() && (forceFetch || query?.isStale())) { - if (activeTab.type === 'node' || activeTab.key === RECENT_TAB_KEY) { + if (activeTab.type === 'node' || activeTabKey === RECENT_TAB_KEY) { + const pages = + (queryClient.getQueryData(activeQueryKey) as InfiniteData) + ?.pages?.length || 0 + + if (forceFetch || pages > 1) { + refs[activeTabKey]?.current?.scrollToOffset({ + offset: 0, + }) + } + queryClient.prefetchInfiniteQuery({ ...(activeTab.type === 'node' ? k.node.topics.getFetchOptions({ name: activeTabKey }) @@ -129,6 +140,12 @@ function HomeScreen() { pages: 1, }) } else { + if (forceFetch) { + refs[activeTabKey]?.current?.scrollToOffset({ + offset: 0, + }) + } + queryClient.prefetchQuery( k.topic.tab.getFetchOptions({ tab: activeTabKey }) ) @@ -138,10 +155,6 @@ function HomeScreen() { setIndex(i) } - const [refs] = useState>>({}) - - const { colors, fontSize } = useAtomValue(uiAtom) - return ( { - if (active) { - refs[route.key]?.current?.scrollToOffset({ - offset: 0, - }) - } handleInexChange( findIndex(tabs, { key: route.key }), active @@ -265,18 +273,17 @@ function HomeScreen() { const RecentTopics = memo( forwardRef(({ headerHeight }, ref) => { - const { - data, - refetch, - hasNextPage, - fetchNextPage, - isFetchingNextPage, - isFetching, - } = k.topic.recent.useSuspenseInfiniteQuery({ - refetchOnWindowFocus: () => isRefetchOnWindowFocus(RECENT_TAB_KEY), - }) - - const { isRefetchingByUser, refetchByUser } = useRefreshByUser(refetch) + const { data, hasNextPage, fetchNextPage, isFetchingNextPage, isFetching } = + k.topic.recent.useSuspenseInfiniteQuery({ + refetchOnWindowFocus: () => isRefetchOnWindowFocus(RECENT_TAB_KEY), + }) + + const { isRefetchingByUser, refetchByUser } = useRefreshByUser(() => + queryClient.prefetchInfiniteQuery({ + ...k.topic.recent.getFetchOptions(), + pages: 1, + }) + ) const renderItem: ListRenderItem = useCallback( ({ item }) => , @@ -385,19 +392,18 @@ const NodeTopics = memo( headerHeight: number } >(({ nodeName, headerHeight }, ref) => { - const { - data, - refetch, - hasNextPage, - fetchNextPage, - isFetchingNextPage, - isFetching, - } = k.node.topics.useSuspenseInfiniteQuery({ - variables: { name: nodeName }, - refetchOnWindowFocus: () => isRefetchOnWindowFocus(nodeName), - }) - - const { isRefetchingByUser, refetchByUser } = useRefreshByUser(refetch) + const { data, hasNextPage, fetchNextPage, isFetchingNextPage, isFetching } = + k.node.topics.useSuspenseInfiniteQuery({ + variables: { name: nodeName }, + refetchOnWindowFocus: () => isRefetchOnWindowFocus(nodeName), + }) + + const { isRefetchingByUser, refetchByUser } = useRefreshByUser(() => + queryClient.prefetchInfiniteQuery({ + ...k.node.topics.getFetchOptions({ name: nodeName }), + pages: 1, + }) + ) const renderItem: ListRenderItem = useCallback( ({ item }) => , diff --git a/screens/HotestTopicsScreen.tsx b/screens/HotestTopicsScreen.tsx index 9cfb36b..aa58560 100644 --- a/screens/HotestTopicsScreen.tsx +++ b/screens/HotestTopicsScreen.tsx @@ -204,7 +204,6 @@ function HotestTopics({ > - {(Platform.OS === 'android' || dayjs().isAfter('2024-03-03 12:00')) && ( + {(Platform.OS === 'android' || dayjs().isAfter('2024-03-19 12:00')) && ( { diff --git a/screens/MemberDetailScreen.tsx b/screens/MemberDetailScreen.tsx index 704c98a..fea66da 100644 --- a/screens/MemberDetailScreen.tsx +++ b/screens/MemberDetailScreen.tsx @@ -489,12 +489,17 @@ const MemberTopics = forwardRef< >(({ contentContainerStyle, onScroll, onScrollEnd }, ref) => { const { params } = useRoute>() - const { data, refetch, hasNextPage, fetchNextPage, isFetchingNextPage } = + const { data, hasNextPage, fetchNextPage, isFetchingNextPage } = k.member.topics.useSuspenseInfiniteQuery({ variables: { username: params.username }, }) - const { isRefetchingByUser, refetchByUser } = useRefreshByUser(refetch) + const { isRefetchingByUser, refetchByUser } = useRefreshByUser(() => + queryClient.prefetchInfiniteQuery({ + ...k.member.topics.getFetchOptions({ username: params.username }), + pages: 1, + }) + ) const renderItem: ListRenderItem = useCallback( ({ item }) => , @@ -555,12 +560,17 @@ const MemberReplies = forwardRef< >(({ contentContainerStyle, onScroll, onScrollEnd }, ref) => { const { params } = useRoute>() - const { data, refetch, hasNextPage, fetchNextPage, isFetchingNextPage } = + const { data, hasNextPage, fetchNextPage, isFetchingNextPage } = k.member.replies.useSuspenseInfiniteQuery({ variables: { username: params.username }, }) - const { isRefetchingByUser, refetchByUser } = useRefreshByUser(refetch) + const { isRefetchingByUser, refetchByUser } = useRefreshByUser(() => + queryClient.prefetchInfiniteQuery({ + ...k.member.replies.getFetchOptions({ username: params.username }), + pages: 1, + }) + ) const flatedData = useMemo( () => uniqBy(data.pages.map(page => page.list).flat(), 'id'), diff --git a/screens/MyFollowingScreen.tsx b/screens/MyFollowingScreen.tsx index 8923666..301a122 100644 --- a/screens/MyFollowingScreen.tsx +++ b/screens/MyFollowingScreen.tsx @@ -29,6 +29,7 @@ import TopicItem from '@/components/topic/TopicItem' import { colorSchemeAtom } from '@/jotai/themeAtom' import { uiAtom } from '@/jotai/uiAtom' import { Topic, k } from '@/servicies' +import { queryClient } from '@/utils/query' import tw from '@/utils/tw' import { useRefreshByUser } from '@/utils/useRefreshByUser' @@ -186,16 +187,15 @@ function MyFollowingScreen() { } function MyFollowing({ headerHeight }: { headerHeight: number }) { - const { - data, - refetch, - hasNextPage, - fetchNextPage, - isFetchingNextPage, - isFetching, - } = k.my.following.useSuspenseInfiniteQuery() + const { data, hasNextPage, fetchNextPage, isFetchingNextPage, isFetching } = + k.my.following.useSuspenseInfiniteQuery() - const { isRefetchingByUser, refetchByUser } = useRefreshByUser(refetch) + const { isRefetchingByUser, refetchByUser } = useRefreshByUser(() => + queryClient.prefetchInfiniteQuery({ + ...k.my.following.getFetchOptions(), + pages: 1, + }) + ) const renderItem: ListRenderItem = useCallback( ({ item }) => , @@ -251,18 +251,17 @@ function MemberTopics({ username: string headerHeight: number }) { - const { - data, - refetch, - hasNextPage, - fetchNextPage, - isFetchingNextPage, - isFetching, - } = k.member.topics.useSuspenseInfiniteQuery({ - variables: { username }, - }) + const { data, hasNextPage, fetchNextPage, isFetchingNextPage, isFetching } = + k.member.topics.useSuspenseInfiniteQuery({ + variables: { username }, + }) - const { isRefetchingByUser, refetchByUser } = useRefreshByUser(refetch) + const { isRefetchingByUser, refetchByUser } = useRefreshByUser(() => + queryClient.prefetchInfiniteQuery({ + ...k.member.topics.getFetchOptions({ username }), + pages: 1, + }) + ) const renderItem: ListRenderItem = useCallback( ({ item }) => , diff --git a/screens/NodeTopicsScreen.tsx b/screens/NodeTopicsScreen.tsx index 40cd8b6..61491b1 100644 --- a/screens/NodeTopicsScreen.tsx +++ b/screens/NodeTopicsScreen.tsx @@ -75,7 +75,7 @@ export default withQuerySuspense(NodeTopicsScreen, { function NodeTopicsScreen() { const { params } = useRoute>() - const { data, refetch, hasNextPage, fetchNextPage, isFetchingNextPage } = + const { data, hasNextPage, fetchNextPage, isFetchingNextPage } = k.node.topics.useSuspenseInfiniteQuery({ variables: { name: params.name }, }) @@ -84,7 +84,12 @@ function NodeTopicsScreen() { select: nodes => find(nodes, { name: params.name }), }) - const { isRefetchingByUser, refetchByUser } = useRefreshByUser(refetch) + const { isRefetchingByUser, refetchByUser } = useRefreshByUser(() => + queryClient.prefetchInfiniteQuery({ + ...k.node.topics.getFetchOptions({ name: params.name }), + pages: 1, + }) + ) const lastPage = last(data.pages)! diff --git a/screens/NotificationsScreen.tsx b/screens/NotificationsScreen.tsx index d0e54ec..ed7541d 100644 --- a/screens/NotificationsScreen.tsx +++ b/screens/NotificationsScreen.tsx @@ -52,33 +52,34 @@ export default withQuerySuspense(NotificationsScreen, { }) function NotificationsScreen() { - const { - data, - refetch, - hasNextPage, - fetchNextPage, - isFetchingNextPage, - isFetching, - } = k.notification.list.useSuspenseInfiniteQuery() + const { data, hasNextPage, fetchNextPage, isFetchingNextPage, isFetching } = + k.notification.list.useSuspenseInfiniteQuery() - const { isRefetchingByUser, refetchByUser } = useRefreshByUser(refetch) + const { isRefetchingByUser, refetchByUser } = useRefreshByUser(() => + queryClient.prefetchInfiniteQuery({ + ...k.notification.list.getFetchOptions(), + pages: 1, + }) + ) const [replyInfo, setReplyInfo] = useState(null) const profile = useAtomValue(profileAtom) - const handleReply = useCallback((notice: Notice) => { - setReplyInfo({ - topicId: notice.topic.id, - username: notice.member.username, - }) - }, []) - const renderItem: ListRenderItem = useCallback( ({ item }) => ( - + { + setReplyInfo({ + topicId: item.topic.id, + username: item.member.username, + }) + }} + /> ), - [handleReply] + [] ) const flatedData = useMemo( @@ -149,13 +150,7 @@ function NotificationsScreen() { } const NoticeItem = memo( - ({ - notice, - onReply, - }: { - notice: Notice - onReply: (notice: Notice) => void - }) => { + ({ notice, onReply }: { notice: Notice; onReply: () => void }) => { const { colors, fontSize } = useAtomValue(uiAtom) return ( @@ -215,7 +210,7 @@ const NoticeItem = memo( activeColor={colors.primary} size={15} icon={} - onPress={() => onReply(notice)} + onPress={onReply} /> )} diff --git a/screens/RecentTopicScreen.tsx b/screens/RecentTopicScreen.tsx index a2d1ffa..9022bb0 100644 --- a/screens/RecentTopicScreen.tsx +++ b/screens/RecentTopicScreen.tsx @@ -151,7 +151,7 @@ const RecentTopicItem = memo( { navigation.push('MemberDetail', { diff --git a/screens/SearchScreen.tsx b/screens/SearchScreen.tsx index 210110d..36eaf43 100644 --- a/screens/SearchScreen.tsx +++ b/screens/SearchScreen.tsx @@ -1,5 +1,6 @@ import { Ionicons } from '@expo/vector-icons' import { RouteProp, useRoute } from '@react-navigation/native' +import { hashKey } from '@tanstack/react-query' import dayjs from 'dayjs' import { useAtom, useAtomValue } from 'jotai' import { RESET } from 'jotai/utils' @@ -25,6 +26,7 @@ import { } from 'react-native' import { SafeAreaView } from 'react-native-safe-area-context' import WebView from 'react-native-webview' +import { inferData } from 'react-query-kit' import DebouncedPressable from '@/components/DebouncedPressable' import Empty from '@/components/Empty' @@ -49,6 +51,7 @@ import { navigation } from '@/navigation/navigationRef' import { Member, Node, Sov2exResult, k } from '@/servicies' import { RootStackParamList } from '@/types' import { confirm } from '@/utils/confirm' +import { useIsMatchedQuery } from '@/utils/query' import tw from '@/utils/tw' import { useRefreshByUser } from '@/utils/useRefreshByUser' @@ -182,7 +185,9 @@ export default function SearchScreen() { key={colorScheme} initialNumToRender={20} keyExtractor={item => - isString(item) ? `Node_${item}` : `${item.title}_${item.name}` + isString(item) + ? `History_${item}` + : `Node_${item.title}_${item.name}` } contentContainerStyle={{ paddingTop: navbarHeight, @@ -250,7 +255,7 @@ export default function SearchScreen() { )} > - 全部节点 + {trimedSearchText ? '节点' : '全部节点'} ) : null @@ -453,13 +458,15 @@ const HitItem = memo( content: string } }) => { - const { data: isReaded } = k.topic.detail.useInfiniteQuery({ - variables: { id: topic.id }, - select: data => { - const replyCount = maxBy(data.pages, 'reply_count')?.reply_count || 0 + const isReaded = useIsMatchedQuery(query => { + if ( + query.queryHash === hashKey(k.topic.detail.getKey({ id: topic.id })) + ) { + const data = query.state.data as inferData + const replyCount = maxBy(data?.pages, 'reply_count')?.reply_count || 0 return replyCount >= topic.reply_count - }, - enabled: false, + } + return false }) const { colors, fontSize } = useAtomValue(uiAtom) diff --git a/servicies/helper.ts b/servicies/helper.ts index b51b56d..f30bc95 100644 --- a/servicies/helper.ts +++ b/servicies/helper.ts @@ -398,7 +398,7 @@ export function parseRank($: CheerioAPI) { type Replacer = Parameters<(typeof String)['prototype']['replace']>[1] -const regex_common_imgurl = /\/.+\.(jpeg|jpg|gif|png|svg)$/ +const regex_common_imgurl = /\/.+\.(jpeg|jpg|gif|png|svg|webp)$/ function is_common_img_url(url: string) { // 常见的图片URL return url.match(regex_common_imgurl) != null diff --git a/utils/query.ts b/utils/query.ts index af39c65..a6577f0 100644 --- a/utils/query.ts +++ b/utils/query.ts @@ -1,7 +1,13 @@ import NetInfo from '@react-native-community/netinfo' -import { QueryClient, focusManager, onlineManager } from '@tanstack/react-query' -import { isArray, isObjectLike } from 'lodash-es' -import { useMemo } from 'react' +import { + Query, + QueryClient, + focusManager, + notifyManager, + onlineManager, +} from '@tanstack/react-query' +import { first, isArray, isObjectLike } from 'lodash-es' +import { useCallback, useMemo, useSyncExternalStore } from 'react' import { AppState, Platform } from 'react-native' import { InfiniteQueryHook, Middleware, getKey } from 'react-query-kit' @@ -31,6 +37,22 @@ if (Platform.OS !== 'web') { }) } +export const useIsMatchedQuery = (predicate: (query: Query) => boolean) => { + const queryCache = queryClient.getQueryCache() + const getSnapshot = () => + !!queryClient.getQueryCache().findAll({ predicate }).length + + return useSyncExternalStore( + useCallback( + onStoreChange => + queryCache.subscribe(notifyManager.batchCalls(onStoreChange)), + [queryCache] + ), + getSnapshot, + getSnapshot + ) +} + export const removeUnnecessaryPages: Middleware< InfiniteQueryHook > = useNext => options => { @@ -53,8 +75,8 @@ export const removeUnnecessaryPages: Middleware< ) { // only keep one page before mount query.setData({ - pages: [data.pages[0]], - pageParams: [data.pageParams[0]], + pages: [first(data.pages)], + pageParams: [first(data.pageParams)], }) } } diff --git a/utils/tw.ts b/utils/tw.ts index c88f065..030ff4e 100644 --- a/utils/tw.ts +++ b/utils/tw.ts @@ -1,8 +1,8 @@ -// lib/tailwind.js -import { create } from 'twrnc' +import { TailwindFn, create } from 'twrnc' -// create the customized version... -const tw = create(require('../tailwind.config.js')) // <- your path may differ +const tw = create(require('../tailwind.config.js')) as TailwindFn & { + setColorScheme: (theme: 'dark' | 'light') => void +} tw.color = utils => { const styleObj = tw.style(utils) @@ -11,5 +11,4 @@ tw.color = utils => { return typeof color === `string` ? color : undefined } -// ... and then this becomes the main function your app uses export default tw diff --git a/yarn.lock b/yarn.lock index 70913c8..7f4e4a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7485,20 +7485,20 @@ react-native-tab-view@^3.5.2: dependencies: use-latest-callback "^0.1.5" -react-native-toast-message@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/react-native-toast-message/-/react-native-toast-message-2.1.6.tgz#322827c66901fa22cb3db614c7383cc717f5bbe2" - integrity sha512-VctXuq20vmRa9AE13acaNZhrLcS3FaBS2zEevS3+vhBsnVZYG0FIlWIis9tVnpnNxUb3ART+BWtwQjzSttXTng== +react-native-toast-message@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/react-native-toast-message/-/react-native-toast-message-2.2.0.tgz#c53a4746b15616858a7d61c4386b92cbe9fbf911" + integrity sha512-AFti8VzUk6JvyGAlLm9/BknTNDXrrhqnUk7ak/pM7uCTxDPveAu2ekszU0on6vnUPFnG04H/QfYE2IlETqeaWw== -react-native-webview@13.6.4: - version "13.6.4" - resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-13.6.4.tgz#6ef66db9dd78b2a2ae1b4fe79e1e3597aa29186e" - integrity sha512-AdgmaMBHPcyERTvng9eSGgHX6AleyUlSusWAxngSOSdiYGgHW81T6C5A8j/ImJAF9oZg0bQDxp43Hu56tzENZQ== +react-native-webview@^13.8.1: + version "13.8.1" + resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-13.8.1.tgz#d0058c063e38241476049aaab2e5cc9f254d5480" + integrity sha512-7Jqm1WzWJrOWraBAXQfKtr/Uo5Jw/IJHzC40jYLwgV/eVGmLJ9BpGKw6QVw7wpRkjmTZ2Typ4B1aHJLJJQFslA== dependencies: escape-string-regexp "2.0.0" invariant "2.2.4" -react-native-youtube-iframe@^2.2.2: +react-native-youtube-iframe@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/react-native-youtube-iframe/-/react-native-youtube-iframe-2.3.0.tgz#40ca8e55db929b91bfa8e8d30e411658cbc304c5" integrity sha512-M+z63xwXVtS4dX3k8PbtHUUcWN+gRZt6J1EtPE7Y60BMOB979KjpkdrHqeR96or9pNR2W8K5tQhIkMXW2jwo7Q== @@ -7549,10 +7549,10 @@ react-native@0.73.4: ws "^6.2.2" yargs "^17.6.2" -react-query-kit@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/react-query-kit/-/react-query-kit-3.1.2.tgz#15e927b73851000bb873877f78db6ecc7d3cb48f" - integrity sha512-8f7YioN71sKIqcHn9lc3WV8eHM5L4hjyzJT3+RQEu7sfr/h9FD9rtsoe2PLIop4b+WJ4QqjZCBLERxfJfO/XjA== +react-query-kit@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/react-query-kit/-/react-query-kit-3.2.0.tgz#6b5e3f037c1aa839bd2d5d587a07b12d0a7a2d93" + integrity sha512-4EKF/XPt50rurdH0hPBjPinsFsPmsC6nvoMDCsyUjxJq+pdN+B8jiZ57aqshL6yhWhuPZrEpWOVKXhCFYEoG8Q== react-refresh@0.14.0, react-refresh@^0.14.0: version "0.14.0" @@ -8571,10 +8571,10 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" -twrnc@^3.6.4: - version "3.6.4" - resolved "https://registry.yarnpkg.com/twrnc/-/twrnc-3.6.4.tgz#95252421f460986289926d5ec6ae78d8c3f34dd3" - integrity sha512-4yw0TS65X6OelJFmc4aCRS8JWI4fIK26Z9nSUOIVMpv7Z/GeAc9BXSnZ7SkD95uOkgmz/gLDS7a4BK6GHOl5Xg== +twrnc@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/twrnc/-/twrnc-4.1.0.tgz#63c969cfa5f10abe9a5f9d0fcfd8dc89689e0056" + integrity sha512-tyB0d+MC82pjCF62hAZ4AHfYd13A80Va3VqxB6PcPcz9Xys6Mlf/iKaAmxsNm9v3X9K/0Aqv2vgnSRCbi2Ws5A== dependencies: tailwindcss ">=2.0.0"