Skip to content

Commit

Permalink
Add React Navigation Bottom Tabs (rebased) (#35)
Browse files Browse the repository at this point in the history
* Add reactNavigation, and reactNavigationBottomTabs files into
boilerplate template
* Set up app with bottom tab navigation by default
* Remove addNavigation command and its tests

Rebase of #28.

---------

Co-authored-by: William Larry <[email protected]>
Co-authored-by: Stephen Hanson <[email protected]>
  • Loading branch information
3 people authored Apr 26, 2024
1 parent d644800 commit ab38f6b
Show file tree
Hide file tree
Showing 17 changed files with 168 additions and 104 deletions.
5 changes: 0 additions & 5 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,6 @@ export default function runCli() {
.description('Install and configure Jest and Testing Library')
.action(buildAction(import('./commands/testingLibrary')));

program
.command('navigation')
.description('Install and configure React Navigation')
.action(buildAction(import('./commands/navigation')));

printWelcome();
program.parse();
}
30 changes: 0 additions & 30 deletions src/commands/__tests__/navigation.test.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/commands/createApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export async function createApp(
options: Options = {},
) {
const { interactive = true } = options;

globals.interactive = interactive;

const appName = await validateAndSanitizeAppName(name);
Expand All @@ -38,6 +37,7 @@ export async function createApp(
const spinner = ora('Creating app with Belt').start();

await exec(`mkdir ${appName}`);

await copyTemplateDirectory({
templateDir: 'boilerplate',
destinationDir: appName,
Expand All @@ -59,7 +59,6 @@ export async function createApp(
spinner.start('Installing dependencies');
const packageManager = getPackageManager(options);
await exec(`${packageManager} install`);

await exec('git init');
await commit('Initial commit');
spinner.succeed('Installed dependencies');
Expand Down
30 changes: 0 additions & 30 deletions src/commands/navigation.ts

This file was deleted.

3 changes: 3 additions & 0 deletions templates/boilerplate/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ beforeEach(() => {
jest.clearAllMocks();
});

jest.mock('expo-font');
jest.mock('expo-asset');

jest.mock('react-native-safe-area-context', () => mockSafeAreaContext);

jest.mock('react-native/Libraries/Alert/Alert', () => ({
Expand Down
2 changes: 2 additions & 0 deletions templates/boilerplate/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
"test:all": "npm run lint && npm run test:cov"
},
"dependencies": {
"@expo/vector-icons": "^13.0.0",
"@react-native-async-storage/async-storage": "1.21.0",
"@react-navigation/bottom-tabs": "^6.5.20",
"@react-navigation/native": "^6.1.10",
"@react-navigation/native-stack": "^6.9.18",
"expo": "^50.0.14",
Expand Down
1 change: 1 addition & 0 deletions templates/boilerplate/src/__tests__/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import RootNavigator from 'src/navigators/RootNavigator';
import render from 'src/test/render';

test('renders', async () => {
jest.useFakeTimers();
render(<RootNavigator />);
expect(await screen.findByText(/Open up App.tsx/)).toBeDefined();
});
16 changes: 16 additions & 0 deletions templates/boilerplate/src/navigators/DashboardStack.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import React from 'react';
import HomeScreen from 'src/screens/HomeScreen/HomeScreen';
import InformationScreen from '../screens/InformationScreen/InformationScreen';
import { DashboardTabParamList } from './navigatorTypes';

const Dashboard = createNativeStackNavigator<DashboardTabParamList>();

export default function DashboardStack() {
return (
<Dashboard.Navigator>
<Dashboard.Screen name="Home" component={HomeScreen} />
<Dashboard.Screen name="Information" component={InformationScreen} />
</Dashboard.Navigator>
);
}
26 changes: 22 additions & 4 deletions templates/boilerplate/src/navigators/RootNavigator.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import HomeScreen from 'src/screens/HomeScreen/HomeScreen';
import {
NativeStackNavigationOptions,
createNativeStackNavigator,
} from '@react-navigation/native-stack';
import TabNavigator from './TabNavigator';

const navigatorScreenOptions: NativeStackNavigationOptions = {
headerShadowVisible: false,
};

const Stack = createNativeStackNavigator();

export default function RootNavigator() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Navigator screenOptions={navigatorScreenOptions}>
<Stack.Screen
name="Tabs"
component={TabNavigator}
options={{ headerShown: false }}
/>

{/*
screens that are navigable outside of tabs go here. This can include:
- authentication screens (only render tab navigator conditionally)
- screens that should not display bottom tab bar and that might be
navigated to from a screen from multiple tabs
*/}
</Stack.Navigator>
);
}
50 changes: 50 additions & 0 deletions templates/boilerplate/src/navigators/TabNavigator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import SettingsScreen from '../screens/SettingsScreen/SettingsScreen';
import DashboardStack from './DashboardStack';
import { TabsParamList } from './navigatorTypes';

const Tab = createBottomTabNavigator<TabsParamList>();

function HomeIcon({ focused = false, color = 'gray' }) {
return <MaterialCommunityIcons name="home" color={color} size={26} />;
}

function AccountIcon({ focused = false, color = 'gray' }) {
return (
<MaterialCommunityIcons name="account-circle" color={color} size={26} />
);
}

export default function TabNavigator() {
return (
<Tab.Navigator
screenOptions={{
tabBarLabelPosition: 'below-icon',
tabBarStyle: {
elevation: 0,
backgroundColor: 'transparent',
borderTopColor: '#eee',
borderTopWidth: 1,
paddingBottom: 2,
},
}}
>
<Tab.Screen
name="DashboardTab"
component={DashboardStack}
options={{
headerShown: false,
tabBarIcon: HomeIcon,
}}
/>
<Tab.Screen
name="SettingsTab"
component={SettingsScreen}
options={{
tabBarIcon: AccountIcon,
}}
/>
</Tab.Navigator>
);
}
40 changes: 37 additions & 3 deletions templates/boilerplate/src/navigators/navigatorTypes.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,40 @@
// add types for navigation here
// key: screen name
// value: params (use undefined if accepts none)
import { NavigatorScreenParams } from '@react-navigation/native';
import { NativeStackScreenProps } from '@react-navigation/native-stack';

export type RootStackParamList = {
Tabs: NavigatorScreenParams<TabsParamList>;
};

export type TabsParamList = {
DashboardTab: NavigatorScreenParams<DashboardTabParamList>;
SettingsTab: NavigatorScreenParams<SettingsTabParamList>;
};

export type DashboardTabParamList = {
Home: undefined;
Information: { owner: string } | undefined;
};

export type SettingsTabParamList = {
Settings: undefined;
};

/* ----------------------------------------------------------------
Derived types -- these should not need to be frequently modified
-------------------------------------------------------------*/
export type TabName = keyof TabsParamList;
export type RootRouteName = keyof RootStackParamList;
export type AppRouteName =
| keyof RootStackParamList
| keyof DashboardTabParamList
| keyof SettingsTabParamList;

export type HomeScreenProp = NativeStackScreenProps<
DashboardTabParamList,
'Home'
>;

export type InformationScreenProp = NativeStackScreenProps<
DashboardTabParamList,
'Information'
>;
10 changes: 9 additions & 1 deletion templates/boilerplate/src/screens/HomeScreen/HomeScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { useNavigation } from '@react-navigation/native';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import { Button, StyleSheet, Text, View } from 'react-native';
import { HomeScreenProp } from 'src/navigators/navigatorTypes';

export default function HomeScreen() {
const navigation = useNavigation<HomeScreenProp['navigation']>();

return (
<View style={styles.container}>
<Text>Open up App.tsx to start working on your app!</Text>
<Button
title="Go to information screen"
onPress={() => navigation.navigate('Information', { owner: 'Will' })}
/>
<StatusBar style="auto" />
</View>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useRoute } from '@react-navigation/native';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import { InformationScreenProp } from 'src/navigators/navigatorTypes';

export default function InformationScreen() {
const { params } = useRoute<InformationScreenProp['route']>();

return (
<View style={styles.container}>
<Text>Information Screen</Text>
{params && <Text>{params.owner}’s Profile</Text>}
<StatusBar style="auto" />
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';

export default function HomeScreen() {
export default function SettingsScreen() {
return (
<View style={styles.container}>
<Text>Open up App.tsx to start working on your app!</Text>
<Text>Settings Screen</Text>
<StatusBar style="auto" />
</View>
);
Expand Down
12 changes: 0 additions & 12 deletions templates/reactNavigation/src/navigators/RootNavigator.tsx

This file was deleted.

6 changes: 0 additions & 6 deletions templates/reactNavigation/src/navigators/navigatorTypes.tsx

This file was deleted.

9 changes: 0 additions & 9 deletions templates/reactNavigation/src/types/global.d.ts

This file was deleted.

0 comments on commit ab38f6b

Please sign in to comment.