diff --git a/.circleci/config.yml b/.circleci/config.yml index c4053c5f19..ad05234255 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2.1 executors: default: docker: - - image: cimg/node:20.19.0 + - image: cimg/node:22.15.0 working_directory: ~/react-native-paper commands: @@ -20,30 +20,17 @@ jobs: - attach_project - restore_cache: keys: - - dependencies-{{ checksum "package.json" }} + - dependencies-{{ checksum "yarn.lock" }} - dependencies- - - restore_cache: - keys: - - dependencies-example-{{ checksum "example/package.json" }} - - dependencies-example- - run: name: Install dependencies command: | - sudo corepack enable - yarn --cwd example --immutable - yarn --cwd docs --immutable yarn --immutable - save_cache: - key: dependencies-{{ checksum "package.json" }} + key: dependencies-{{ checksum "yarn.lock" }} paths: - node_modules - - save_cache: - key: dependencies-docs-{{ checksum "docs/package.json" }} - paths: - docs/node_modules - - save_cache: - key: dependencies-example-{{ checksum "example/package.json" }} - paths: - example/node_modules - persist_to_workspace: root: . diff --git a/example/package.json b/example/package.json index 36603ea4aa..992ead9c23 100644 --- a/example/package.json +++ b/example/package.json @@ -13,10 +13,10 @@ "dependencies": { "@react-native-async-storage/async-storage": "2.2.0", "@react-native-masked-view/masked-view": "0.3.2", - "@react-navigation/bottom-tabs": "^8.0.0-alpha.30", - "@react-navigation/drawer": "^8.0.0-alpha.31", - "@react-navigation/native": "^8.0.0-alpha.25", - "@react-navigation/native-stack": "^8.0.0-alpha.31", + "@react-navigation/bottom-tabs": "^8.0.0-alpha.33", + "@react-navigation/drawer": "^8.0.0-alpha.34", + "@react-navigation/native": "^8.0.0-alpha.28", + "@react-navigation/native-stack": "^8.0.0-alpha.34", "expo": "~56.0.0", "expo-crypto": "~56.0.3", "expo-dev-client": "~56.0.13", diff --git a/example/src/DrawerItems.tsx b/example/src/DrawerItems.tsx index f9df80433c..ea4627bb64 100644 --- a/example/src/DrawerItems.tsx +++ b/example/src/DrawerItems.tsx @@ -1,15 +1,8 @@ import * as React from 'react'; -import { - ColorValue, - I18nManager, - Platform, - StyleSheet, - View, -} from 'react-native'; +import { ColorValue, Platform, StyleSheet, View } from 'react-native'; import { DrawerContentScrollView } from '@react-navigation/drawer'; import Constants, { ExecutionEnvironment } from 'expo-constants'; -import * as Updates from 'expo-updates'; import { Badge, Button, @@ -124,16 +117,12 @@ function DrawerItems() { } = preferences; const _handleToggleRTL = () => { - if (expoGoExecution) { + if (!isWeb && expoGoExecution) { setShowRTLDialog(true); return; } toggleRTL(); - I18nManager.forceRTL(!isRTL); - if (isWeb) { - Updates.reloadAsync(); - } }; const _handleDismissRTLDialog = () => { @@ -206,16 +195,14 @@ function DrawerItems() { - {!isWeb && ( - - - RTL - - - + + + RTL + + - - )} + + diff --git a/example/src/ExampleList.tsx b/example/src/ExampleList.tsx index 7b874d4906..bdf5af7428 100644 --- a/example/src/ExampleList.tsx +++ b/example/src/ExampleList.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { FlatList } from 'react-native'; -import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; import { Divider, List, useTheme } from 'react-native-paper'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; @@ -49,102 +49,76 @@ import ThemingWithReactNavigation from './Examples/ThemingWithReactNavigation'; import ToggleButtonExample from './Examples/ToggleButtonExample'; import TooltipExample from './Examples/TooltipExample'; import TouchableRippleExample from './Examples/TouchableRippleExample'; -export const mainExamples: Record< - string, - React.ComponentType & { title: string } -> = { - animatedFab: AnimatedFABExample, - activityIndicator: ActivityIndicatorExample, - appbar: AppbarExample, - avatar: AvatarExample, - badge: BadgeExample, - banner: BannerExample, - bottomNavigationBarExample: BottomNavigationBarExample, - bottomNavigation: BottomNavigationExample, - button: ButtonExample, - card: CardExample, - checkbox: CheckboxExample, - checkboxItem: CheckboxItemExample, - chip: ChipExample, - dataTable: DataTableExample, - dialog: DialogExample, - divider: DividerExample, - fab: FABExample, - iconButton: IconButtonExample, - icon: IconExample, - listAccordion: ListAccordionExample, - listAccordionGroup: ListAccordionExampleGroup, - listSection: ListSectionExample, - listItem: ListItemExample, - menu: MenuExample, - progressbar: ProgressBarExample, - radio: RadioButtonExample, - radioGroup: RadioButtonGroupExample, - radioItem: RadioButtonItemExample, - searchbar: SearchbarExample, - segmentedButton: SegmentedButtonExample, - snackbar: SnackbarExample, - surface: SurfaceExample, - switch: SwitchExample, - text: TextExample, - textInput: TextInputExample, - toggleButton: ToggleButtonExample, - tooltipExample: TooltipExample, - touchableRipple: TouchableRippleExample, - theme: ThemeExample, - themingWithReactNavigation: ThemingWithReactNavigation, + +export const mainExamples = { + AnimatedFAB: AnimatedFABExample, + ActivityIndicator: ActivityIndicatorExample, + Appbar: AppbarExample, + Avatar: AvatarExample, + Badge: BadgeExample, + Banner: BannerExample, + BottomNavigationBarExample, + BottomNavigation: BottomNavigationExample, + Button: ButtonExample, + Card: CardExample, + Checkbox: CheckboxExample, + CheckboxItem: CheckboxItemExample, + Chip: ChipExample, + DataTable: DataTableExample, + Dialog: DialogExample, + Divider: DividerExample, + FAB: FABExample, + IconButton: IconButtonExample, + Icon: IconExample, + ListAccordion: ListAccordionExample, + ListAccordionGroup: ListAccordionExampleGroup, + ListSection: ListSectionExample, + ListItem: ListItemExample, + Menu: MenuExample, + Progressbar: ProgressBarExample, + Radio: RadioButtonExample, + RadioGroup: RadioButtonGroupExample, + RadioItem: RadioButtonItemExample, + Searchbar: SearchbarExample, + SegmentedButton: SegmentedButtonExample, + Snackbar: SnackbarExample, + Surface: SurfaceExample, + Switch: SwitchExample, + Text: TextExample, + TextInput: TextInputExample, + ToggleButton: ToggleButtonExample, + TooltipExample, + TouchableRipple: TouchableRippleExample, + Theme: ThemeExample, + ThemingWithReactNavigation, }; -export const nestedExamples: Record< - string, - React.ComponentType & { title: string } -> = { - themingWithReactNavigation: ThemingWithReactNavigation, - teamDetails: TeamDetails, - teamsList: TeamsList, - segmentedButtonRealCase: SegmentedButtonRealCase, - segmentedButtonMultiselectRealCase: SegmentedButtonMultiselectRealCase, +export const nestedExamples = { + ThemingWithReactNavigation, + TeamDetails, + TeamsList, + SegmentedButtonRealCase, + SegmentedButtonMultiselectRealCase, }; -export const examples: Record< - string, - React.ComponentType & { title: string } -> = { +export const examples = { ...mainExamples, ...nestedExamples, }; -type Props = { - navigation: NativeStackNavigationProp<{ [key: string]: undefined }>; -}; - -type Item = { - id: string; - data: (typeof mainExamples)[string]; -}; +type MainExampleId = keyof typeof mainExamples; -const data = Object.keys(mainExamples).map( - (id): Item => ({ id, data: mainExamples[id] }) -); +const data = (Object.keys(mainExamples) as MainExampleId[]).map((id) => ({ + id, + data: mainExamples[id], +})); -export default function ExampleList({ navigation }: Props) { - const keyExtractor = (item: { id: string }) => item.id; +export default function ExampleList() { + const navigation = useNavigation('ExampleList'); const { colors } = useTheme(); const safeArea = useSafeAreaInsets(); - const renderItem = ({ item }: { item: Item }) => { - const { data, id } = item; - - return ( - navigation.navigate(id)} - /> - ); - }; - return ( ( + { + // @ts-expect-error TypeScript can't call overloaded functions with union arguments. + // https://github.com/microsoft/TypeScript/issues/40803 + navigation.navigate(item.id); + }} + /> + )} + keyExtractor={({ id }) => id} data={data} /> ); diff --git a/example/src/Examples/AppbarExample.tsx b/example/src/Examples/AppbarExample.tsx index a8d07e581e..846dd61182 100644 --- a/example/src/Examples/AppbarExample.tsx +++ b/example/src/Examples/AppbarExample.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { Platform, StyleSheet, View } from 'react-native'; -import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; import { Appbar, FAB, @@ -17,16 +17,14 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'; import ScreenWrapper from '../ScreenWrapper'; -type Props = { - navigation: NativeStackNavigationProp<{}>; -}; - type AppbarModes = 'small' | 'medium' | 'large' | 'center-aligned'; const MORE_ICON = Platform.OS === 'ios' ? 'dots-horizontal' : 'dots-vertical'; const MEDIUM_FAB_HEIGHT = 56; -const AppbarExample = ({ navigation }: Props) => { +const AppbarExample = () => { + const navigation = useNavigation('Appbar'); + const [showLeftIcon, setShowLeftIcon] = React.useState(true); const [showSubtitle, setShowSubtitle] = React.useState(true); const [showSearchIcon, setShowSearchIcon] = React.useState(true); diff --git a/example/src/Examples/BottomNavigationBarExample.tsx b/example/src/Examples/BottomNavigationBarExample.tsx index 083d6172fb..9fbddf7f23 100644 --- a/example/src/Examples/BottomNavigationBarExample.tsx +++ b/example/src/Examples/BottomNavigationBarExample.tsx @@ -2,7 +2,10 @@ import React from 'react'; import { View, StyleSheet, Image } from 'react-native'; import Icon from '@react-native-vector-icons/material-design-icons'; -import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { + createBottomTabNavigator, + createBottomTabScreen, +} from '@react-navigation/bottom-tabs'; import { CommonActions, SFSymbol, @@ -10,8 +13,6 @@ import { } from '@react-navigation/native'; import { Text, BottomNavigation } from 'react-native-paper'; -const Tab = createBottomTabNavigator(); - function HomeScreen() { return ( @@ -28,106 +29,98 @@ function SettingsScreen() { ); } -export default function BottomNavigationBarExample() { - return ( - ( - { - const event = navigation.emit({ - type: 'tabPress', - target: route.key, - canPreventDefault: true, - }); +const BottomNavigationBarExample = createBottomTabNavigator({ + screenOptions: { + headerShown: false, + }, + tabBar: ({ navigation, state, descriptors }) => ( + { + const event = navigation.emit({ + type: 'tabPress', + target: route.key, + canPreventDefault: true, + }); - if (event.defaultPrevented) { - preventDefault(); - } else { - navigation.dispatch({ - ...CommonActions.navigate(route.name, route.params), - target: state.key, - }); - } - }} - renderIcon={({ route, focused, color }) => { - const tabBarIcon = descriptors[route.key].options.tabBarIcon; + if (event.defaultPrevented) { + preventDefault(); + } else { + // Custom tab bars must target the tab navigator state. + navigation.dispatch({ + ...CommonActions.navigate(route.name, route.params), + target: state.key, + }); + } + }} + renderIcon={({ route, focused, color }) => { + const tabBarIcon = descriptors[route.key].options.tabBarIcon; - const size = 24; - const icon = - typeof tabBarIcon === 'function' - ? tabBarIcon({ focused, color, size }) - : tabBarIcon; + const size = 24; + const icon = + typeof tabBarIcon === 'function' + ? tabBarIcon({ focused, color, size }) + : tabBarIcon; - if (icon == null) { - return null; - } + if (icon == null) { + return null; + } - if (React.isValidElement(icon)) { - return icon; - } + if (React.isValidElement(icon)) { + return icon; + } - if (typeof icon === 'object' && icon !== null && 'type' in icon) { - switch (icon.type) { - case 'sfSymbol': - return ( - - ); - case 'materialSymbol': - return ( - - ); - case 'image': - return ( - - ); - } - } + if (typeof icon === 'object' && icon !== null && 'type' in icon) { + switch (icon.type) { + case 'sfSymbol': + return ; + case 'materialSymbol': + return ( + + ); + case 'image': + return ( + + ); + } + } - throw new Error( - 'Tab bar icon is not a valid React element, SFSymbol, MaterialSymbol, or Image.' - ); - }} - getLabelText={({ route }) => descriptors[route.key].route.name} - /> - )} - > - { - return ; - }, - }} - /> - { - return ; - }, - }} - /> - - ); -} + throw new Error( + 'Tab bar icon is not a valid React element, SFSymbol, MaterialSymbol, or Image.' + ); + }} + getLabelText={({ route }) => descriptors[route.key].route.name} + /> + ), + screens: { + Home: createBottomTabScreen({ + screen: HomeScreen, + options: { + tabBarIcon: ({ color, size }) => { + return ; + }, + }, + }), + Settings: createBottomTabScreen({ + screen: SettingsScreen, + options: { + tabBarIcon: ({ color, size }) => { + return ; + }, + }, + }), + }, +}); -BottomNavigationBarExample.title = 'Bottom Navigation Bar'; +export default Object.assign(BottomNavigationBarExample, { + title: 'Bottom Navigation Bar', +}); const styles = StyleSheet.create({ container: { diff --git a/example/src/Examples/BottomNavigationExample.tsx b/example/src/Examples/BottomNavigationExample.tsx index e12bb58ad1..0c0fc8d4cc 100644 --- a/example/src/Examples/BottomNavigationExample.tsx +++ b/example/src/Examples/BottomNavigationExample.tsx @@ -8,7 +8,7 @@ import { View, } from 'react-native'; -import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; import { Appbar, BottomNavigation, @@ -21,10 +21,6 @@ import ScreenWrapper from '../ScreenWrapper'; type Route = { route: { key: string } }; -type Props = { - navigation: NativeStackNavigationProp<{}>; -}; - const MORE_ICON = Platform.OS === 'ios' ? 'dots-horizontal' : 'dots-vertical'; const PhotoGallery = ({ route }: Route) => { @@ -48,7 +44,9 @@ const PhotoGallery = ({ route }: Route) => { ); }; -const BottomNavigationExample = ({ navigation }: Props) => { +const BottomNavigationExample = () => { + const navigation = useNavigation('BottomNavigation'); + const insets = useSafeAreaInsets(); const [index, setIndex] = React.useState(0); const [menuVisible, setMenuVisible] = React.useState(false); diff --git a/example/src/Examples/MenuExample.tsx b/example/src/Examples/MenuExample.tsx index a263b7ee39..831e811574 100644 --- a/example/src/Examples/MenuExample.tsx +++ b/example/src/Examples/MenuExample.tsx @@ -6,7 +6,7 @@ import { View, } from 'react-native'; -import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; import { Appbar, Button, @@ -20,17 +20,15 @@ import ScreenWrapper from '../ScreenWrapper'; type ContextualMenuCoord = { x: number; y: number }; -type Props = { - navigation: NativeStackNavigationProp<{}>; -}; - type MenuVisibility = { [key: string]: boolean | undefined; }; const MORE_ICON = Platform.OS === 'ios' ? 'dots-horizontal' : 'dots-vertical'; -const MenuExample = ({ navigation }: Props) => { +const MenuExample = () => { + const navigation = useNavigation('Menu'); + const [visible, setVisible] = React.useState({}); const [contextualMenuCoord, setContextualMenuCoor] = React.useState({ x: 0, y: 0 }); diff --git a/example/src/Examples/SearchbarExample.tsx b/example/src/Examples/SearchbarExample.tsx index a293f2c85a..739002156b 100644 --- a/example/src/Examples/SearchbarExample.tsx +++ b/example/src/Examples/SearchbarExample.tsx @@ -1,8 +1,7 @@ import * as React from 'react'; import { Keyboard, StyleSheet } from 'react-native'; -import type { DrawerNavigationProp } from '@react-navigation/drawer'; -import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; import { Avatar, List, @@ -14,11 +13,9 @@ import { import ScreenWrapper from '../ScreenWrapper'; -type Props = { - navigation: NativeStackNavigationProp<{}>; -}; +const SearchExample = () => { + const navigation = useNavigation('Searchbar'); -const SearchExample = ({ navigation }: Props) => { const [isVisible, setIsVisible] = React.useState(false); const [searchQueries, setSearchQuery] = React.useState({ searchBarMode: '', @@ -194,7 +191,7 @@ const SearchExample = ({ navigation }: Props) => { value={searchQueries.clickableDrawer} onIconPress={() => { Keyboard.dismiss(); - (navigation as any as DrawerNavigationProp<{}>).openDrawer(); + navigation.openDrawer(); }} icon="menu" style={styles.searchbar} diff --git a/example/src/Examples/SegmentedButtonsExample.tsx b/example/src/Examples/SegmentedButtonsExample.tsx index 5bfe3ba8b5..d6f2d610a4 100644 --- a/example/src/Examples/SegmentedButtonsExample.tsx +++ b/example/src/Examples/SegmentedButtonsExample.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; import { List } from 'react-native-paper'; import { @@ -16,25 +16,23 @@ import { } from './SegmentedButtons'; import ScreenWrapper from '../ScreenWrapper'; -type Props = { - navigation: NativeStackNavigationProp<{ [key: string]: undefined }>; -}; +const SegmentedButtonExample = () => { + const navigation = useNavigation('SegmentedButton'); -const SegmentedButtonExample = ({ navigation }: Props) => { return ( navigation.navigate('segmentedButtonRealCase')} + onPress={() => navigation.navigate('SegmentedButtonRealCase')} right={(props) => } /> - navigation.navigate('segmentedButtonMultiselectRealCase') + navigation.navigate('SegmentedButtonMultiselectRealCase') } right={(props) => } /> diff --git a/example/src/Examples/TeamDetails.tsx b/example/src/Examples/TeamDetails.tsx index a4b1f41a0b..5970274f31 100644 --- a/example/src/Examples/TeamDetails.tsx +++ b/example/src/Examples/TeamDetails.tsx @@ -8,7 +8,7 @@ import { View, } from 'react-native'; -import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { useNavigation, useRoute } from '@react-navigation/native'; import { Appbar, BottomNavigation, @@ -37,20 +37,6 @@ type RoutesState = Array<{ getTestID?: string; }>; -type Route = { - route: { key: string }; - params: { - sourceColor: string; - headerTitle: string; - darkMode: boolean; - }; -}; - -type Props = { - navigation: NativeStackNavigationProp<{}>; - route: Route; -}; - type Item = { host: string; guest: string; @@ -177,12 +163,14 @@ const Results = () => { ); }; -const ThemeBasedOnSourceColor = ({ navigation, route }: Props) => { +const ThemeBasedOnSourceColor = () => { + const navigation = useNavigation('TeamDetails'); + const route = useRoute('TeamDetails'); + const insets = useSafeAreaInsets(); const [index, setIndex] = React.useState(0); - const { params } = route; - const { sourceColor, headerTitle, darkMode } = params; + const { sourceColor, headerTitle, darkMode } = route.params ?? {}; const [routes] = React.useState([ { diff --git a/example/src/Examples/TeamsList.tsx b/example/src/Examples/TeamsList.tsx index 69e07b93aa..98abd9cbbb 100644 --- a/example/src/Examples/TeamsList.tsx +++ b/example/src/Examples/TeamsList.tsx @@ -1,16 +1,15 @@ import * as React from 'react'; import { StyleSheet } from 'react-native'; -import type { ParamListBase } from '@react-navigation/native'; -import type { NativeStackScreenProps } from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; import { DataTable } from 'react-native-paper'; import { teamsList } from '../../utils'; import ScreenWrapper from '../ScreenWrapper'; -type Props = NativeStackScreenProps; +const TeamsList = () => { + const navigation = useNavigation('TeamsList'); -const TeamsList = ({ navigation }: Props) => { return ( @@ -25,10 +24,10 @@ const TeamsList = ({ navigation }: Props) => { - navigation.navigate('teamDetails', { + navigation.navigate('TeamDetails', { sourceColor: item.name.split(' ')[1].toLowerCase(), headerTitle: item.name, - darkMode: item.darkMode, + darkMode: item.darkMode ?? false, }) } > diff --git a/example/src/Examples/ThemeExample.tsx b/example/src/Examples/ThemeExample.tsx index 54d4e9ba41..39f033aa06 100644 --- a/example/src/Examples/ThemeExample.tsx +++ b/example/src/Examples/ThemeExample.tsx @@ -1,16 +1,14 @@ import * as React from 'react'; import { StyleSheet } from 'react-native'; -import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; import { List, PaperProvider, Banner } from 'react-native-paper'; import ScreenWrapper from '../ScreenWrapper'; -type Props = { - navigation: NativeStackNavigationProp<{ [key: string]: undefined }>; -}; +const ThemeExample = () => { + const navigation = useNavigation('Theme'); -const ThemeExample = ({ navigation }: Props) => { return ( @@ -23,7 +21,7 @@ const ThemeExample = ({ navigation }: Props) => { navigation.navigate('teamsList')} + onPress={() => navigation.navigate('TeamsList')} right={(props) => } /> diff --git a/example/src/Examples/ThemingWithReactNavigation.tsx b/example/src/Examples/ThemingWithReactNavigation.tsx index 633af0bd76..394640ae6c 100644 --- a/example/src/Examples/ThemingWithReactNavigation.tsx +++ b/example/src/Examples/ThemingWithReactNavigation.tsx @@ -4,15 +4,13 @@ import { View, StyleSheet, Platform } from 'react-native'; import Icon from '@react-native-vector-icons/material-design-icons'; import { createBottomTabNavigator, + createBottomTabScreen, type BottomTabNavigationOptions, } from '@react-navigation/bottom-tabs'; import { PlatformPressable } from '@react-navigation/elements'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { Text } from 'react-native-paper'; -const Stack = createNativeStackNavigator(); -const Tab = createBottomTabNavigator(); - function HomeScreen() { return ( @@ -29,72 +27,63 @@ function SettingsScreen() { ); } -const HomeTab = () => { - return ( - ( - - ), - }} - > - ( - { - android: { - type: 'materialSymbol', - name: 'home', - }, - ios: { - type: 'sfSymbol', - name: 'house', - }, - default: ({ color, size }) => { - return ; - }, - } - ), - }} - /> - ( - { - android: { - type: 'materialSymbol', - name: 'settings', - }, - ios: { - type: 'sfSymbol', - name: 'gear', - }, - default: ({ color, size }) => { - return ; - }, - } - ), - }} - /> - - ); -}; +const HomeTab = createBottomTabNavigator({ + screenOptions: { + headerShown: false, + tabBarButton: (props) => ( + + ), + }, + screens: { + ThemingHome: createBottomTabScreen({ + screen: HomeScreen, + options: { + tabBarIcon: Platform.select({ + android: { + type: 'materialSymbol', + name: 'home', + }, + ios: { + type: 'sfSymbol', + name: 'house', + }, + default: ({ color, size }) => { + return ; + }, + }), + }, + }), + ThemingSettings: createBottomTabScreen({ + screen: SettingsScreen, + options: { + tabBarIcon: Platform.select({ + android: { + type: 'materialSymbol', + name: 'settings', + }, + ios: { + type: 'sfSymbol', + name: 'gear', + }, + default: ({ color, size }) => { + return ; + }, + }), + }, + }), + }, +}); -function ThemingWithReactNavigation() { - return ( - - - - ); -} +const ThemingWithReactNavigation = Object.assign( + createNativeStackNavigator({ + screens: { + 'React Navigation': HomeTab, + }, + }), + { + title: 'Theming With React Navigation', + } +); const styles = StyleSheet.create({ container: { @@ -104,6 +93,4 @@ const styles = StyleSheet.create({ }, }); -ThemingWithReactNavigation.title = 'Theming With React Navigation'; - export default ThemingWithReactNavigation; diff --git a/example/src/Examples/TooltipExample.tsx b/example/src/Examples/TooltipExample.tsx index d499892e31..ebe86e74f2 100644 --- a/example/src/Examples/TooltipExample.tsx +++ b/example/src/Examples/TooltipExample.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { Platform, StyleSheet, View, Image } from 'react-native'; -import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; import { Appbar, Avatar, @@ -18,10 +18,6 @@ import { import { isWeb } from '../../utils'; import ScreenWrapper from '../ScreenWrapper'; -type Props = { - navigation: NativeStackNavigationProp<{}>; -}; - const MORE_ICON = Platform.OS === 'ios' ? 'dots-horizontal' : 'dots-vertical'; const DURATION_MEDIUM = 1500; @@ -41,7 +37,9 @@ const formOfTransport = [ }, ]; -const TooltipExample = ({ navigation }: Props) => { +const TooltipExample = () => { + const navigation = useNavigation('TooltipExample'); + const [textAlign, setTextAlign] = React.useState('bold'); React.useLayoutEffect(() => { navigation.setOptions({ diff --git a/example/src/RootNavigator.tsx b/example/src/RootNavigator.tsx index dcdbd73359..7e0876dcd0 100644 --- a/example/src/RootNavigator.tsx +++ b/example/src/RootNavigator.tsx @@ -1,62 +1,90 @@ import * as React from 'react'; import { Platform, StyleSheet, View } from 'react-native'; -import type { DrawerNavigationProp } from '@react-navigation/drawer'; -import { createNativeStackNavigator } from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; +import { + createNativeStackNavigator, + createNativeStackScreen, + type NativeStackHeaderProps, +} from '@react-navigation/native-stack'; import { Appbar } from 'react-native-paper'; import ExampleList, { examples } from './ExampleList'; -const Stack = createNativeStackNavigator(); +const { TeamDetails, ...examplesWithoutParams } = examples; + +type ExampleRouteName = keyof typeof examplesWithoutParams; + +const fromEntries = ( + entries: Array<[Key, Value]> +) => Object.fromEntries(entries) as Record; + +function Header({ navigation, route, options, back }: NativeStackHeaderProps) { + const drawerNavigation = useNavigation('Home'); -export default function Root() { return ( - - ({ - header: ({ navigation, route, options, back }) => ( - - {back ? ( - navigation.goBack()} /> - ) : (navigation as any).openDrawer ? ( - - (navigation as any as DrawerNavigationProp<{}>).openDrawer() - } - /> - ) : null} - - - ), - })} - > - + {back ? ( + navigation.goBack()} /> + ) : ( + drawerNavigation.openDrawer()} /> - {(Object.keys(examples) as Array).map((id) => { - return ( - - ); - })} - - + )} + + ); } +const Root = createNativeStackNavigator({ + layout: ({ children }) => {children}, + screenOptions: { + header: (props) =>
, + }, + screens: { + ExampleList: createNativeStackScreen({ + screen: ExampleList, + options: { + title: 'Examples', + }, + linking: '', + }), + ...fromEntries( + ( + Object.entries(examplesWithoutParams) as [ + ExampleRouteName, + (typeof examplesWithoutParams)[ExampleRouteName] + ][] + ).map(([id, screen]) => [ + id, + createNativeStackScreen({ + screen: screen, + options: { + title: screen.title, + headerShown: id !== 'ThemingWithReactNavigation', + }, + }), + ]) + ), + TeamDetails: createNativeStackScreen({ + screen: TeamDetails, + options: { + title: TeamDetails.title, + }, + linking: { + path: 'team-details/:sourceColor?/:headerTitle?/:darkMode?', + parse: { + darkMode: (value) => value === 'true', + }, + }, + }), + }, +}); + +export default Root; + const styles = StyleSheet.create({ stackWrapper: { flex: 1, diff --git a/example/src/index.native.tsx b/example/src/index.native.tsx deleted file mode 100644 index 23b734fe4d..0000000000 --- a/example/src/index.native.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import * as React from 'react'; -import { I18nManager } from 'react-native'; - -import AsyncStorage from '@react-native-async-storage/async-storage'; -import { createDrawerNavigator } from '@react-navigation/drawer'; -import { InitialState, NavigationContainer } from '@react-navigation/native'; -import { useFonts } from 'expo-font'; -import { useKeepAwake } from 'expo-keep-awake'; -import { StatusBar } from 'expo-status-bar'; -import * as Updates from 'expo-updates'; -import { - PaperProvider, - DarkTheme, - LightTheme, - DynamicLightTheme, - DynamicDarkTheme, -} from 'react-native-paper'; -import { SafeAreaInsetsContext } from 'react-native-safe-area-context'; - -import DrawerItems from './DrawerItems'; -import { PreferencesContext } from './PreferencesContext'; -import App from './RootNavigator'; -import { dynamicThemeSupported } from '../utils'; -import { - CombinedDefaultTheme, - CombinedDarkTheme, - createConfiguredFontTheme, - createConfiguredFontNavigationTheme, -} from '../utils/themes'; - -const PERSISTENCE_KEY = 'NAVIGATION_STATE'; -const PREFERENCES_KEY = 'APP_PREFERENCES'; - -const Drawer = createDrawerNavigator<{ Home: undefined }>(); - -export default function PaperExample() { - useKeepAwake(); - - const [fontsLoaded] = useFonts({ - Abel: require('../assets/fonts/Abel-Regular.ttf'), - }); - - const [isReady, setIsReady] = React.useState(false); - const [initialState, setInitialState] = React.useState< - InitialState | undefined - >(); - - const [shouldUseDynamicTheme, setShouldUseDynamicTheme] = - React.useState(true); - const [isDarkMode, setIsDarkMode] = React.useState(false); - const [rtl, setRtl] = React.useState( - I18nManager.getConstants().isRTL - ); - const [collapsed, setCollapsed] = React.useState(false); - const [customFontLoaded, setCustomFont] = React.useState(false); - const [rippleEffectEnabled, setRippleEffectEnabled] = React.useState(true); - - const theme = React.useMemo(() => { - if (dynamicThemeSupported && shouldUseDynamicTheme) { - return isDarkMode ? DynamicDarkTheme : DynamicLightTheme; - } - - return isDarkMode ? DarkTheme : LightTheme; - }, [isDarkMode, shouldUseDynamicTheme]); - - React.useEffect(() => { - const restoreState = async () => { - try { - const savedStateString = await AsyncStorage.getItem(PERSISTENCE_KEY); - const state = JSON.parse(savedStateString || ''); - - setInitialState(state); - } catch (e) { - // ignore error - } finally { - setIsReady(true); - } - }; - - if (!isReady) { - restoreState(); - } - }, [isReady]); - - React.useEffect(() => { - const restorePrefs = async () => { - try { - const prefString = await AsyncStorage.getItem(PREFERENCES_KEY); - const preferences = JSON.parse(prefString || ''); - - if (preferences) { - setIsDarkMode(preferences.theme === 'dark'); - - if (typeof preferences.rtl === 'boolean') { - setRtl(preferences.rtl); - } - } - } catch (e) { - // ignore error - } - }; - - restorePrefs(); - }, []); - - React.useEffect(() => { - const savePrefs = async () => { - try { - await AsyncStorage.setItem( - PREFERENCES_KEY, - JSON.stringify({ - theme: isDarkMode ? 'dark' : 'light', - rtl, - }) - ); - } catch (e) { - // ignore error - } - - if (I18nManager.getConstants().isRTL !== rtl) { - I18nManager.forceRTL(rtl); - Updates.reloadAsync(); - } - }; - - savePrefs(); - }, [rtl, isDarkMode]); - - const preferences = React.useMemo( - () => ({ - toggleShouldUseDynamicTheme: () => - setShouldUseDynamicTheme((oldValue) => !oldValue), - toggleTheme: () => setIsDarkMode((oldValue) => !oldValue), - toggleRtl: () => setRtl((rtl) => !rtl), - toggleCollapsed: () => setCollapsed(!collapsed), - toggleCustomFont: () => setCustomFont(!customFontLoaded), - toggleRippleEffect: () => setRippleEffectEnabled(!rippleEffectEnabled), - customFontLoaded, - rippleEffectEnabled, - collapsed, - rtl, - theme, - shouldUseDynamicTheme: shouldUseDynamicTheme, - }), - [ - rtl, - theme, - collapsed, - customFontLoaded, - shouldUseDynamicTheme, - rippleEffectEnabled, - ] - ); - - if (!isReady && !fontsLoaded) { - return null; - } - - const combinedTheme = isDarkMode ? CombinedDarkTheme : CombinedDefaultTheme; - const configuredFontTheme = createConfiguredFontTheme(combinedTheme); - const configuredFontNavigationTheme = - createConfiguredFontNavigationTheme(combinedTheme); - - return ( - - - - AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state)) - } - > - - {(insets) => { - const { left, right } = insets || { left: 0, right: 0 }; - const collapsedDrawerWidth = 100 + Math.max(left, right); - return ( - } - > - - - ); - }} - - - - - - ); -} diff --git a/example/src/index.tsx b/example/src/index.tsx index df291baf3f..688297b059 100644 --- a/example/src/index.tsx +++ b/example/src/index.tsx @@ -1,16 +1,30 @@ import * as React from 'react'; +import { I18nManager, Platform } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; -import { createDrawerNavigator } from '@react-navigation/drawer'; -import { InitialState, NavigationContainer } from '@react-navigation/native'; +import { + createDrawerNavigator, + createDrawerScreen, +} from '@react-navigation/drawer'; +import { createStaticNavigation } from '@react-navigation/native'; import { useFonts } from 'expo-font'; import { useKeepAwake } from 'expo-keep-awake'; -import { PaperProvider, DarkTheme, LightTheme } from 'react-native-paper'; -import { SafeAreaInsetsContext } from 'react-native-safe-area-context'; +import * as SplashScreen from 'expo-splash-screen'; +import { StatusBar } from 'expo-status-bar'; +import * as Updates from 'expo-updates'; +import { + PaperProvider, + DarkTheme, + LightTheme, + DynamicLightTheme, + DynamicDarkTheme, +} from 'react-native-paper'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; import DrawerItems from './DrawerItems'; import { PreferencesContext } from './PreferencesContext'; import App from './RootNavigator'; +import { dynamicThemeSupported } from '../utils'; import { CombinedDarkTheme, CombinedDefaultTheme, @@ -20,9 +34,53 @@ import { const PERSISTENCE_KEY = 'NAVIGATION_STATE'; const PREFERENCES_KEY = 'APP_PREFERENCES'; -const noop = () => {}; -const Drawer = createDrawerNavigator<{ Home: undefined }>(); +const getInitialRtl = () => { + if (Platform.OS === 'web' && typeof document !== 'undefined') { + return document.documentElement.dir === 'rtl'; + } + + return I18nManager.getConstants().isRTL; +}; + +const Drawer = createDrawerNavigator({ + screens: { + Home: createDrawerScreen({ + screen: App, + options: { + headerShown: false, + }, + linking: { + path: '', + initialRouteName: 'ExampleList', + }, + }), + }, +}).with(({ Navigator }) => { + const preferences = React.useContext(PreferencesContext); + const insets = useSafeAreaInsets(); + const { left, right } = insets || { left: 0, right: 0 }; + const collapsedDrawerWidth = 100 + Math.max(left, right); + + return ( + } + /> + ); +}); + +const Navigation = createStaticNavigation(Drawer); + +type RootDrawerType = typeof Drawer; + +declare module '@react-navigation/core' { + interface RootNavigator extends RootDrawerType {} +} export default function PaperExample() { useKeepAwake(); @@ -32,38 +90,25 @@ export default function PaperExample() { }); const [isReady, setIsReady] = React.useState(false); - const [initialState, setInitialState] = React.useState< - InitialState | undefined - >(); + const [shouldUseDynamicTheme, setShouldUseDynamicTheme] = + React.useState(true); const [isDarkMode, setIsDarkMode] = React.useState(false); + const [rtl, setRtl] = React.useState(getInitialRtl); const [collapsed, setCollapsed] = React.useState(false); const [customFontLoaded, setCustomFont] = React.useState(false); const [rippleEffectEnabled, setRippleEffectEnabled] = React.useState(true); - const theme = React.useMemo( - () => (isDarkMode ? DarkTheme : LightTheme), - [isDarkMode] - ); - - React.useEffect(() => { - const restoreState = async () => { - try { - const savedStateString = await AsyncStorage.getItem(PERSISTENCE_KEY); - const state = JSON.parse(savedStateString || ''); + const theme = + dynamicThemeSupported && shouldUseDynamicTheme + ? isDarkMode + ? DynamicDarkTheme + : DynamicLightTheme + : isDarkMode + ? DarkTheme + : LightTheme; - setInitialState(state); - } catch (e) { - // ignore error - } finally { - setIsReady(true); - } - }; - - if (!isReady) { - restoreState(); - } - }, [isReady]); + const direction = rtl ? 'rtl' : 'ltr'; React.useEffect(() => { const restorePrefs = async () => { @@ -73,9 +118,15 @@ export default function PaperExample() { if (preferences) { setIsDarkMode(preferences.theme === 'dark'); + + if (typeof preferences.rtl === 'boolean') { + setRtl(preferences.rtl); + } } } catch (e) { // ignore error + } finally { + setIsReady(true); } }; @@ -84,41 +135,65 @@ export default function PaperExample() { React.useEffect(() => { const savePrefs = async () => { + if (!isReady) { + return; + } + try { await AsyncStorage.setItem( PREFERENCES_KEY, JSON.stringify({ theme: isDarkMode ? 'dark' : 'light', + rtl, }) ); } catch (e) { // ignore error } + + if (Platform.OS === 'web' && typeof document !== 'undefined') { + document.documentElement.dir = direction; + } + + if (I18nManager.getConstants().isRTL !== rtl) { + I18nManager.forceRTL(rtl); + + if (Platform.OS !== 'web') { + Updates.reloadAsync(); + } + } }; savePrefs(); - }, [isDarkMode]); + }, [direction, isDarkMode, isReady, rtl]); const preferences = React.useMemo( () => ({ + toggleShouldUseDynamicTheme: () => + setShouldUseDynamicTheme((oldValue) => !oldValue), toggleTheme: () => setIsDarkMode((oldValue) => !oldValue), - toggleCollapsed: () => setCollapsed(!collapsed), - toggleCustomFont: () => setCustomFont(!customFontLoaded), - toggleRippleEffect: () => setRippleEffectEnabled(!rippleEffectEnabled), + toggleRtl: () => setRtl((oldValue) => !oldValue), + toggleCollapsed: () => setCollapsed((oldValue) => !oldValue), + toggleCustomFont: () => setCustomFont((oldValue) => !oldValue), + toggleRippleEffect: () => setRippleEffectEnabled((oldValue) => !oldValue), + customFontLoaded, + rippleEffectEnabled, + shouldUseDynamicTheme, + theme, + collapsed, + rtl, + }), + [ + rtl, theme, collapsed, customFontLoaded, + shouldUseDynamicTheme, rippleEffectEnabled, - // noop for web, specified to avoid type errors - toggleRtl: noop, - toggleShouldUseDynamicTheme: noop, - rtl: false, - shouldUseDynamicTheme: false, - }), - [theme, collapsed, customFontLoaded, rippleEffectEnabled] + ] ); - if (!isReady && !fontsLoaded) { + if (!isReady || !fontsLoaded) { return null; } @@ -126,45 +201,41 @@ export default function PaperExample() { const configuredFontTheme = createConfiguredFontTheme(combinedTheme); const configuredFontNavigationTheme = createConfiguredFontNavigationTheme(combinedTheme); + const paperTheme = customFontLoaded ? configuredFontTheme : theme; + const navigationTheme = customFontLoaded + ? configuredFontNavigationTheme + : combinedTheme; return ( - - AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state)) - } - > - - {(insets) => { - const { left, right } = insets || { left: 0, right: 0 }; - const collapsedDrawerWidth = 100 + Math.max(left, right); - return ( - } - > - - + - + }, + async restore() { + const state = await AsyncStorage.getItem(PERSISTENCE_KEY); + + return state ? JSON.parse(state) : undefined; + }, + }} + onReady={() => { + SplashScreen.hideAsync(); + }} + /> + {Platform.OS !== 'web' ? ( + + ) : null} ); diff --git a/package.json b/package.json index 6a8cffabb2..34ae7e3d9e 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "@react-native-vector-icons/material-design-icons": "^12.0.0", "@react-native/babel-preset": "^0.85.3", "@react-native/jest-preset": "^0.85.3", - "@react-navigation/native": "^8.0.0-alpha.25", + "@react-navigation/native": "^8.0.0-alpha.28", "@release-it/conventional-changelog": "^1.1.0", "@testing-library/jest-native": "^5.4.1", "@testing-library/react-native": "11.5.0", diff --git a/yarn.lock b/yarn.lock index bc18b34207..63b967951e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5325,24 +5325,24 @@ __metadata: languageName: node linkType: hard -"@react-navigation/bottom-tabs@npm:^8.0.0-alpha.30": - version: 8.0.0-alpha.30 - resolution: "@react-navigation/bottom-tabs@npm:8.0.0-alpha.30" +"@react-navigation/bottom-tabs@npm:^8.0.0-alpha.33": + version: 8.0.0-alpha.33 + resolution: "@react-navigation/bottom-tabs@npm:8.0.0-alpha.33" dependencies: - "@react-navigation/elements": "npm:^3.0.0-alpha.28" + "@react-navigation/elements": "npm:^3.0.0-alpha.31" peerDependencies: - "@react-navigation/native": ^8.0.0-alpha.25 + "@react-navigation/native": ^8.0.0-alpha.28 react: ">= 19.2.0" react-native: "*" react-native-safe-area-context: ">= 5.5.0" react-native-screens: ">= 4.25.0" - checksum: 10c0/e0c3399f1fc160667fe2c37b2a8ae72d65bdcd0fc2ea0009d3d1eeccaf4336f1c97db21af02f29b07d0ba9bd278a341ac8c6c3ab4b93d709eb0432e6fa0c40ff + checksum: 10c0/94a2f3c6ec0f266d0bd53066069bdcfc8e59563530cec4519bb34aca6f248e79295d367fb1a63299658081411fb4b93718927a04d7d41fa399c3b6fbdf874f26 languageName: node linkType: hard -"@react-navigation/core@npm:^8.0.0-alpha.16": - version: 8.0.0-alpha.16 - resolution: "@react-navigation/core@npm:8.0.0-alpha.16" +"@react-navigation/core@npm:^8.0.0-alpha.19": + version: 8.0.0-alpha.19 + resolution: "@react-navigation/core@npm:8.0.0-alpha.19" dependencies: "@react-navigation/routers": "npm:^8.0.0-alpha.10" escape-string-regexp: "npm:^5.0.0" @@ -5354,19 +5354,19 @@ __metadata: use-sync-external-store: "npm:^1.6.0" peerDependencies: react: ">= 19.2.0" - checksum: 10c0/f376844b9d506200e74c53834d3246c935c932c335a764cedc5724bdf566d174bb0f8247f995447480ca0bad2a4d72e9d33506aa7b58076a69711171eef12928 + checksum: 10c0/bb0ce7e49b063cf423effcc8b668c5b73ad83ea61abcdd807aebe04cf1ededfe4042e13a1ba92fae09d8c1ed5f4fcc8faf51e8603c8a9f7a710d66be051b5ec0 languageName: node linkType: hard -"@react-navigation/drawer@npm:^8.0.0-alpha.31": - version: 8.0.0-alpha.31 - resolution: "@react-navigation/drawer@npm:8.0.0-alpha.31" +"@react-navigation/drawer@npm:^8.0.0-alpha.34": + version: 8.0.0-alpha.34 + resolution: "@react-navigation/drawer@npm:8.0.0-alpha.34" dependencies: - "@react-navigation/elements": "npm:^3.0.0-alpha.28" + "@react-navigation/elements": "npm:^3.0.0-alpha.31" react-native-drawer-layout: "npm:^5.0.0-alpha.10" use-latest-callback: "npm:^0.3.3" peerDependencies: - "@react-navigation/native": ^8.0.0-alpha.25 + "@react-navigation/native": ^8.0.0-alpha.28 react: ">= 19.2.0" react-native: "*" react-native-gesture-handler: ">= 2.0.0" @@ -5374,49 +5374,49 @@ __metadata: react-native-safe-area-context: ">= 5.5.0" react-native-screens: ">= 4.25.0" react-native-worklets: ">= 0.4.0" - checksum: 10c0/4d7e6bb701475e918f50a78f5c88032bdc159ef7c1f7b3d7c33e3ba07be943a93a872d8dc32118d14bb04e9225df78eeff0bafb9c37c673c614af10ede1c734d + checksum: 10c0/0e1b6a0b34b06c4d42e7495619a4871a7cee4f2fa798259607f4399c7c8716ff0d6a1a0da0025d1a83b6c7097f252ac67b136a1d7de533ce35d0d61f11e8b0c2 languageName: node linkType: hard -"@react-navigation/elements@npm:^3.0.0-alpha.28": - version: 3.0.0-alpha.28 - resolution: "@react-navigation/elements@npm:3.0.0-alpha.28" +"@react-navigation/elements@npm:^3.0.0-alpha.31": + version: 3.0.0-alpha.31 + resolution: "@react-navigation/elements@npm:3.0.0-alpha.31" dependencies: sf-symbols-typescript: "npm:^2.2.0" use-latest-callback: "npm:^0.3.3" use-sync-external-store: "npm:^1.6.0" peerDependencies: "@callstack/liquid-glass": ">= 0.6.0" - "@react-navigation/native": ^8.0.0-alpha.25 + "@react-navigation/native": ^8.0.0-alpha.28 react: ">= 19.2.0" react-native: "*" react-native-safe-area-context: ">= 5.5.0" react-native-screens: ">= 4.25.0" - checksum: 10c0/b08b7d37fcdb08b3baa63491460576d808839b294d979c157ac7c26f5eab94901bba1d493cdfe83f65aab1995d2c08aaa4ac69edc425437b910878ec59a907b6 + checksum: 10c0/a3a4433fba4cb15a7cb043fdd6033ee09c834e03a34b91f2fdee02527f5f19951ff2841f583dc569a7b0b44f5030c6313cd5ebc10a2743700a33fc404bcdc906 languageName: node linkType: hard -"@react-navigation/native-stack@npm:^8.0.0-alpha.31": - version: 8.0.0-alpha.31 - resolution: "@react-navigation/native-stack@npm:8.0.0-alpha.31" +"@react-navigation/native-stack@npm:^8.0.0-alpha.34": + version: 8.0.0-alpha.34 + resolution: "@react-navigation/native-stack@npm:8.0.0-alpha.34" dependencies: - "@react-navigation/elements": "npm:^3.0.0-alpha.28" + "@react-navigation/elements": "npm:^3.0.0-alpha.31" warn-once: "npm:^0.1.1" peerDependencies: - "@react-navigation/native": ^8.0.0-alpha.25 + "@react-navigation/native": ^8.0.0-alpha.28 react: ">= 19.2.0" react-native: "*" react-native-safe-area-context: ">= 5.5.0" react-native-screens: ">= 4.25.0" - checksum: 10c0/4595225a7ad5b94563486ac331a3c6d1c9045591c9a258f7bafed6e140d1ba1b6a43bd03b2f0cc348baa160e30769879638f90baf256d106a045c9efa6b9bc52 + checksum: 10c0/322de7b9e0ad1ddcec95d96c793807a11b8d20cb0c008d70863d8401d97b8620277c39c6f93eac65e854f583d1d078542979cfa52ce30b6e188c13eaa001b842 languageName: node linkType: hard -"@react-navigation/native@npm:^8.0.0-alpha.25": - version: 8.0.0-alpha.25 - resolution: "@react-navigation/native@npm:8.0.0-alpha.25" +"@react-navigation/native@npm:^8.0.0-alpha.28": + version: 8.0.0-alpha.28 + resolution: "@react-navigation/native@npm:8.0.0-alpha.28" dependencies: - "@react-navigation/core": "npm:^8.0.0-alpha.16" + "@react-navigation/core": "npm:^8.0.0-alpha.19" escape-string-regexp: "npm:^5.0.0" fast-deep-equal: "npm:^3.1.3" nanoid: "npm:^5.1.7" @@ -5425,7 +5425,7 @@ __metadata: peerDependencies: react: ">= 19.2.0" react-native: "*" - checksum: 10c0/146d0c8b752b8bafb975892f2efb103ff75b58462adc9ae0bd54a9c2a286a878fdcb32fb9008252f56304387608e43e5f4d6e2924ea3797b2141648ed315412e + checksum: 10c0/2221366589b1fce39578c7dc25e420902585ea0eed02214deca7795a407f56dc607a97bc0e346e4e01502fe181269d3075380b3c7af75a8b70f73e0ddb5585c4 languageName: node linkType: hard @@ -20557,10 +20557,10 @@ __metadata: "@babel/core": "npm:^7.29.0" "@react-native-async-storage/async-storage": "npm:2.2.0" "@react-native-masked-view/masked-view": "npm:0.3.2" - "@react-navigation/bottom-tabs": "npm:^8.0.0-alpha.30" - "@react-navigation/drawer": "npm:^8.0.0-alpha.31" - "@react-navigation/native": "npm:^8.0.0-alpha.25" - "@react-navigation/native-stack": "npm:^8.0.0-alpha.31" + "@react-navigation/bottom-tabs": "npm:^8.0.0-alpha.33" + "@react-navigation/drawer": "npm:^8.0.0-alpha.34" + "@react-navigation/native": "npm:^8.0.0-alpha.28" + "@react-navigation/native-stack": "npm:^8.0.0-alpha.34" babel-preset-expo: "npm:~56.0.0" expo: "npm:~56.0.0" expo-crypto: "npm:~56.0.3" @@ -20597,7 +20597,7 @@ __metadata: "@react-native-vector-icons/material-design-icons": "npm:^12.0.0" "@react-native/babel-preset": "npm:^0.85.3" "@react-native/jest-preset": "npm:^0.85.3" - "@react-navigation/native": "npm:^8.0.0-alpha.25" + "@react-navigation/native": "npm:^8.0.0-alpha.28" "@release-it/conventional-changelog": "npm:^1.1.0" "@testing-library/jest-native": "npm:^5.4.1" "@testing-library/react-native": "npm:11.5.0"