Skip to content

Commit

Permalink
Merge pull request #28 from kanzitelli/navio
Browse files Browse the repository at this point in the history
`rn-navio` integration
  • Loading branch information
kanzitelli committed Oct 1, 2022
2 parents b2abd07 + 7ad41f2 commit ad76e27
Show file tree
Hide file tree
Showing 20 changed files with 328 additions and 453 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ web-build/
.DS_Store

*.env
.eas.json
eas.json
_scripts/
.expo
media/
Expand Down
27 changes: 17 additions & 10 deletions App.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
import 'expo-dev-client';
import React, {useCallback, useEffect, useState} from 'react';
import * as SplashScreen from 'expo-splash-screen';
import {LogBox} from 'react-native';
import * as SplashScreen from 'expo-splash-screen';
import {GestureHandlerRootView} from 'react-native-gesture-handler';

import {AppRoot} from './src/screens';
import {configureDesignSystem} from './src/utils/designSystem';
import {
configureDesignSystem,
getNavigationTheme,
getStatusBarBGColor,
getStatusBarStyle,
} from './src/utils/designSystem';
import {hydrateStores} from './src/stores';
import {initServices} from './src/services';
import {AppearanceProvider, SSProvider} from './src/utils/providers';
import {SSProvider} from './src/utils/providers';
import {StatusBar} from 'expo-status-bar';
import {useAppearance} from './src/utils/hooks';

LogBox.ignoreLogs(['Require']);

export default (): JSX.Element => {
useAppearance();
const [ready, setReady] = useState(false);

const startApp = useCallback(async () => {
const start = useCallback(async () => {
await SplashScreen.preventAutoHideAsync();

await hydrateStores();
Expand All @@ -27,16 +35,15 @@ export default (): JSX.Element => {
}, []);

useEffect(() => {
startApp();
}, [startApp]);
start();
}, [start]);

if (!ready) <></>;
if (!ready) return <></>;
return (
<GestureHandlerRootView style={{flex: 1}}>
<SSProvider>
<AppearanceProvider>
<AppRoot />
</AppearanceProvider>
<StatusBar style={getStatusBarStyle()} backgroundColor={getStatusBarBGColor()} />
<AppRoot navigationContainerProps={{theme: getNavigationTheme()}} />
</SSProvider>
</GestureHandlerRootView>
);
Expand Down
114 changes: 66 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ yarn start

- [Expo SDK](https://github.com/expo/expo) - a set of tools and services built around React Native and native platforms.
- [React Navigation (v6)](https://github.com/react-navigation/react-navigation) - routing and navigation for React Native apps.
- [Navio](https://github.com/kanzitelli/rn-navio) - universal navigation library for React Native. Built on top of [React Navigation](https://github.com/react-navigation/react-navigation).
- [RN UI lib](https://github.com/wix/react-native-ui-lib) - amazing Design System, UI toolset & components library for React Native. Dark Mode is implemented using this library.
- [Reanimated 2](https://github.com/software-mansion/react-native-reanimated) - React Native's Animated library reimplemented.
- [MobX](https://github.com/mobxjs/mobx) - simple, scalable state management, with [mobx-persist-store](https://github.com/quarrant/mobx-persist-store) for persisting your stores.
- [Flash List](https://github.com/Shopify/flash-list) - a better list for React Native (by Shopify).
- [React Native Gesture Handler](https://github.com/kmagiera/react-native-gesture-handler) - native touches and gesture system for React Native.

#### Recommended libraries
#### Native libraries

In order to use them, you will need to run `yarn prebuild` command to generate `ios/` and `android/` folders with native code.

Expand All @@ -60,7 +61,7 @@ In order to use them, you will need to run `yarn prebuild` command to generate `

#### Useful services/methods

- `nav` - a service where some of navigation configuration takes place in (such as default options).
- `navio` - a service that exposes all navigation methods of [Navio](https://github.com/kanzitelli/rn-navio) instance.
- `translate` - a service that brings an easy integration of localization for an app by using [i18n-js](https://github.com/fnando/i18n-js) and [expo-localization](https://github.com/expo/expo/tree/master/packages/expo-localization).
- `api` - a service where API-related methods are located.
- `onStart` - a service where you can write your own logic when app is launched. For example, you can increment number of `appLaunches` there.
Expand All @@ -75,67 +76,83 @@ https://user-images.githubusercontent.com/4402166/191781571-57749464-982b-4d36-b

## Advantages

#### Describe app screens in one place
#### Describe app layout in one place (w/ [Navio](https://github.com/kanzitelli/rn-navio))

All setup for your screens, tabs and modals take place in one file `src/screens/index.ts`:
All setup for your screens, tabs and modals take place in one file `src/screens/index.ts`.

```tsx
const screens: ScreensInfo = {
Main: {
component: Main,
options: () => ({
title: 'Main',
...screenDefaultOptions(),
}),
import {Navio} from 'rn-navio';

// importing screen components
import {Main} from './main';
import {Playground} from './playground';
import {Settings} from './settings';
import {Example} from './_screen-sample';

// building layout
export const navio = Navio.build({
screens: {
Main,
Settings,
Example,
Playground: {
component: Playground,
options: () => ({
title: 'Playground',
}),
},
},
// ...
};
const HomeStack = () => <Stack screens={pick(screens, ['Main', 'Example'])} />;

const tabs: TabsInfo = {
HomeTab: {
component: HomeStack,
options: () => ({
title: 'Home',
...tabBarDefaultOptions('HomeTab'),
}),
stacks: {
MainStack: ['Main', 'Example'],
ExampleStack: ['Example'],
},
};
```

#### Build layouts with ease

Stack Navigator:

```tsx
const HomeStack = () => <Stack screens={pick(screens, ['Main', 'Example'])} />;
```

Tab Navigator:

```tsx
const AppTabs = () => <Tabs tabs={tabs} />;
```

Root:
tabs: {
MainTab: {
stack: 'MainStack',
options: {
title: 'Home',
},
},
PlaygroundTab: {
stack: ['Playground'],
options: () => ({
title: 'Playground',
}),
},
SettingsTab: {
stack: ['Settings'],
options: () => ({
title: 'Settings',
}),
},
},
modals: {
ExampleModal: 'ExampleStack',
},
root: 'Tabs',
hooks: [useAppearance],
options: {
stack: screenDefaultOptions,
tab: tabDefaultOptions,
},
});

```tsx
const AppRoot = () => <Root tabs={tabs} modals={modals} />;
export const AppRoot = navio.Root;
```

#### Navigate to other screens with predictability
#### Navigate with predictability

```tsx
const Screen = ({componentId}) => {
const {nav} = useServices();
export const Screen = () => {
const {navio} = useServices();

return (
<View>
<Button
label="Open Settings"
label="Push Settings"
onPress={() => {
// IDE will autocomplete with registered screens
nav.push('Settings');
// Typescript and IDE will help with autocompletion
navio.push('Settings');
}}
/>
</View>
Expand All @@ -156,6 +173,7 @@ So you have one structure within the project. You can find them in corresponding
There are still some things I would like to add to the starter:

- [x] Auth flow [example](https://github.com/kanzitelli/expo-starter/issues/14#issuecomment-1020730141)
- [x] [Navigation library](https://github.com/kanzitelli/rn-navio) to reduce boilerplate code.
- [ ] Shared transitions

Feel free to open an issue for suggestions.
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"pub:web": "npx expo export:web && cd web-build && vercel --prod && cd ..",
"pub:app:prod": "eas update --branch production",
"pub:app:dev": "eas update --branch development",
"pub:config": "eas update:configure",
"pub:all": "yarn pub:app:dev && yarn pub:web",
"format": "prettier --check ./src",
"format:write": "prettier --write ./src",
Expand All @@ -40,7 +41,7 @@
"expo-localization": "~13.1.0",
"expo-splash-screen": "~0.16.2",
"expo-status-bar": "~1.4.0",
"expo-updates": "~0.14.5",
"expo-updates": "~0.14.6",
"formik": "^2.2.9",
"i18n-js": "^4.1.1",
"lodash": "^4.17.21",
Expand All @@ -49,7 +50,7 @@
"mobx-react": "^7.5.3",
"react": "18.0.0",
"react-dom": "18.0.0",
"react-native": "0.69.5",
"react-native": "0.69.6",
"react-native-fast-image": "^8.6.1",
"react-native-gesture-handler": "~2.5.0",
"react-native-mmkv": "^2.4.3",
Expand All @@ -59,6 +60,7 @@
"react-native-ui-lib": "^6.21.2",
"react-native-web": "~0.18.7",
"rn-bounceable": "^1.2.0",
"rn-navio": "^0.0.1",
"yup": "^0.32.11"
},
"devDependencies": {
Expand Down
49 changes: 36 additions & 13 deletions src/screens/_screen-sample.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,65 @@
import React from 'react';
import React, {useEffect} from 'react';
import {ScrollView} from 'react-native';
import {View} from 'react-native-ui-lib';
import {observer} from 'mobx-react';
import {useNavigation} from '@react-navigation/native';
import {NavioScreen} from 'rn-navio';

import {useServices} from '../services';
import {services, useServices} from '../services';
// import {useStores} from '../stores';
import {Section} from '../components/section';
import {BButton} from '../components/button';
import {useAppearance} from '../utils/hooks';

export type Props = {
type?: 'push' | 'show';
type?: 'push';
};
export const Example: React.FC<Props> = observer(({type = 'push'}) => {

export const Example: NavioScreen<Props> = observer(({type = 'push'}) => {
useAppearance(); // for Dark Mode
const {nav, t} = useServices();
const navigation = useNavigation();
const {t, navio} = useServices();
// const {ui} = useStores();

// State

// Methods
const push = () => nav.push('Example');
const show = () => nav.show('ExampleModal');
const goBack = async () => {
nav.pop();
const push = () => navio.push('Example', {type: 'push'});
const pushStack = () => navio.pushStack('ExampleStack');
const jumpTo = () => navio.jumpTo('PlaygroundTab');
const show = () => navio.show('ExampleModal');
const setRoot = () => navio.setRoot('Tabs');
const goBack = () => navio.pop();

// Start
useEffect(() => {
configureUI();
}, []);

// UI Methods
const configureUI = () => {
navigation.setOptions({});
};

// UI Methods

return (
<View flex bg-bgColor>
<ScrollView contentInsetAdjustmentBehavior="always">
<Section title={t.do('section.navigation.title')}>
<BButton marginV-s1 label={t.do('section.navigation.button.push')} onPress={push} />
<BButton marginV-s1 label={t.do('section.navigation.button.show')} onPress={show} />
<BButton marginV-s1 label={t.do('section.navigation.button.back')} onPress={goBack} />
<Section title={t.do('section.navio.title')}>
<BButton marginV-s1 label={t.do('section.navio.button.push')} onPress={push} />
<BButton marginV-s1 label={t.do('section.navio.button.push_stack')} onPress={pushStack} />
<BButton marginV-s1 label={t.do('section.navio.button.jump_to')} onPress={jumpTo} />
<BButton marginV-s1 label={t.do('section.navio.button.show')} onPress={show} />
<BButton marginV-s1 label={t.do('section.navio.button.back')} onPress={goBack} />
<BButton marginV-s1 label={'Set Root - Tabs'} onPress={setRoot} />
</Section>
</ScrollView>
</View>
);
});

Example.options = props => ({
headerBackTitleStyle: false,
title: `${services.t.do('example.title')} ${(props?.route?.params as Props)?.type ?? ''}`,
});

0 comments on commit ad76e27

Please sign in to comment.