expo-template-tabs 48.0.1 → 48.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/(tabs)/_layout.tsx +55 -0
- package/{screens/TabOneScreen.tsx → app/(tabs)/index.tsx} +4 -5
- package/{screens/TabTwoScreen.tsx → app/(tabs)/two.tsx} +3 -3
- package/app/[...missing].tsx +40 -0
- package/app/_layout.tsx +51 -0
- package/{screens/ModalScreen.tsx → app/modal.tsx} +1 -1
- package/app.json +1 -4
- package/babel.config.js +5 -2
- package/components/EditScreenInfo.tsx +7 -10
- package/components/ExternalLink.tsx +24 -0
- package/components/StyledText.tsx +1 -1
- package/components/Themed.tsx +2 -3
- package/index.ts +1 -0
- package/package.json +9 -13
- package/App.tsx +0 -22
- package/constants/Layout.ts +0 -12
- package/hooks/useCachedResources.ts +0 -33
- package/hooks/useColorScheme.ts +0 -8
- package/navigation/LinkingConfiguration.ts +0 -36
- package/navigation/index.tsx +0 -107
- package/screens/NotFoundScreen.tsx +0 -36
- package/types.tsx +0 -35
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import FontAwesome from '@expo/vector-icons/FontAwesome';
|
|
2
|
+
import { Link, Tabs } from 'expo-router';
|
|
3
|
+
import { Pressable, useColorScheme } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import Colors from '../../constants/Colors';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
|
|
9
|
+
*/
|
|
10
|
+
function TabBarIcon(props: {
|
|
11
|
+
name: React.ComponentProps<typeof FontAwesome>['name'];
|
|
12
|
+
color: string;
|
|
13
|
+
}) {
|
|
14
|
+
return <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default function TabLayout() {
|
|
18
|
+
const colorScheme = useColorScheme();
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Tabs
|
|
22
|
+
screenOptions={{
|
|
23
|
+
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
|
|
24
|
+
}}>
|
|
25
|
+
<Tabs.Screen
|
|
26
|
+
name="index"
|
|
27
|
+
options={{
|
|
28
|
+
title: 'Tab One',
|
|
29
|
+
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
|
30
|
+
headerRight: () => (
|
|
31
|
+
<Link href="/modal" asChild>
|
|
32
|
+
<Pressable>
|
|
33
|
+
{({ pressed }) => (
|
|
34
|
+
<FontAwesome
|
|
35
|
+
name="info-circle"
|
|
36
|
+
size={25}
|
|
37
|
+
color={Colors[colorScheme ?? 'light'].text}
|
|
38
|
+
style={{ marginRight: 15, opacity: pressed ? 0.5 : 1 }}
|
|
39
|
+
/>
|
|
40
|
+
)}
|
|
41
|
+
</Pressable>
|
|
42
|
+
</Link>
|
|
43
|
+
),
|
|
44
|
+
}}
|
|
45
|
+
/>
|
|
46
|
+
<Tabs.Screen
|
|
47
|
+
name="two"
|
|
48
|
+
options={{
|
|
49
|
+
title: 'Tab Two',
|
|
50
|
+
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
|
51
|
+
}}
|
|
52
|
+
/>
|
|
53
|
+
</Tabs>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
2
|
|
|
3
|
-
import EditScreenInfo from '
|
|
4
|
-
import { Text, View } from '
|
|
5
|
-
import { RootTabScreenProps } from '../types';
|
|
3
|
+
import EditScreenInfo from '../../components/EditScreenInfo';
|
|
4
|
+
import { Text, View } from '../../components/Themed';
|
|
6
5
|
|
|
7
|
-
export default function TabOneScreen(
|
|
6
|
+
export default function TabOneScreen() {
|
|
8
7
|
return (
|
|
9
8
|
<View style={styles.container}>
|
|
10
9
|
<Text style={styles.title}>Tab One</Text>
|
|
11
10
|
<View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
|
|
12
|
-
<EditScreenInfo path="/
|
|
11
|
+
<EditScreenInfo path="app/(tabs)/index.tsx" />
|
|
13
12
|
</View>
|
|
14
13
|
);
|
|
15
14
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
2
|
|
|
3
|
-
import EditScreenInfo from '
|
|
4
|
-
import { Text, View } from '
|
|
3
|
+
import EditScreenInfo from '../../components/EditScreenInfo';
|
|
4
|
+
import { Text, View } from '../../components/Themed';
|
|
5
5
|
|
|
6
6
|
export default function TabTwoScreen() {
|
|
7
7
|
return (
|
|
8
8
|
<View style={styles.container}>
|
|
9
9
|
<Text style={styles.title}>Tab Two</Text>
|
|
10
10
|
<View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
|
|
11
|
-
<EditScreenInfo path="/
|
|
11
|
+
<EditScreenInfo path="app/(tabs)/two.tsx" />
|
|
12
12
|
</View>
|
|
13
13
|
);
|
|
14
14
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Link, Stack } from 'expo-router';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { Text, View } from '../components/Themed';
|
|
5
|
+
|
|
6
|
+
export default function NotFoundScreen() {
|
|
7
|
+
return (
|
|
8
|
+
<>
|
|
9
|
+
<Stack.Screen options={{ title: 'Oops!' }} />
|
|
10
|
+
<View style={styles.container}>
|
|
11
|
+
<Text style={styles.title}>This screen doesn't exist.</Text>
|
|
12
|
+
|
|
13
|
+
<Link href="/" style={styles.link}>
|
|
14
|
+
<Text style={styles.linkText}>Go to home screen!</Text>
|
|
15
|
+
</Link>
|
|
16
|
+
</View>
|
|
17
|
+
</>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const styles = StyleSheet.create({
|
|
22
|
+
container: {
|
|
23
|
+
flex: 1,
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
justifyContent: 'center',
|
|
26
|
+
padding: 20,
|
|
27
|
+
},
|
|
28
|
+
title: {
|
|
29
|
+
fontSize: 20,
|
|
30
|
+
fontWeight: 'bold',
|
|
31
|
+
},
|
|
32
|
+
link: {
|
|
33
|
+
marginTop: 15,
|
|
34
|
+
paddingVertical: 15,
|
|
35
|
+
},
|
|
36
|
+
linkText: {
|
|
37
|
+
fontSize: 14,
|
|
38
|
+
color: '#2e78b7',
|
|
39
|
+
},
|
|
40
|
+
});
|
package/app/_layout.tsx
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import FontAwesome from '@expo/vector-icons/FontAwesome';
|
|
2
|
+
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
|
|
3
|
+
import { useFonts } from 'expo-font';
|
|
4
|
+
import { SplashScreen, Stack } from 'expo-router';
|
|
5
|
+
import { useEffect } from 'react';
|
|
6
|
+
import { useColorScheme } from 'react-native';
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
// Catch any errors thrown by the Layout component.
|
|
10
|
+
ErrorBoundary,
|
|
11
|
+
} from 'expo-router';
|
|
12
|
+
|
|
13
|
+
export const unstable_settings = {
|
|
14
|
+
// Ensure that reloading on `/modal` keeps a back button present.
|
|
15
|
+
initialRouteName: '(tabs)',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default function RootLayout() {
|
|
19
|
+
const [loaded, error] = useFonts({
|
|
20
|
+
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
|
|
21
|
+
...FontAwesome.font,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Expo Router uses Error Boundaries to catch errors in the navigation tree.
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (error) throw error;
|
|
27
|
+
}, [error]);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
{/* Keep the splash screen open until the assets have loaded. In the future, we should just support async font loading with a native version of font-display. */}
|
|
32
|
+
{!loaded && <SplashScreen />}
|
|
33
|
+
{loaded && <RootLayoutNav />}
|
|
34
|
+
</>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function RootLayoutNav() {
|
|
39
|
+
const colorScheme = useColorScheme();
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
|
44
|
+
<Stack>
|
|
45
|
+
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
|
46
|
+
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
|
|
47
|
+
</Stack>
|
|
48
|
+
</ThemeProvider>
|
|
49
|
+
</>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -9,7 +9,7 @@ export default function ModalScreen() {
|
|
|
9
9
|
<View style={styles.container}>
|
|
10
10
|
<Text style={styles.title}>Modal</Text>
|
|
11
11
|
<View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
|
|
12
|
-
<EditScreenInfo path="/
|
|
12
|
+
<EditScreenInfo path="app/modal.tsx" />
|
|
13
13
|
|
|
14
14
|
{/* Use a light status bar on iOS to account for the black space above the modal */}
|
|
15
15
|
<StatusBar style={Platform.OS === 'ios' ? 'light' : 'auto'} />
|
package/app.json
CHANGED
|
@@ -12,10 +12,6 @@
|
|
|
12
12
|
"resizeMode": "contain",
|
|
13
13
|
"backgroundColor": "#ffffff"
|
|
14
14
|
},
|
|
15
|
-
"updates": {
|
|
16
|
-
"fallbackToCacheTimeout": 0
|
|
17
|
-
},
|
|
18
|
-
"assetBundlePatterns": ["**/*"],
|
|
19
15
|
"ios": {
|
|
20
16
|
"supportsTablet": true
|
|
21
17
|
},
|
|
@@ -26,6 +22,7 @@
|
|
|
26
22
|
}
|
|
27
23
|
},
|
|
28
24
|
"web": {
|
|
25
|
+
"bundler": "metro",
|
|
29
26
|
"favicon": "./assets/images/favicon.png"
|
|
30
27
|
}
|
|
31
28
|
}
|
package/babel.config.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { StyleSheet
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import Colors from '../constants/Colors';
|
|
5
|
+
import { ExternalLink } from './ExternalLink';
|
|
5
6
|
import { MonoText } from './StyledText';
|
|
6
7
|
import { Text, View } from './Themed';
|
|
7
8
|
|
|
@@ -32,22 +33,18 @@ export default function EditScreenInfo({ path }: { path: string }) {
|
|
|
32
33
|
</View>
|
|
33
34
|
|
|
34
35
|
<View style={styles.helpContainer}>
|
|
35
|
-
<
|
|
36
|
+
<ExternalLink
|
|
37
|
+
style={styles.helpLink}
|
|
38
|
+
href="https://docs.expo.io/get-started/create-a-new-app/#opening-the-app-on-your-phonetablet">
|
|
36
39
|
<Text style={styles.helpLinkText} lightColor={Colors.light.tint}>
|
|
37
40
|
Tap here if your app doesn't automatically update after making changes
|
|
38
41
|
</Text>
|
|
39
|
-
</
|
|
42
|
+
</ExternalLink>
|
|
40
43
|
</View>
|
|
41
44
|
</View>
|
|
42
45
|
);
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
function handleHelpPress() {
|
|
46
|
-
WebBrowser.openBrowserAsync(
|
|
47
|
-
'https://docs.expo.io/get-started/create-a-new-app/#opening-the-app-on-your-phonetablet'
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
48
|
const styles = StyleSheet.create({
|
|
52
49
|
getStartedContainer: {
|
|
53
50
|
alignItems: 'center',
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Link } from 'expo-router';
|
|
2
|
+
import * as WebBrowser from 'expo-web-browser';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Platform } from 'react-native';
|
|
5
|
+
|
|
6
|
+
export function ExternalLink(props: React.ComponentProps<typeof Link>) {
|
|
7
|
+
return (
|
|
8
|
+
<Link
|
|
9
|
+
hrefAttrs={{
|
|
10
|
+
// On web, launch the link in a new tab.
|
|
11
|
+
target: '_blank',
|
|
12
|
+
}}
|
|
13
|
+
{...props}
|
|
14
|
+
onPress={(e) => {
|
|
15
|
+
if (Platform.OS !== 'web') {
|
|
16
|
+
// Prevent the default behavior of linking to the default browser on native.
|
|
17
|
+
e.preventDefault();
|
|
18
|
+
// Open the link in an in-app browser.
|
|
19
|
+
WebBrowser.openBrowserAsync(props.href as string);
|
|
20
|
+
}
|
|
21
|
+
}}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
package/components/Themed.tsx
CHANGED
|
@@ -3,16 +3,15 @@
|
|
|
3
3
|
* https://docs.expo.io/guides/color-schemes/
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { Text as DefaultText, View as DefaultView } from 'react-native';
|
|
6
|
+
import { Text as DefaultText, useColorScheme, View as DefaultView } from 'react-native';
|
|
7
7
|
|
|
8
8
|
import Colors from '../constants/Colors';
|
|
9
|
-
import useColorScheme from '../hooks/useColorScheme';
|
|
10
9
|
|
|
11
10
|
export function useThemeColor(
|
|
12
11
|
props: { light?: string; dark?: string },
|
|
13
12
|
colorName: keyof typeof Colors.light & keyof typeof Colors.dark
|
|
14
13
|
) {
|
|
15
|
-
const theme = useColorScheme();
|
|
14
|
+
const theme = useColorScheme() ?? 'light';
|
|
16
15
|
const colorFromProps = props[theme];
|
|
17
16
|
|
|
18
17
|
if (colorFromProps) {
|
package/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'expo-router/entry';
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-template-tabs",
|
|
3
3
|
"description": "The Tab Navigation project template includes several example screens.",
|
|
4
|
-
"version": "48.0.
|
|
5
|
-
"main": "node_modules/expo/AppEntry.js",
|
|
4
|
+
"version": "48.0.4",
|
|
6
5
|
"scripts": {
|
|
7
6
|
"start": "expo start",
|
|
8
7
|
"android": "expo start --android",
|
|
@@ -15,18 +14,15 @@
|
|
|
15
14
|
},
|
|
16
15
|
"dependencies": {
|
|
17
16
|
"@expo/vector-icons": "^13.0.0",
|
|
18
|
-
"@react-navigation/bottom-tabs": "^6.0.5",
|
|
19
17
|
"@react-navigation/native": "^6.0.2",
|
|
20
|
-
"
|
|
21
|
-
"expo": "~
|
|
22
|
-
"expo-
|
|
23
|
-
"expo-
|
|
24
|
-
"expo-
|
|
25
|
-
"expo-
|
|
26
|
-
"expo-
|
|
27
|
-
"expo-
|
|
28
|
-
"expo-system-ui": "~2.2.0",
|
|
29
|
-
"expo-web-browser": "~12.1.0",
|
|
18
|
+
"expo": "~48.0.0-beta.2",
|
|
19
|
+
"expo-font": "~11.1.1",
|
|
20
|
+
"expo-linking": "~4.0.1",
|
|
21
|
+
"expo-splash-screen": "~0.18.1",
|
|
22
|
+
"expo-status-bar": "~1.4.4",
|
|
23
|
+
"expo-system-ui": "~2.2.1",
|
|
24
|
+
"expo-web-browser": "~12.1.1",
|
|
25
|
+
"expo-router": "^1.0.0-rc5",
|
|
30
26
|
"react": "18.2.0",
|
|
31
27
|
"react-dom": "18.2.0",
|
|
32
28
|
"react-native": "0.71.2",
|
package/App.tsx
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { StatusBar } from 'expo-status-bar';
|
|
2
|
-
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
3
|
-
|
|
4
|
-
import useCachedResources from './hooks/useCachedResources';
|
|
5
|
-
import useColorScheme from './hooks/useColorScheme';
|
|
6
|
-
import Navigation from './navigation';
|
|
7
|
-
|
|
8
|
-
export default function App() {
|
|
9
|
-
const isLoadingComplete = useCachedResources();
|
|
10
|
-
const colorScheme = useColorScheme();
|
|
11
|
-
|
|
12
|
-
if (!isLoadingComplete) {
|
|
13
|
-
return null;
|
|
14
|
-
} else {
|
|
15
|
-
return (
|
|
16
|
-
<SafeAreaProvider>
|
|
17
|
-
<Navigation colorScheme={colorScheme} />
|
|
18
|
-
<StatusBar />
|
|
19
|
-
</SafeAreaProvider>
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
}
|
package/constants/Layout.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { FontAwesome } from '@expo/vector-icons';
|
|
2
|
-
import * as Font from 'expo-font';
|
|
3
|
-
import * as SplashScreen from 'expo-splash-screen';
|
|
4
|
-
import { useEffect, useState } from 'react';
|
|
5
|
-
|
|
6
|
-
export default function useCachedResources() {
|
|
7
|
-
const [isLoadingComplete, setLoadingComplete] = useState(false);
|
|
8
|
-
|
|
9
|
-
// Load any resources or data that we need prior to rendering the app
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
async function loadResourcesAndDataAsync() {
|
|
12
|
-
try {
|
|
13
|
-
SplashScreen.preventAutoHideAsync();
|
|
14
|
-
|
|
15
|
-
// Load fonts
|
|
16
|
-
await Font.loadAsync({
|
|
17
|
-
...FontAwesome.font,
|
|
18
|
-
'space-mono': require('../assets/fonts/SpaceMono-Regular.ttf'),
|
|
19
|
-
});
|
|
20
|
-
} catch (e) {
|
|
21
|
-
// We might want to provide this error information to an error reporting service
|
|
22
|
-
console.warn(e);
|
|
23
|
-
} finally {
|
|
24
|
-
setLoadingComplete(true);
|
|
25
|
-
SplashScreen.hideAsync();
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
loadResourcesAndDataAsync();
|
|
30
|
-
}, []);
|
|
31
|
-
|
|
32
|
-
return isLoadingComplete;
|
|
33
|
-
}
|
package/hooks/useColorScheme.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { ColorSchemeName, useColorScheme as _useColorScheme } from 'react-native';
|
|
2
|
-
|
|
3
|
-
// The useColorScheme value is always either light or dark, but the built-in
|
|
4
|
-
// type suggests that it can be null. This will not happen in practice, so this
|
|
5
|
-
// makes it a bit easier to work with.
|
|
6
|
-
export default function useColorScheme(): NonNullable<ColorSchemeName> {
|
|
7
|
-
return _useColorScheme() as NonNullable<ColorSchemeName>;
|
|
8
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Learn more about deep linking with React Navigation
|
|
3
|
-
* https://reactnavigation.org/docs/deep-linking
|
|
4
|
-
* https://reactnavigation.org/docs/configuring-links
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { LinkingOptions } from '@react-navigation/native';
|
|
8
|
-
import * as Linking from 'expo-linking';
|
|
9
|
-
|
|
10
|
-
import { RootStackParamList } from '../types';
|
|
11
|
-
|
|
12
|
-
const linking: LinkingOptions<RootStackParamList> = {
|
|
13
|
-
prefixes: [Linking.createURL('/')],
|
|
14
|
-
config: {
|
|
15
|
-
screens: {
|
|
16
|
-
Root: {
|
|
17
|
-
screens: {
|
|
18
|
-
TabOne: {
|
|
19
|
-
screens: {
|
|
20
|
-
TabOneScreen: 'one',
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
TabTwo: {
|
|
24
|
-
screens: {
|
|
25
|
-
TabTwoScreen: 'two',
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
Modal: 'modal',
|
|
31
|
-
NotFound: '*',
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export default linking;
|
package/navigation/index.tsx
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* If you are not familiar with React Navigation, refer to the "Fundamentals" guide:
|
|
3
|
-
* https://reactnavigation.org/docs/getting-started
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
6
|
-
import { FontAwesome } from '@expo/vector-icons';
|
|
7
|
-
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
|
8
|
-
import { NavigationContainer, DefaultTheme, DarkTheme } from '@react-navigation/native';
|
|
9
|
-
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
|
10
|
-
import * as React from 'react';
|
|
11
|
-
import { ColorSchemeName, Pressable } from 'react-native';
|
|
12
|
-
|
|
13
|
-
import Colors from '../constants/Colors';
|
|
14
|
-
import useColorScheme from '../hooks/useColorScheme';
|
|
15
|
-
import ModalScreen from '../screens/ModalScreen';
|
|
16
|
-
import NotFoundScreen from '../screens/NotFoundScreen';
|
|
17
|
-
import TabOneScreen from '../screens/TabOneScreen';
|
|
18
|
-
import TabTwoScreen from '../screens/TabTwoScreen';
|
|
19
|
-
import { RootStackParamList, RootTabParamList, RootTabScreenProps } from '../types';
|
|
20
|
-
import LinkingConfiguration from './LinkingConfiguration';
|
|
21
|
-
|
|
22
|
-
export default function Navigation({ colorScheme }: { colorScheme: ColorSchemeName }) {
|
|
23
|
-
return (
|
|
24
|
-
<NavigationContainer
|
|
25
|
-
linking={LinkingConfiguration}
|
|
26
|
-
theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
|
27
|
-
<RootNavigator />
|
|
28
|
-
</NavigationContainer>
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* A root stack navigator is often used for displaying modals on top of all other content.
|
|
34
|
-
* https://reactnavigation.org/docs/modal
|
|
35
|
-
*/
|
|
36
|
-
const Stack = createNativeStackNavigator<RootStackParamList>();
|
|
37
|
-
|
|
38
|
-
function RootNavigator() {
|
|
39
|
-
return (
|
|
40
|
-
<Stack.Navigator>
|
|
41
|
-
<Stack.Screen name="Root" component={BottomTabNavigator} options={{ headerShown: false }} />
|
|
42
|
-
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
|
|
43
|
-
<Stack.Group screenOptions={{ presentation: 'modal' }}>
|
|
44
|
-
<Stack.Screen name="Modal" component={ModalScreen} />
|
|
45
|
-
</Stack.Group>
|
|
46
|
-
</Stack.Navigator>
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* A bottom tab navigator displays tab buttons on the bottom of the display to switch screens.
|
|
52
|
-
* https://reactnavigation.org/docs/bottom-tab-navigator
|
|
53
|
-
*/
|
|
54
|
-
const BottomTab = createBottomTabNavigator<RootTabParamList>();
|
|
55
|
-
|
|
56
|
-
function BottomTabNavigator() {
|
|
57
|
-
const colorScheme = useColorScheme();
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<BottomTab.Navigator
|
|
61
|
-
initialRouteName="TabOne"
|
|
62
|
-
screenOptions={{
|
|
63
|
-
tabBarActiveTintColor: Colors[colorScheme].tint,
|
|
64
|
-
}}>
|
|
65
|
-
<BottomTab.Screen
|
|
66
|
-
name="TabOne"
|
|
67
|
-
component={TabOneScreen}
|
|
68
|
-
options={({ navigation }: RootTabScreenProps<'TabOne'>) => ({
|
|
69
|
-
title: 'Tab One',
|
|
70
|
-
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
|
71
|
-
headerRight: () => (
|
|
72
|
-
<Pressable
|
|
73
|
-
onPress={() => navigation.navigate('Modal')}
|
|
74
|
-
style={({ pressed }) => ({
|
|
75
|
-
opacity: pressed ? 0.5 : 1,
|
|
76
|
-
})}>
|
|
77
|
-
<FontAwesome
|
|
78
|
-
name="info-circle"
|
|
79
|
-
size={25}
|
|
80
|
-
color={Colors[colorScheme].text}
|
|
81
|
-
style={{ marginRight: 15 }}
|
|
82
|
-
/>
|
|
83
|
-
</Pressable>
|
|
84
|
-
),
|
|
85
|
-
})}
|
|
86
|
-
/>
|
|
87
|
-
<BottomTab.Screen
|
|
88
|
-
name="TabTwo"
|
|
89
|
-
component={TabTwoScreen}
|
|
90
|
-
options={{
|
|
91
|
-
title: 'Tab Two',
|
|
92
|
-
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
|
93
|
-
}}
|
|
94
|
-
/>
|
|
95
|
-
</BottomTab.Navigator>
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
|
|
101
|
-
*/
|
|
102
|
-
function TabBarIcon(props: {
|
|
103
|
-
name: React.ComponentProps<typeof FontAwesome>['name'];
|
|
104
|
-
color: string;
|
|
105
|
-
}) {
|
|
106
|
-
return <FontAwesome size={30} style={{ marginBottom: -3 }} {...props} />;
|
|
107
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { StyleSheet, TouchableOpacity } from 'react-native';
|
|
2
|
-
|
|
3
|
-
import { Text, View } from '../components/Themed';
|
|
4
|
-
import { RootStackScreenProps } from '../types';
|
|
5
|
-
|
|
6
|
-
export default function NotFoundScreen({ navigation }: RootStackScreenProps<'NotFound'>) {
|
|
7
|
-
return (
|
|
8
|
-
<View style={styles.container}>
|
|
9
|
-
<Text style={styles.title}>This screen doesn't exist.</Text>
|
|
10
|
-
<TouchableOpacity onPress={() => navigation.replace('Root')} style={styles.link}>
|
|
11
|
-
<Text style={styles.linkText}>Go to home screen!</Text>
|
|
12
|
-
</TouchableOpacity>
|
|
13
|
-
</View>
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const styles = StyleSheet.create({
|
|
18
|
-
container: {
|
|
19
|
-
flex: 1,
|
|
20
|
-
alignItems: 'center',
|
|
21
|
-
justifyContent: 'center',
|
|
22
|
-
padding: 20,
|
|
23
|
-
},
|
|
24
|
-
title: {
|
|
25
|
-
fontSize: 20,
|
|
26
|
-
fontWeight: 'bold',
|
|
27
|
-
},
|
|
28
|
-
link: {
|
|
29
|
-
marginTop: 15,
|
|
30
|
-
paddingVertical: 15,
|
|
31
|
-
},
|
|
32
|
-
linkText: {
|
|
33
|
-
fontSize: 14,
|
|
34
|
-
color: '#2e78b7',
|
|
35
|
-
},
|
|
36
|
-
});
|
package/types.tsx
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Learn more about using TypeScript with React Navigation:
|
|
3
|
-
* https://reactnavigation.org/docs/typescript/
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
|
|
7
|
-
import { CompositeScreenProps, NavigatorScreenParams } from '@react-navigation/native';
|
|
8
|
-
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
|
9
|
-
|
|
10
|
-
declare global {
|
|
11
|
-
namespace ReactNavigation {
|
|
12
|
-
interface RootParamList extends RootStackParamList {}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export type RootStackParamList = {
|
|
17
|
-
Root: NavigatorScreenParams<RootTabParamList> | undefined;
|
|
18
|
-
Modal: undefined;
|
|
19
|
-
NotFound: undefined;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type RootStackScreenProps<Screen extends keyof RootStackParamList> = NativeStackScreenProps<
|
|
23
|
-
RootStackParamList,
|
|
24
|
-
Screen
|
|
25
|
-
>;
|
|
26
|
-
|
|
27
|
-
export type RootTabParamList = {
|
|
28
|
-
TabOne: undefined;
|
|
29
|
-
TabTwo: undefined;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export type RootTabScreenProps<Screen extends keyof RootTabParamList> = CompositeScreenProps<
|
|
33
|
-
BottomTabScreenProps<RootTabParamList, Screen>,
|
|
34
|
-
NativeStackScreenProps<RootStackParamList>
|
|
35
|
-
>;
|