diff --git a/example/src/Screens/AuthFlow.tsx b/example/src/Screens/AuthFlow.tsx
deleted file mode 100644
index 45d145334a..0000000000
--- a/example/src/Screens/AuthFlow.tsx
+++ /dev/null
@@ -1,206 +0,0 @@
-import * as React from 'react';
-import { View, TextInput, ActivityIndicator, StyleSheet } from 'react-native';
-import { Title, Button } from 'react-native-paper';
-import { useTheme, ParamListBase } from '@react-navigation/native';
-import {
- createStackNavigator,
- StackScreenProps,
-} from '@react-navigation/stack';
-import { HeaderBackButton } from '@react-navigation/elements';
-
-type AuthStackParams = {
- Splash: undefined;
- Home: undefined;
- SignIn: undefined;
- PostSignOut: undefined;
-};
-
-const AUTH_CONTEXT_ERROR =
- 'Authentication context not found. Have your wrapped your components with AuthContext.Consumer?';
-
-const AuthContext = React.createContext<{
- signIn: () => void;
- signOut: () => void;
-}>({
- signIn: () => {
- throw new Error(AUTH_CONTEXT_ERROR);
- },
- signOut: () => {
- throw new Error(AUTH_CONTEXT_ERROR);
- },
-});
-
-const SplashScreen = () => {
- const { colors } = useTheme();
-
- return (
-
-
-
- );
-};
-
-const SignInScreen = () => {
- const { signIn } = React.useContext(AuthContext);
- const { colors } = useTheme();
-
- return (
-
-
-
-
-
- );
-};
-
-const HomeScreen = () => {
- const { signOut } = React.useContext(AuthContext);
-
- return (
-
- Signed in successfully 🎉
-
-
- );
-};
-
-const SimpleStack = createStackNavigator();
-
-type State = {
- isLoading: boolean;
- isSignout: boolean;
- userToken: undefined | string;
-};
-
-type Action =
- | { type: 'RESTORE_TOKEN'; token: undefined | string }
- | { type: 'SIGN_IN'; token: string }
- | { type: 'SIGN_OUT' };
-
-export default function SimpleStackScreen({
- navigation,
-}: StackScreenProps) {
- const [state, dispatch] = React.useReducer>(
- (prevState, action) => {
- switch (action.type) {
- case 'RESTORE_TOKEN':
- return {
- ...prevState,
- userToken: action.token,
- isLoading: false,
- };
- case 'SIGN_IN':
- return {
- ...prevState,
- isSignout: false,
- userToken: action.token,
- };
- case 'SIGN_OUT':
- return {
- ...prevState,
- isSignout: true,
- userToken: undefined,
- };
- }
- },
- {
- isLoading: true,
- isSignout: false,
- userToken: undefined,
- }
- );
-
- React.useEffect(() => {
- const timer = setTimeout(() => {
- dispatch({ type: 'RESTORE_TOKEN', token: undefined });
- }, 1000);
-
- return () => clearTimeout(timer);
- }, []);
-
- React.useLayoutEffect(() => {
- navigation.setOptions({
- headerShown: false,
- });
- }, [navigation]);
-
- const authContext = React.useMemo(
- () => ({
- signIn: () => dispatch({ type: 'SIGN_IN', token: 'dummy-auth-token' }),
- signOut: () => dispatch({ type: 'SIGN_OUT' }),
- }),
- []
- );
-
- if (state.isLoading) {
- return ;
- }
-
- return (
-
- (
- navigation.goBack()} />
- ),
- }}
- >
- {state.userToken === undefined ? (
-
- ) : (
-
- )}
-
-
- );
-}
-
-const styles = StyleSheet.create({
- content: {
- flex: 1,
- padding: 16,
- justifyContent: 'center',
- },
- input: {
- margin: 8,
- padding: 10,
- borderRadius: 3,
- borderWidth: StyleSheet.hairlineWidth,
- borderColor: 'rgba(0, 0, 0, 0.08)',
- },
- button: {
- margin: 8,
- },
- text: {
- textAlign: 'center',
- margin: 8,
- },
-});
diff --git a/example/src/Screens/BottomTabs.tsx b/example/src/Screens/BottomTabs.tsx
deleted file mode 100644
index 748d853a89..0000000000
--- a/example/src/Screens/BottomTabs.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import * as React from 'react';
-import { Platform } from 'react-native';
-import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
-import {
- getFocusedRouteNameFromRoute,
- ParamListBase,
- NavigatorScreenParams,
-} from '@react-navigation/native';
-import type { StackScreenProps } from '@react-navigation/stack';
-import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
-import { HeaderBackButton } from '@react-navigation/elements';
-import TouchableBounce from '../Shared/TouchableBounce';
-import Albums from '../Shared/Albums';
-import Contacts from '../Shared/Contacts';
-import Chat from '../Shared/Chat';
-import SimpleStackScreen, { SimpleStackParams } from './SimpleStack';
-
-const getTabBarIcon = (name: string) => ({
- color,
- size,
-}: {
- color: string;
- size: number;
-}) => ;
-
-type BottomTabParams = {
- TabStack: NavigatorScreenParams;
- TabAlbums: undefined;
- TabContacts: undefined;
- TabChat: undefined;
-};
-
-const BottomTabs = createBottomTabNavigator();
-
-export default function BottomTabsScreen({
- navigation,
- route,
-}: StackScreenProps) {
- const routeName = getFocusedRouteNameFromRoute(route) ?? 'Article';
-
- React.useLayoutEffect(() => {
- navigation.setOptions({
- headerShown: false,
- title: routeName,
- });
- }, [navigation, routeName]);
-
- return (
- (
-
- ),
- tabBarButton:
- Platform.OS === 'web'
- ? undefined
- : (props) => ,
- }}
- >
-
-
-
-
-
- );
-}
diff --git a/example/src/Screens/DynamicTabs.tsx b/example/src/Screens/DynamicTabs.tsx
deleted file mode 100644
index d9813715f4..0000000000
--- a/example/src/Screens/DynamicTabs.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import * as React from 'react';
-import { View, StyleSheet } from 'react-native';
-import { Title, Button } from 'react-native-paper';
-import Feather from 'react-native-vector-icons/Feather';
-import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
-
-type BottomTabParams = {
- [key: string]: undefined;
-};
-
-const BottomTabs = createBottomTabNavigator();
-
-export default function BottomTabsScreen() {
- const [tabs, setTabs] = React.useState([0, 1]);
-
- return (
-
- {tabs.map((i) => (
- (
-
- ),
- }}
- >
- {() => (
-
- Tab {i}
-
-
-
- )}
-
- ))}
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- alignItems: 'center',
- justifyContent: 'center',
- },
-});
diff --git a/example/src/Screens/LinkComponent.tsx b/example/src/Screens/LinkComponent.tsx
deleted file mode 100644
index a1bd0a548c..0000000000
--- a/example/src/Screens/LinkComponent.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-import * as React from 'react';
-import { View, StyleSheet, ScrollView, Platform } from 'react-native';
-import { Button } from 'react-native-paper';
-import {
- Link,
- StackActions,
- ParamListBase,
- useLinkProps,
-} from '@react-navigation/native';
-import {
- createStackNavigator,
- StackScreenProps,
-} from '@react-navigation/stack';
-import Article from '../Shared/Article';
-import Albums from '../Shared/Albums';
-
-type SimpleStackParams = {
- Article: { author: string };
- Albums: undefined;
-};
-
-const scrollEnabled = Platform.select({ web: true, default: false });
-
-const LinkButton = ({
- to,
- ...rest
-}: React.ComponentProps & { to: string }) => {
- const props = useLinkProps({ to });
-
- return ;
-};
-
-const ArticleScreen = ({
- navigation,
- route,
-}: StackScreenProps) => {
- return (
-
-
-
- Go to /link-component/music
-
-
- Replace with /link-component/music
-
-
- Go to /link-component/music
-
-
-
-
-
- );
-};
-
-const AlbumsScreen = ({ navigation }: StackScreenProps) => {
- return (
-
-
-
- Go to /link-component/article
-
-
- Go to /link-component/article
-
-
-
-
-
- );
-};
-
-const SimpleStack = createStackNavigator();
-
-type Props = Partial> &
- StackScreenProps;
-
-export default function SimpleStackScreen({ navigation, ...rest }: Props) {
- React.useLayoutEffect(() => {
- navigation.setOptions({
- headerShown: false,
- });
- }, [navigation]);
-
- return (
-
- ({
- title: `Article by ${route.params.author}`,
- })}
- initialParams={{ author: 'Gandalf' }}
- />
-
-
- );
-}
-
-const styles = StyleSheet.create({
- buttons: {
- padding: 8,
- },
- button: {
- margin: 8,
- },
-});
diff --git a/example/src/Screens/MasterDetail.tsx b/example/src/Screens/MasterDetail.tsx
deleted file mode 100644
index a1af18d4d7..0000000000
--- a/example/src/Screens/MasterDetail.tsx
+++ /dev/null
@@ -1,149 +0,0 @@
-import * as React from 'react';
-import { Dimensions, ScaledSize } from 'react-native';
-import { Appbar } from 'react-native-paper';
-import {
- useTheme,
- useNavigation,
- ParamListBase,
-} from '@react-navigation/native';
-import {
- createDrawerNavigator,
- DrawerScreenProps,
- DrawerContent,
- DrawerContentComponentProps,
-} from '@react-navigation/drawer';
-import type { StackScreenProps } from '@react-navigation/stack';
-import Article from '../Shared/Article';
-import Albums from '../Shared/Albums';
-import NewsFeed from '../Shared/NewsFeed';
-
-type DrawerParams = {
- Article: undefined;
- NewsFeed: undefined;
- Albums: undefined;
-};
-
-const useIsLargeScreen = () => {
- const [dimensions, setDimensions] = React.useState(Dimensions.get('window'));
-
- React.useEffect(() => {
- const onDimensionsChange = ({ window }: { window: ScaledSize }) => {
- setDimensions(window);
- };
-
- Dimensions.addEventListener('change', onDimensionsChange);
-
- return () => Dimensions.removeEventListener('change', onDimensionsChange);
- }, []);
-
- return dimensions.width > 414;
-};
-
-const Header = ({
- onGoBack,
- title,
-}: {
- onGoBack: () => void;
- title: string;
-}) => {
- const { colors } = useTheme();
- const isLargeScreen = useIsLargeScreen();
-
- return (
-
- {isLargeScreen ? null : }
-
-
- );
-};
-
-const ArticleScreen = ({
- navigation,
-}: DrawerScreenProps) => {
- return (
- <>
- navigation.toggleDrawer()} />
-
- >
- );
-};
-
-const NewsFeedScreen = ({
- navigation,
-}: DrawerScreenProps) => {
- return (
- <>
- navigation.toggleDrawer()} />
-
- >
- );
-};
-
-const AlbumsScreen = ({
- navigation,
-}: DrawerScreenProps) => {
- return (
- <>
- navigation.toggleDrawer()} />
-
- >
- );
-};
-
-const CustomDrawerContent = (props: DrawerContentComponentProps) => {
- const { colors } = useTheme();
- const navigation = useNavigation();
-
- return (
- <>
-
- navigation.goBack()} />
-
-
-
- >
- );
-};
-
-const Drawer = createDrawerNavigator();
-
-type Props = Partial> &
- StackScreenProps;
-
-export default function DrawerScreen({ navigation, ...rest }: Props) {
- React.useLayoutEffect(() => {
- navigation.setOptions({
- headerShown: false,
- gestureEnabled: false,
- });
- }, [navigation]);
-
- const isLargeScreen = useIsLargeScreen();
-
- return (
- }
- screenOptions={{
- headerShown: false,
- drawerType: isLargeScreen ? 'permanent' : 'back',
- drawerStyle: isLargeScreen ? null : { width: '100%' },
- drawerContentContainerStyle: { paddingTop: 4 },
- overlayColor: 'transparent',
- }}
- {...rest}
- >
-
-
-
-
- );
-}
diff --git a/example/src/Screens/MaterialBottomTabs.tsx b/example/src/Screens/MaterialBottomTabs.tsx
deleted file mode 100644
index ff073a67a6..0000000000
--- a/example/src/Screens/MaterialBottomTabs.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import * as React from 'react';
-import { StyleSheet } from 'react-native';
-import type { NavigatorScreenParams } from '@react-navigation/native';
-import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';
-import Albums from '../Shared/Albums';
-import Contacts from '../Shared/Contacts';
-import Chat from '../Shared/Chat';
-import SimpleStackScreen, { SimpleStackParams } from './SimpleStack';
-
-type MaterialBottomTabParams = {
- TabStack: NavigatorScreenParams;
- TabAlbums: undefined;
- TabContacts: undefined;
- TabChat: undefined;
-};
-
-const MaterialBottomTabs = createMaterialBottomTabNavigator();
-
-export default function MaterialBottomTabsScreen() {
- return (
-
-
- {(props) => (
-
- )}
-
-
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- tabBar: {
- backgroundColor: 'white',
- },
-});
diff --git a/example/src/Screens/MaterialTopTabs.tsx b/example/src/Screens/MaterialTopTabs.tsx
deleted file mode 100644
index 9e7343a48b..0000000000
--- a/example/src/Screens/MaterialTopTabs.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import * as React from 'react';
-import type { ParamListBase } from '@react-navigation/native';
-import type { StackScreenProps } from '@react-navigation/stack';
-import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
-import Albums from '../Shared/Albums';
-import Contacts from '../Shared/Contacts';
-import Chat from '../Shared/Chat';
-
-type MaterialTopTabParams = {
- Albums: undefined;
- Contacts: undefined;
- Chat: undefined;
-};
-
-const MaterialTopTabs = createMaterialTopTabNavigator();
-
-export default function MaterialTopTabsScreen({
- navigation,
-}: StackScreenProps) {
- React.useLayoutEffect(() => {
- navigation.setOptions({
- cardStyle: { flex: 1 },
- });
- }, [navigation]);
-
- return (
-
-
-
-
-
- );
-}
diff --git a/example/src/Screens/MixedHeaderMode.tsx b/example/src/Screens/MixedHeaderMode.tsx
deleted file mode 100644
index 687a2826e5..0000000000
--- a/example/src/Screens/MixedHeaderMode.tsx
+++ /dev/null
@@ -1,159 +0,0 @@
-import * as React from 'react';
-import { View, Platform, StyleSheet, ScrollView } from 'react-native';
-import { Button } from 'react-native-paper';
-import type { ParamListBase } from '@react-navigation/native';
-import {
- createStackNavigator,
- StackScreenProps,
- TransitionPresets,
- HeaderStyleInterpolators,
-} from '@react-navigation/stack';
-import Article from '../Shared/Article';
-import Albums from '../Shared/Albums';
-import NewsFeed from '../Shared/NewsFeed';
-
-export type SimpleStackParams = {
- Article: { author: string } | undefined;
- NewsFeed: { date: number };
- Albums: undefined;
-};
-
-const scrollEnabled = Platform.select({ web: true, default: false });
-
-const ArticleScreen = ({
- navigation,
- route,
-}: StackScreenProps) => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-const NewsFeedScreen = ({
- route,
- navigation,
-}: StackScreenProps) => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-const AlbumsScreen = ({
- navigation,
-}: StackScreenProps) => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-const SimpleStack = createStackNavigator();
-
-export default function SimpleStackScreen({
- navigation,
-}: StackScreenProps) {
- React.useLayoutEffect(() => {
- navigation.setOptions({
- headerShown: false,
- });
- }, [navigation]);
-
- return (
-
- ({
- title: `Article by ${route.params?.author ?? 'Unknown'}`,
- })}
- initialParams={{ author: 'Gandalf' }}
- />
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- buttons: {
- flexDirection: 'row',
- padding: 8,
- },
- button: {
- margin: 8,
- },
-});
diff --git a/example/src/Screens/ModalStack.tsx b/example/src/Screens/ModalStack.tsx
deleted file mode 100644
index 279d6a1e26..0000000000
--- a/example/src/Screens/ModalStack.tsx
+++ /dev/null
@@ -1,111 +0,0 @@
-import * as React from 'react';
-import { View, StyleSheet, ScrollView, Platform } from 'react-native';
-import { Button } from 'react-native-paper';
-import type { ParamListBase } from '@react-navigation/native';
-import {
- createStackNavigator,
- StackScreenProps,
-} from '@react-navigation/stack';
-import Article from '../Shared/Article';
-import Albums from '../Shared/Albums';
-
-type ModalStackParams = {
- Article: { author: string };
- Albums: undefined;
-};
-
-const scrollEnabled = Platform.select({ web: true, default: false });
-
-const ArticleScreen = ({
- navigation,
- route,
-}: StackScreenProps) => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-const AlbumsScreen = ({ navigation }: StackScreenProps) => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-const ModalStack = createStackNavigator();
-
-type Props = StackScreenProps;
-
-export default function ModalStackScreen({ navigation }: Props) {
- React.useLayoutEffect(() => {
- navigation.setOptions({
- headerShown: false,
- });
- }, [navigation]);
-
- return (
-
- ({
- title: `Article by ${route.params.author}`,
- })}
- initialParams={{ author: 'Gandalf' }}
- />
-
-
- );
-}
-
-const styles = StyleSheet.create({
- buttons: {
- flexDirection: 'row',
- padding: 8,
- },
- button: {
- margin: 8,
- },
-});
diff --git a/example/src/Screens/NotFound.tsx b/example/src/Screens/NotFound.tsx
deleted file mode 100644
index 144c40d1a3..0000000000
--- a/example/src/Screens/NotFound.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import * as React from 'react';
-import { StyleSheet, Text, View } from 'react-native';
-import { Button } from 'react-native-paper';
-import type { StackScreenProps } from '@react-navigation/stack';
-
-const NotFoundScreen = ({
- route,
- navigation,
-}: StackScreenProps<{ Home: undefined }>) => {
- return (
-
- 404 Not Found ({route.path})
-
-
- );
-};
-
-export default NotFoundScreen;
-
-const styles = StyleSheet.create({
- title: {
- fontSize: 36,
- },
- container: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- padding: 8,
- },
- button: {
- margin: 24,
- },
-});
diff --git a/example/src/Screens/PreventRemove.tsx b/example/src/Screens/PreventRemove.tsx
deleted file mode 100644
index c14a8660d7..0000000000
--- a/example/src/Screens/PreventRemove.tsx
+++ /dev/null
@@ -1,180 +0,0 @@
-import * as React from 'react';
-import {
- Alert,
- View,
- TextInput,
- ScrollView,
- StyleSheet,
- Platform,
-} from 'react-native';
-import { Button } from 'react-native-paper';
-import {
- useTheme,
- CommonActions,
- ParamListBase,
- NavigationAction,
-} from '@react-navigation/native';
-import {
- createStackNavigator,
- StackScreenProps,
-} from '@react-navigation/stack';
-import Article from '../Shared/Article';
-
-type PreventRemoveParams = {
- Article: { author: string };
- Input: undefined;
-};
-
-const scrollEnabled = Platform.select({ web: true, default: false });
-
-const ArticleScreen = ({
- navigation,
- route,
-}: StackScreenProps) => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-const InputScreen = ({
- navigation,
-}: StackScreenProps) => {
- const [text, setText] = React.useState('');
- const { colors } = useTheme();
-
- const hasUnsavedChanges = Boolean(text);
-
- React.useEffect(
- () =>
- navigation.addListener('beforeRemove', (e) => {
- const action: NavigationAction & { payload?: { confirmed?: boolean } } =
- e.data.action;
-
- if (!hasUnsavedChanges || action.payload?.confirmed) {
- return;
- }
-
- e.preventDefault();
-
- if (Platform.OS === 'web') {
- const discard = confirm(
- 'You have unsaved changes. Discard them and leave the screen?'
- );
-
- if (discard) {
- navigation.dispatch(action);
- }
- } else {
- Alert.alert(
- 'Discard changes?',
- 'You have unsaved changes. Discard them and leave the screen?',
- [
- { text: "Don't leave", style: 'cancel', onPress: () => {} },
- {
- text: 'Discard',
- style: 'destructive',
- onPress: () => navigation.dispatch(action),
- },
- ]
- );
- }
- }),
- [hasUnsavedChanges, navigation]
- );
-
- return (
-
-
-
-
-
- );
-};
-
-const SimpleStack = createStackNavigator();
-
-type Props = StackScreenProps;
-
-export default function SimpleStackScreen({ navigation }: Props) {
- React.useLayoutEffect(() => {
- navigation.setOptions({
- headerShown: false,
- });
- }, [navigation]);
-
- return (
-
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- content: {
- flex: 1,
- padding: 16,
- },
- input: {
- margin: 8,
- padding: 10,
- borderRadius: 3,
- borderWidth: StyleSheet.hairlineWidth,
- borderColor: 'rgba(0, 0, 0, 0.08)',
- },
- buttons: {
- flexDirection: 'row',
- padding: 8,
- },
- button: {
- margin: 8,
- },
-});
diff --git a/example/src/Screens/SimpleStack.tsx b/example/src/Screens/SimpleStack.tsx
deleted file mode 100644
index 841ae6bb0b..0000000000
--- a/example/src/Screens/SimpleStack.tsx
+++ /dev/null
@@ -1,151 +0,0 @@
-import * as React from 'react';
-import { View, Platform, StyleSheet, ScrollView } from 'react-native';
-import { Button } from 'react-native-paper';
-import type { ParamListBase } from '@react-navigation/native';
-import {
- createStackNavigator,
- StackNavigationOptions,
- StackScreenProps,
-} from '@react-navigation/stack';
-import Article from '../Shared/Article';
-import Albums from '../Shared/Albums';
-import NewsFeed from '../Shared/NewsFeed';
-
-export type SimpleStackParams = {
- Article: { author: string } | undefined;
- NewsFeed: { date: number };
- Albums: undefined;
-};
-
-const scrollEnabled = Platform.select({ web: true, default: false });
-
-const ArticleScreen = ({
- navigation,
- route,
-}: StackScreenProps) => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-const NewsFeedScreen = ({
- route,
- navigation,
-}: StackScreenProps) => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-const AlbumsScreen = ({
- navigation,
-}: StackScreenProps) => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-const SimpleStack = createStackNavigator();
-
-export default function SimpleStackScreen({
- navigation,
- screenOptions,
-}: StackScreenProps & {
- screenOptions?: StackNavigationOptions;
-}) {
- React.useLayoutEffect(() => {
- navigation.setOptions({
- headerShown: false,
- });
- }, [navigation]);
-
- return (
-
- ({
- title: `Article by ${route.params?.author ?? 'Unknown'}`,
- })}
- initialParams={{ author: 'Gandalf' }}
- />
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- buttons: {
- flexDirection: 'row',
- padding: 8,
- },
- button: {
- margin: 8,
- },
-});
diff --git a/example/src/Screens/StackHeaderCustomization.tsx b/example/src/Screens/StackHeaderCustomization.tsx
deleted file mode 100644
index 88b6d90987..0000000000
--- a/example/src/Screens/StackHeaderCustomization.tsx
+++ /dev/null
@@ -1,198 +0,0 @@
-import * as React from 'react';
-import {
- Animated,
- View,
- StyleSheet,
- ScrollView,
- Alert,
- Platform,
-} from 'react-native';
-import { Button, Appbar } from 'react-native-paper';
-import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
-import { useTheme, ParamListBase } from '@react-navigation/native';
-import {
- createStackNavigator,
- StackScreenProps,
- Header,
- StackHeaderProps,
-} from '@react-navigation/stack';
-import { HeaderBackground, useHeaderHeight } from '@react-navigation/elements';
-import BlurView from '../Shared/BlurView';
-import Article from '../Shared/Article';
-import Albums from '../Shared/Albums';
-
-type SimpleStackParams = {
- Article: { author: string };
- Albums: undefined;
-};
-
-const scrollEnabled = Platform.select({ web: true, default: false });
-
-const ArticleScreen = ({
- navigation,
- route,
-}: StackScreenProps) => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-const AlbumsScreen = ({ navigation }: StackScreenProps) => {
- const headerHeight = useHeaderHeight();
-
- return (
-
-
-
-
-
-
-
- );
-};
-
-const SimpleStack = createStackNavigator();
-
-type Props = StackScreenProps;
-
-function CustomHeader(props: StackHeaderProps) {
- const { current, next } = props.progress;
-
- const progress = Animated.add(current, next || 0);
- const opacity = progress.interpolate({
- inputRange: [0, 1, 2],
- outputRange: [0, 1, 0],
- });
-
- return (
- <>
-
-
- Why hello there, pardner!
-
- >
- );
-}
-
-export default function HeaderCustomizationScreen({ navigation }: Props) {
- React.useLayoutEffect(() => {
- navigation.setOptions({
- headerShown: false,
- });
- }, [navigation]);
-
- const { colors, dark } = useTheme();
- const [headerTitleCentered, setHeaderTitleCentered] = React.useState(true);
-
- return (
-
- ({
- title: `Article by ${route.params?.author}`,
- header: (props) => ,
- headerTintColor: '#fff',
- headerStyle: { backgroundColor: '#ff005d' },
- headerBackTitleVisible: false,
- headerTitleAlign: headerTitleCentered ? 'center' : 'left',
- headerBackImage: ({ tintColor }) => (
-
- ),
- headerRight: ({ tintColor }) => (
- {
- setHeaderTitleCentered((centered) => !centered);
- Alert.alert(
- 'Never gonna give you up!',
- 'Never gonna let you down! Never gonna run around and desert you!'
- );
- }}
- />
- ),
- })}
- initialParams={{ author: 'Gandalf' }}
- />
- (
-
-
-
- ),
- }}
- />
-
- );
-}
-
-const styles = StyleSheet.create({
- buttons: {
- flexDirection: 'row',
- padding: 8,
- },
- button: {
- margin: 8,
- },
- banner: {
- textAlign: 'center',
- color: 'tomato',
- backgroundColor: 'papayawhip',
- padding: 4,
- },
-});
diff --git a/example/src/Screens/StackTransparent.tsx b/example/src/Screens/StackTransparent.tsx
deleted file mode 100644
index 64c0127a23..0000000000
--- a/example/src/Screens/StackTransparent.tsx
+++ /dev/null
@@ -1,151 +0,0 @@
-import * as React from 'react';
-import { View, StyleSheet, ScrollView, Platform } from 'react-native';
-import { Button, Paragraph } from 'react-native-paper';
-import { ParamListBase, useTheme } from '@react-navigation/native';
-import {
- createStackNavigator,
- StackScreenProps,
-} from '@react-navigation/stack';
-import Article from '../Shared/Article';
-
-type SimpleStackParams = {
- Article: { author: string };
- Dialog: undefined;
-};
-
-const scrollEnabled = Platform.select({ web: true, default: false });
-
-const ArticleScreen = ({
- navigation,
- route,
-}: StackScreenProps) => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-const DialogScreen = ({ navigation }: StackScreenProps) => {
- const { colors } = useTheme();
-
- return (
-
-
-
- Mise en place is a French term that literally means “put in place.” It
- also refers to a way cooks in professional kitchens and restaurants
- set up their work stations—first by gathering all ingredients for a
- recipes, partially preparing them (like measuring out and chopping),
- and setting them all near each other. Setting up mise en place before
- cooking is another top tip for home cooks, as it seriously helps with
- organization. It’ll pretty much guarantee you never forget to add an
- ingredient and save you time from running back and forth from the
- pantry ten times.
-
-
-
-
- );
-};
-
-const SimpleStack = createStackNavigator();
-
-type Props = Partial> &
- StackScreenProps;
-
-export default function SimpleStackScreen({ navigation, ...rest }: Props) {
- React.useLayoutEffect(() => {
- navigation.setOptions({
- headerShown: false,
- });
- }, [navigation]);
-
- return (
-
-
- ({
- cardStyle: {
- opacity: progress.interpolate({
- inputRange: [0, 0.5, 0.9, 1],
- outputRange: [0, 0.25, 0.7, 1],
- }),
- transform: [
- {
- scale: progress.interpolate({
- inputRange: [0, 1],
- outputRange: [0.9, 1],
- extrapolate: 'clamp',
- }),
- },
- ],
- },
- overlayStyle: {
- opacity: progress.interpolate({
- inputRange: [0, 1],
- outputRange: [0, 0.5],
- extrapolate: 'clamp',
- }),
- },
- }),
- }}
- />
-
- );
-}
-
-const styles = StyleSheet.create({
- buttons: {
- flexDirection: 'row',
- padding: 8,
- },
- button: {
- margin: 8,
- },
- container: {
- flex: 1,
- alignItems: 'center',
- justifyContent: 'center',
- },
- dialog: {
- padding: 16,
- width: '90%',
- maxWidth: 400,
- borderRadius: 3,
- },
- close: {
- alignSelf: 'flex-end',
- },
-});
diff --git a/example/src/Shared/Albums.tsx b/example/src/Shared/Albums.tsx
deleted file mode 100644
index 65f10ad220..0000000000
--- a/example/src/Shared/Albums.tsx
+++ /dev/null
@@ -1,106 +0,0 @@
-/* eslint-disable import/no-commonjs */
-
-import * as React from 'react';
-import {
- View,
- Image,
- ScrollView,
- StyleSheet,
- ScrollViewProps,
- Dimensions,
- Platform,
- ScaledSize,
-} from 'react-native';
-import { useScrollToTop } from '@react-navigation/native';
-
-const COVERS = [
- require('../../assets/album-art-01.jpg'),
- require('../../assets/album-art-02.jpg'),
- require('../../assets/album-art-03.jpg'),
- require('../../assets/album-art-04.jpg'),
- require('../../assets/album-art-05.jpg'),
- require('../../assets/album-art-06.jpg'),
- require('../../assets/album-art-07.jpg'),
- require('../../assets/album-art-08.jpg'),
- require('../../assets/album-art-09.jpg'),
- require('../../assets/album-art-10.jpg'),
- require('../../assets/album-art-11.jpg'),
- require('../../assets/album-art-12.jpg'),
- require('../../assets/album-art-13.jpg'),
- require('../../assets/album-art-14.jpg'),
- require('../../assets/album-art-15.jpg'),
- require('../../assets/album-art-16.jpg'),
- require('../../assets/album-art-17.jpg'),
- require('../../assets/album-art-18.jpg'),
- require('../../assets/album-art-19.jpg'),
- require('../../assets/album-art-20.jpg'),
- require('../../assets/album-art-21.jpg'),
- require('../../assets/album-art-22.jpg'),
- require('../../assets/album-art-23.jpg'),
- require('../../assets/album-art-24.jpg'),
-];
-
-export default function Albums(props: Partial) {
- const [dimensions, setDimensions] = React.useState(Dimensions.get('window'));
-
- React.useEffect(() => {
- const onDimensionsChange = ({ window }: { window: ScaledSize }) => {
- setDimensions(window);
- };
-
- Dimensions.addEventListener('change', onDimensionsChange);
-
- return () => Dimensions.removeEventListener('change', onDimensionsChange);
- }, []);
-
- const ref = React.useRef(null);
-
- useScrollToTop(ref);
-
- const itemSize = dimensions.width / Math.floor(dimensions.width / 150);
-
- return (
-
- {COVERS.map((source, i) => (
-
-
-
- ))}
-
- );
-}
-
-const styles = StyleSheet.create({
- ...Platform.select({
- web: {
- content: {
- display: 'grid' as 'none',
- gridTemplateColumns: 'repeat(auto-fill, minmax(150px, 1fr))',
- },
- item: {
- width: '100%',
- },
- },
- default: {
- content: {
- flexDirection: 'row',
- flexWrap: 'wrap',
- },
- },
- }),
- photo: {
- flex: 1,
- resizeMode: 'cover',
- paddingTop: '100%',
- },
-});
diff --git a/example/src/Shared/Article.tsx b/example/src/Shared/Article.tsx
deleted file mode 100644
index 66ce9be16d..0000000000
--- a/example/src/Shared/Article.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import * as React from 'react';
-import {
- View,
- Text,
- Image,
- ScrollView,
- StyleSheet,
- ScrollViewProps,
-} from 'react-native';
-import { useScrollToTop, useTheme } from '@react-navigation/native';
-
-type Props = Partial & {
- date?: string;
- author?: {
- name: string;
- };
-};
-
-export default function Article({
- date = '1st Jan 2025',
- author = {
- name: 'Knowledge Bot',
- },
- ...rest
-}: Props) {
- const ref = React.useRef(null);
-
- useScrollToTop(ref);
-
- const { colors } = useTheme();
-
- return (
-
-
-
-
-
- {author.name}
-
- {date}
-
-
- Lorem Ipsum
-
- Contrary to popular belief, Lorem Ipsum is not simply random text. It
- has roots in a piece of classical Latin literature from 45 BC, making it
- over 2000 years old.
-
-
-
- Richard McClintock, a Latin professor at Hampden-Sydney College in
- Virginia, looked up one of the more obscure Latin words, consectetur,
- from a Lorem Ipsum passage, and going through the cites of the word in
- classical literature, discovered the undoubtable source.
-
-
- Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus
- Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero,
- written in 45 BC. This book is a treatise on the theory of ethics, very
- popular during the Renaissance. The first line of Lorem Ipsum,
- "Lorem ipsum dolor sit amet..", comes from a line in section
- 1.10.32.
-
-
- );
-}
-
-const styles = StyleSheet.create({
- content: {
- paddingVertical: 16,
- },
- author: {
- flexDirection: 'row',
- marginVertical: 8,
- marginHorizontal: 16,
- },
- meta: {
- marginHorizontal: 8,
- justifyContent: 'center',
- },
- name: {
- fontWeight: 'bold',
- fontSize: 16,
- lineHeight: 24,
- },
- timestamp: {
- opacity: 0.5,
- fontSize: 14,
- lineHeight: 21,
- },
- avatar: {
- height: 48,
- width: 48,
- borderRadius: 24,
- },
- title: {
- fontWeight: 'bold',
- fontSize: 36,
- marginVertical: 8,
- marginHorizontal: 16,
- },
- paragraph: {
- fontSize: 16,
- lineHeight: 24,
- marginVertical: 8,
- marginHorizontal: 16,
- },
- image: {
- width: '100%',
- height: 200,
- resizeMode: 'cover',
- marginVertical: 8,
- },
-});
diff --git a/example/src/Shared/BlurView.native.tsx b/example/src/Shared/BlurView.native.tsx
deleted file mode 100644
index 49226dfd31..0000000000
--- a/example/src/Shared/BlurView.native.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-import { BlurView } from 'expo-blur';
-
-export default BlurView;
diff --git a/example/src/Shared/BlurView.tsx b/example/src/Shared/BlurView.tsx
deleted file mode 100644
index 4aaf81a737..0000000000
--- a/example/src/Shared/BlurView.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import * as React from 'react';
-import { View, ViewProps } from 'react-native';
-
-type Props = ViewProps & {
- tint: 'light' | 'dark';
- intensity: number;
-};
-
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-export default function BlurView({ tint, intensity, ...rest }: Props) {
- return ;
-}
diff --git a/example/src/Shared/Chat.tsx b/example/src/Shared/Chat.tsx
deleted file mode 100644
index 81153745fa..0000000000
--- a/example/src/Shared/Chat.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import * as React from 'react';
-import {
- View,
- Image,
- Text,
- TextInput,
- ScrollView,
- StyleSheet,
- ScrollViewProps,
-} from 'react-native';
-import { useScrollToTop, useTheme } from '@react-navigation/native';
-import Color from 'color';
-
-const MESSAGES = [
- 'okay',
- 'sudo make me a sandwich',
- 'what? make it yourself',
- 'make me a sandwich',
-];
-
-export default function Chat(props: Partial) {
- const ref = React.useRef(null);
-
- useScrollToTop(ref);
-
- const { colors } = useTheme();
-
- return (
-
-
- {MESSAGES.map((text, i) => {
- const odd = i % 2;
-
- return (
-
-
-
-
- {text}
-
-
-
- );
- })}
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- inverted: {
- transform: [{ scaleY: -1 }],
- },
- content: {
- padding: 16,
- },
- even: {
- flexDirection: 'row',
- },
- odd: {
- flexDirection: 'row-reverse',
- },
- avatar: {
- marginVertical: 8,
- marginHorizontal: 6,
- height: 40,
- width: 40,
- borderRadius: 20,
- borderColor: 'rgba(0, 0, 0, .16)',
- borderWidth: StyleSheet.hairlineWidth,
- },
- bubble: {
- marginVertical: 8,
- marginHorizontal: 6,
- paddingVertical: 12,
- paddingHorizontal: 16,
- borderRadius: 20,
- },
- input: {
- height: 48,
- paddingVertical: 12,
- paddingHorizontal: 24,
- },
-});
diff --git a/example/src/Shared/Contacts.tsx b/example/src/Shared/Contacts.tsx
deleted file mode 100644
index 238a5983ee..0000000000
--- a/example/src/Shared/Contacts.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-import * as React from 'react';
-import { View, Text, FlatList, StyleSheet } from 'react-native';
-import { useScrollToTop, useTheme } from '@react-navigation/native';
-
-type Item = { name: string; number: number };
-
-const CONTACTS: Item[] = [
- { name: 'Marissa Castillo', number: 7766398169 },
- { name: 'Denzel Curry', number: 9394378449 },
- { name: 'Miles Ferguson', number: 8966872888 },
- { name: 'Desiree Webster', number: 6818656371 },
- { name: 'Samantha Young', number: 6538288534 },
- { name: 'Irene Hunter', number: 2932176249 },
- { name: 'Annie Ryan', number: 4718456627 },
- { name: 'Sasha Oliver', number: 9743195919 },
- { name: 'Jarrod Avila', number: 8339212305 },
- { name: 'Griffin Weaver', number: 6059349721 },
- { name: 'Emilee Moss', number: 7382905180 },
- { name: 'Angelique Oliver', number: 9689298436 },
- { name: 'Emanuel Little', number: 6673376805 },
- { name: 'Wayne Day', number: 6918839582 },
- { name: 'Lauren Reese', number: 4652613201 },
- { name: 'Kailey Ward', number: 2232609512 },
- { name: 'Gabrielle Newman', number: 2837997127 },
- { name: 'Luke Strickland', number: 8404732322 },
- { name: 'Payton Garza', number: 7916140875 },
- { name: 'Anna Moss', number: 3504954657 },
- { name: 'Kailey Vazquez', number: 3002136330 },
- { name: 'Jennifer Coleman', number: 5469629753 },
- { name: 'Cindy Casey', number: 8446175026 },
- { name: 'Dillon Doyle', number: 5614510703 },
- { name: 'Savannah Garcia', number: 5634775094 },
- { name: 'Kailey Hudson', number: 3289239675 },
- { name: 'Ariel Green', number: 2103492196 },
- { name: 'Weston Perez', number: 2984221823 },
- { name: 'Kari Juarez', number: 9502125065 },
- { name: 'Sara Sanders', number: 7696668206 },
- { name: 'Griffin Le', number: 3396937040 },
- { name: 'Fernando Valdez', number: 9124257306 },
- { name: 'Taylor Marshall', number: 9656072372 },
- { name: 'Elias Dunn', number: 9738536473 },
- { name: 'Diane Barrett', number: 6886824829 },
- { name: 'Samuel Freeman', number: 5523948094 },
- { name: 'Irene Garza', number: 2077694008 },
- { name: 'Devante Alvarez', number: 9897002645 },
- { name: 'Sydney Floyd', number: 6462897254 },
- { name: 'Toni Dixon', number: 3775448213 },
- { name: 'Anastasia Spencer', number: 4548212752 },
- { name: 'Reid Cortez', number: 6668056507 },
- { name: 'Ramon Duncan', number: 8889157751 },
- { name: 'Kenny Moreno', number: 5748219540 },
- { name: 'Shelby Craig', number: 9473708675 },
- { name: 'Jordyn Brewer', number: 7552277991 },
- { name: 'Tanya Walker', number: 4308189657 },
- { name: 'Nolan Figueroa', number: 9173443776 },
- { name: 'Sophia Gibbs', number: 6435942770 },
- { name: 'Vincent Sandoval', number: 2606111495 },
-];
-
-const ContactItem = React.memo(
- ({ item }: { item: { name: string; number: number } }) => {
- const { colors } = useTheme();
-
- return (
-
-
-
- {item.name.slice(0, 1).toUpperCase()}
-
-
-
- {item.name}
-
- {item.number}
-
-
-
- );
- }
-);
-
-const ItemSeparator = () => {
- const { colors } = useTheme();
-
- return (
-
- );
-};
-
-export default function Contacts() {
- const ref = React.useRef>(null);
-
- useScrollToTop(ref);
-
- const renderItem = ({ item }: { item: Item }) => ;
-
- return (
- String(i)}
- renderItem={renderItem}
- ItemSeparatorComponent={ItemSeparator}
- />
- );
-}
-
-const styles = StyleSheet.create({
- item: {
- flexDirection: 'row',
- alignItems: 'center',
- padding: 8,
- },
- avatar: {
- height: 36,
- width: 36,
- borderRadius: 18,
- backgroundColor: '#e91e63',
- alignItems: 'center',
- justifyContent: 'center',
- },
- letter: {
- color: 'white',
- fontWeight: 'bold',
- },
- details: {
- margin: 8,
- },
- name: {
- fontWeight: 'bold',
- fontSize: 14,
- },
- number: {
- fontSize: 12,
- },
- separator: {
- height: StyleSheet.hairlineWidth,
- },
-});
diff --git a/example/src/Shared/NewsFeed.tsx b/example/src/Shared/NewsFeed.tsx
deleted file mode 100644
index 27b331d242..0000000000
--- a/example/src/Shared/NewsFeed.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-import * as React from 'react';
-import {
- View,
- TextInput,
- Image,
- ScrollView,
- StyleSheet,
- ScrollViewProps,
-} from 'react-native';
-import { useScrollToTop, useTheme } from '@react-navigation/native';
-import {
- Card,
- Text,
- Avatar,
- Subheading,
- IconButton,
- Divider,
-} from 'react-native-paper';
-import Color from 'color';
-
-type Props = Partial & {
- date?: number;
-};
-
-const Author = () => {
- return (
-
-
- Joke bot
-
- );
-};
-
-const Footer = () => {
- return (
-
-
-
-
-
- );
-};
-
-export default function NewsFeed(props: Props) {
- const ref = React.useRef(null);
-
- useScrollToTop(ref);
-
- const { colors } = useTheme();
-
- return (
-
-
-
-
-
-
-
-
- If you aren't impressed with the picture of the first Black
- Hole, you clearly don't understand the gravity of the
- situation.
-
-
-
-
-
-
-
-
-
- I went to the zoo and I saw a baguette in a cage. I asked the
- zookeeper about it and he said it was bread in captivity.
-
-
-
-
-
-
-
-
- Why didn't 4 ask 5 out? Because he was 2².
-
-
-
-
-
-
-
-
- What did Master Yoda say when he first saw himself in 4k? HDMI.
-
-
-
-
-
-
-
-
-
- Someone broke into my house and stole 20% of my couch. Ouch!
-
-
-
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- input: {
- padding: 16,
- backgroundColor: 'transparent',
- margin: 0,
- },
- card: {
- marginVertical: 8,
- borderRadius: 0,
- },
- cover: {
- height: 160,
- borderRadius: 0,
- },
- content: {
- marginBottom: 12,
- },
- attribution: {
- margin: 12,
- },
- author: {
- marginHorizontal: 8,
- },
- row: {
- flexDirection: 'row',
- alignItems: 'center',
- },
- icon: {
- flex: 1,
- },
-});
diff --git a/example/src/Shared/SettingsItem.tsx b/example/src/Shared/SettingsItem.tsx
deleted file mode 100644
index 908bfb4a99..0000000000
--- a/example/src/Shared/SettingsItem.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import * as React from 'react';
-import { View } from 'react-native';
-import { Subheading, Switch } from 'react-native-paper';
-
-type Props = {
- label: string;
- value: boolean;
- onValueChange: () => void;
-};
-
-export default function SettingsItem({ label, value, onValueChange }: Props) {
- return (
-
- {label}
-
-
- );
-}
diff --git a/example/src/Shared/TouchableBounce.native.tsx b/example/src/Shared/TouchableBounce.native.tsx
deleted file mode 100644
index 17c0c8719e..0000000000
--- a/example/src/Shared/TouchableBounce.native.tsx
+++ /dev/null
@@ -1,4 +0,0 @@
-// @ts-expect-error: there are no type definitions for deep imports
-import TouchableBounce from 'react-native/Libraries/Components/Touchable/TouchableBounce';
-
-export default TouchableBounce;
diff --git a/example/src/Shared/TouchableBounce.tsx b/example/src/Shared/TouchableBounce.tsx
deleted file mode 100644
index 7dc89f02bc..0000000000
--- a/example/src/Shared/TouchableBounce.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-import { TouchableOpacity } from 'react-native';
-
-export default TouchableOpacity;
diff --git a/example/src/app-navigation-types.ts b/example/src/app-navigation-types.ts
new file mode 100644
index 0000000000..9fe235cfea
--- /dev/null
+++ b/example/src/app-navigation-types.ts
@@ -0,0 +1,28 @@
+import type { RouteProp } from '@react-navigation/native';
+import type { StackNavigationProp } from '@react-navigation/stack';
+
+type MainScreenParams = {};
+type DetailScreenParams =
+ | {
+ id?: string;
+ }
+ | undefined;
+
+export type AppStackParamsList = {
+ Main: MainScreenParams;
+ Detail: DetailScreenParams;
+};
+
+// Route Prop
+export type MainScreenRouteProp = RouteProp;
+export type DetailScreenRouteProp = RouteProp;
+
+// Navigation Props
+export type MainScreenNavigationProp = StackNavigationProp<
+ AppStackParamsList,
+ 'Main'
+>;
+export type DetailScreenNavigationProp = StackNavigationProp<
+ AppStackParamsList,
+ 'Detail'
+>;
diff --git a/example/src/index.tsx b/example/src/index.tsx
index 5f9009dcfa..e683e0d81a 100644
--- a/example/src/index.tsx
+++ b/example/src/index.tsx
@@ -1,370 +1,53 @@
-import * as React from 'react';
-import {
- ScrollView,
- Platform,
- StatusBar,
- I18nManager,
- Dimensions,
- ScaledSize,
- Linking,
- LogBox,
-} from 'react-native';
-import { SafeAreaView } from 'react-native-safe-area-context';
-import { enableScreens } from 'react-native-screens';
-import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
-import {
- Provider as PaperProvider,
- DefaultTheme as PaperLightTheme,
- DarkTheme as PaperDarkTheme,
- List,
- Divider,
- Text,
-} from 'react-native-paper';
-import { createURL } from 'expo-linking';
-import AsyncStorage from '@react-native-async-storage/async-storage';
-import {
- InitialState,
- NavigationContainer,
- DefaultTheme,
- DarkTheme,
- PathConfigMap,
- NavigationContainerRef,
-} from '@react-navigation/native';
+import React from 'react';
+import 'react-native-gesture-handler';
+import { LinkingOptions, NavigationContainer } from '@react-navigation/native';
+import { createStackNavigator } from '@react-navigation/stack';
+import MainScreen from './screens/main';
+import DetailScreen from './screens/detail';
+import type { AppStackParamsList } from './app-navigation-types';
import { createDrawerNavigator } from '@react-navigation/drawer';
-import {
- createStackNavigator,
- StackScreenProps,
- HeaderStyleInterpolators,
-} from '@react-navigation/stack';
-import { useReduxDevToolsExtension } from '@react-navigation/devtools';
-
-import { restartApp } from './Restart';
-import SettingsItem from './Shared/SettingsItem';
-import SimpleStack from './Screens/SimpleStack';
-import ModalStack from './Screens/ModalStack';
-import MixedHeaderMode from './Screens/MixedHeaderMode';
-import StackTransparent from './Screens/StackTransparent';
-import StackHeaderCustomization from './Screens/StackHeaderCustomization';
-import BottomTabs from './Screens/BottomTabs';
-import MaterialTopTabsScreen from './Screens/MaterialTopTabs';
-import MaterialBottomTabs from './Screens/MaterialBottomTabs';
-import NotFound from './Screens/NotFound';
-import DynamicTabs from './Screens/DynamicTabs';
-import MasterDetail from './Screens/MasterDetail';
-import AuthFlow from './Screens/AuthFlow';
-import PreventRemove from './Screens/PreventRemove';
-import LinkComponent from './Screens/LinkComponent';
-
-if (Platform.OS !== 'web') {
- LogBox.ignoreLogs(['Require cycle:']);
-}
-
-enableScreens();
-
-type RootDrawerParamList = {
- Examples: undefined;
-};
+import { createURL } from 'expo-linking';
-const SCREENS = {
- SimpleStack: { title: 'Simple Stack', component: SimpleStack },
- ModalStack: {
- title: 'Modal Stack',
- component: ModalStack,
- },
- MixedHeaderMode: {
- title: 'Float + Screen Header Stack',
- component: MixedHeaderMode,
- },
- StackTransparent: {
- title: 'Transparent Stack',
- component: StackTransparent,
- },
- StackHeaderCustomization: {
- title: 'Header Customization in Stack',
- component: StackHeaderCustomization,
- },
- BottomTabs: { title: 'Bottom Tabs', component: BottomTabs },
- MaterialTopTabs: {
- title: 'Material Top Tabs',
- component: MaterialTopTabsScreen,
- },
- MaterialBottomTabs: {
- title: 'Material Bottom Tabs',
- component: MaterialBottomTabs,
- },
- DynamicTabs: {
- title: 'Dynamic Tabs',
- component: DynamicTabs,
- },
- MasterDetail: {
- title: 'Master Detail',
- component: MasterDetail,
- },
- AuthFlow: {
- title: 'Auth Flow',
- component: AuthFlow,
- },
- PreventRemove: {
- title: 'Prevent removing screen',
- component: PreventRemove,
- },
- LinkComponent: {
- title: '',
- component: LinkComponent,
+const DrawerLinking: LinkingOptions = {
+ prefixes: [createURL('/')],
+ config: {
+ screens: {
+ MainStack: {
+ screens: {
+ initialRouteName: 'Main',
+ Main: {
+ path: 'main',
+ },
+ Detail: {
+ path: 'detail',
+ },
+ },
+ },
+ },
},
};
-type RootStackParamList = {
- Home: undefined;
- NotFound: undefined;
-} & {
- [P in keyof typeof SCREENS]: undefined;
-};
-
-const Drawer = createDrawerNavigator();
-const Stack = createStackNavigator();
-
-const NAVIGATION_PERSISTENCE_KEY = 'NAVIGATION_STATE';
-const THEME_PERSISTENCE_KEY = 'THEME_TYPE';
-
-export default function App() {
- const [theme, setTheme] = React.useState(DefaultTheme);
-
- const [isReady, setIsReady] = React.useState(Platform.OS === 'web');
- const [initialState, setInitialState] = React.useState<
- InitialState | undefined
- >();
-
- React.useEffect(() => {
- const restoreState = async () => {
- try {
- const initialUrl = await Linking.getInitialURL();
-
- if (Platform.OS !== 'web' || initialUrl === null) {
- const savedState = await AsyncStorage?.getItem(
- NAVIGATION_PERSISTENCE_KEY
- );
-
- const state = savedState ? JSON.parse(savedState) : undefined;
-
- if (state !== undefined) {
- setInitialState(state);
- }
- }
- } finally {
- try {
- const themeName = await AsyncStorage?.getItem(THEME_PERSISTENCE_KEY);
-
- setTheme(themeName === 'dark' ? DarkTheme : DefaultTheme);
- } catch (e) {
- // Ignore
- }
-
- setIsReady(true);
- }
- };
-
- restoreState();
- }, []);
-
- const paperTheme = React.useMemo(() => {
- const t = theme.dark ? PaperDarkTheme : PaperLightTheme;
-
- return {
- ...t,
- colors: {
- ...t.colors,
- ...theme.colors,
- surface: theme.colors.card,
- accent: theme.dark ? 'rgb(255, 55, 95)' : 'rgb(255, 45, 85)',
- },
- };
- }, [theme.colors, theme.dark]);
-
- const [dimensions, setDimensions] = React.useState(Dimensions.get('window'));
-
- React.useEffect(() => {
- const onDimensionsChange = ({ window }: { window: ScaledSize }) => {
- setDimensions(window);
- };
-
- Dimensions.addEventListener('change', onDimensionsChange);
-
- return () => Dimensions.removeEventListener('change', onDimensionsChange);
- }, []);
-
- const navigationRef = React.useRef(null);
-
- useReduxDevToolsExtension(navigationRef);
-
- if (!isReady) {
- return null;
- }
-
- const isLargeScreen = dimensions.width >= 1024;
+const AppStack = createStackNavigator();
+function AppStackNavigator(): JSX.Element {
return (
-
- {Platform.OS === 'ios' && (
-
- )}
-
- AsyncStorage?.setItem(
- NAVIGATION_PERSISTENCE_KEY,
- JSON.stringify(state)
- )
- }
- theme={theme}
- linking={{
- // To test deep linking on, run the following in the Terminal:
- // Android: adb shell am start -a android.intent.action.VIEW -d "exp://127.0.0.1:19000/--/simple-stack"
- // iOS: xcrun simctl openurl booted exp://127.0.0.1:19000/--/simple-stack
- // Android (bare): adb shell am start -a android.intent.action.VIEW -d "rne://127.0.0.1:19000/--/simple-stack"
- // iOS (bare): xcrun simctl openurl booted rne://127.0.0.1:19000/--/simple-stack
- // The first segment of the link is the the scheme + host (returned by `Linking.makeUrl`)
- prefixes: [createURL('/')],
- config: {
- initialRouteName: 'Home',
- screens: Object.keys(SCREENS).reduce(
- (acc, name) => {
- // Convert screen names such as SimpleStack to kebab case (simple-stack)
- const path = name
- .replace(/([A-Z]+)/g, '-$1')
- .replace(/^-/, '')
- .toLowerCase();
-
- acc[name] = {
- path,
- screens: {
- Article: {
- path: 'article/:author?',
- parse: {
- author: (author) =>
- author.charAt(0).toUpperCase() +
- author.slice(1).replace(/-/g, ' '),
- },
- stringify: {
- author: (author: string) =>
- author.toLowerCase().replace(/\s/g, '-'),
- },
- },
- Albums: 'music',
- Chat: 'chat',
- Contacts: 'people',
- NewsFeed: 'feed',
- Dialog: 'dialog',
- },
- };
+
+
+
+
+ );
+}
- return acc;
- },
- {
- Home: {
- screens: {
- Examples: '',
- },
- },
- NotFound: '*',
- }
- ),
- },
- }}
- fallback={Loading…}
- documentTitle={{
- formatter: (options, route) =>
- `${options?.title ?? route?.name} - React Navigation Example`,
- }}
- >
-
-
- {() => (
-
- (
-
- ),
- }}
- >
- {({ navigation }: StackScreenProps) => (
-
-
- {
- I18nManager.forceRTL(!I18nManager.isRTL);
- restartApp();
- }}
- />
-
- {
- AsyncStorage?.setItem(
- THEME_PERSISTENCE_KEY,
- theme.dark ? 'light' : 'dark'
- );
+const Drawer = createDrawerNavigator();
- setTheme((t) =>
- t.dark ? DefaultTheme : DarkTheme
- );
- }}
- />
-
- {(Object.keys(SCREENS) as (keyof typeof SCREENS)[]).map(
- (name) => (
- navigation.navigate(name)}
- />
- )
- )}
-
-
- )}
-
-
- )}
-
-
- {(Object.keys(SCREENS) as (keyof typeof SCREENS)[]).map((name) => (
- SCREENS[name].component}
- options={{ title: SCREENS[name].title }}
- />
- ))}
-
-
-
+function App() {
+ return (
+
+
+
+
+
);
}
+
+export default App;
diff --git a/example/src/screens/detail/index.tsx b/example/src/screens/detail/index.tsx
new file mode 100644
index 0000000000..09152ee847
--- /dev/null
+++ b/example/src/screens/detail/index.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import { SafeAreaView, Text } from 'react-native';
+import type { DetailScreenRouteProp } from '../../app-navigation-types';
+
+type Props = {
+ route: DetailScreenRouteProp;
+};
+
+function DetailScreen({ route }: Props) {
+ const randomRef = React.useRef(Math.random());
+ return (
+
+
+ {route.params ? JSON.stringify(route.params) : 'undefined params'}
+
+ {randomRef.current}
+
+ );
+}
+
+export default DetailScreen;
diff --git a/example/src/screens/main/index.tsx b/example/src/screens/main/index.tsx
new file mode 100644
index 0000000000..964cc77f17
--- /dev/null
+++ b/example/src/screens/main/index.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import { SafeAreaView, Button } from 'react-native';
+import type { MainScreenNavigationProp } from '../../app-navigation-types';
+
+type Props = {
+ navigation: MainScreenNavigationProp;
+};
+
+function HomeScreen({ navigation }: Props) {
+ return (
+
+
+ );
+}
+
+export default HomeScreen;