mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-24 04:25:34 +08:00
chore: setup monorepo with yarn workspaces (#38)
This commit is contained in:
committed by
Michał Osadnik
parent
0d68f1ed59
commit
ce7d163073
4
packages/example/.expo-shared/assets.json
Normal file
4
packages/example/.expo-shared/assets.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"f9155ac790fd02fadcdeca367b02581c04a353aa6d5aa84409a59f6804c87acd": true,
|
||||
"89ed26367cdb9b771858e026f2eb95bfdb90e5ae943e716575327ec325f39c44": true
|
||||
}
|
||||
1
packages/example/App.tsx
Normal file
1
packages/example/App.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './src/index';
|
||||
30
packages/example/app.json
Normal file
30
packages/example/app.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "@navigation-ex/example",
|
||||
"slug": "navigation-ex-example",
|
||||
"privacy": "public",
|
||||
"sdkVersion": "34.0.0",
|
||||
"platforms": [
|
||||
"ios",
|
||||
"android",
|
||||
"web"
|
||||
],
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"splash": {
|
||||
"image": "./assets/splash.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"updates": {
|
||||
"fallbackToCacheTimeout": 0
|
||||
},
|
||||
"assetBundlePatterns": [
|
||||
"**/*"
|
||||
],
|
||||
"ios": {
|
||||
"supportsTablet": true
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
packages/example/assets/icon.png
Normal file
BIN
packages/example/assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
packages/example/assets/splash.png
Normal file
BIN
packages/example/assets/splash.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.0 KiB |
9
packages/example/babel.config.js
Normal file
9
packages/example/babel.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
/* eslint-env node */
|
||||
|
||||
module.exports = function(api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: ['babel-preset-expo'],
|
||||
};
|
||||
};
|
||||
46
packages/example/metro.config.js
Normal file
46
packages/example/metro.config.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/* eslint-disable import/no-commonjs, import/no-extraneous-dependencies */
|
||||
/* eslint-env node */
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const escape = require('escape-string-regexp');
|
||||
const blacklist = require('metro-config/src/defaults/blacklist');
|
||||
|
||||
module.exports = {
|
||||
projectRoot: __dirname,
|
||||
watchFolders: [path.resolve(__dirname, '..', '..')],
|
||||
|
||||
resolver: {
|
||||
blacklistRE: blacklist(
|
||||
[
|
||||
...fs
|
||||
.readdirSync(path.resolve(__dirname, '..'))
|
||||
.filter(d => d !== 'example'),
|
||||
'..',
|
||||
].map(
|
||||
it =>
|
||||
new RegExp(
|
||||
`^${escape(
|
||||
path.resolve(__dirname, '..', it, 'node_modules')
|
||||
)}\\/.*$`
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
providesModuleNodeModules: [
|
||||
'@babel/runtime',
|
||||
'react',
|
||||
'react-native',
|
||||
'shortid',
|
||||
],
|
||||
},
|
||||
|
||||
transformer: {
|
||||
getTransformOptions: async () => ({
|
||||
transform: {
|
||||
experimentalImportSupport: false,
|
||||
inlineRequires: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
41
packages/example/package.json
Normal file
41
packages/example/package.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "@navigation-ex/example",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"nohoist": [
|
||||
"*",
|
||||
"*/**"
|
||||
]
|
||||
},
|
||||
"main": "node_modules/expo/AppEntry.js",
|
||||
"scripts": {
|
||||
"start": "expo start",
|
||||
"android": "expo start --android",
|
||||
"ios": "expo start --ios",
|
||||
"web": "expo start --web",
|
||||
"eject": "expo eject"
|
||||
},
|
||||
"dependencies": {
|
||||
"expo": "^34.0.1",
|
||||
"react": "16.8.3",
|
||||
"react-dom": "^16.8.3",
|
||||
"react-native": "https://github.com/expo/react-native/archive/sdk-34.0.0.tar.gz",
|
||||
"react-native-paper": "3.0.0-alpha.3",
|
||||
"react-native-web": "^0.11.4",
|
||||
"scheduler": "^0.14.0",
|
||||
"shortid": "^2.2.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.5",
|
||||
"@expo/webpack-config": "^0.7.0",
|
||||
"@types/react": "^16.8.23",
|
||||
"@types/react-native": "^0.57.65",
|
||||
"babel-preset-expo": "^6.0.0",
|
||||
"expo-cli": "^3.0.6"
|
||||
},
|
||||
"resolutions": {
|
||||
"react": "16.8.3",
|
||||
"react-dom": "^16.8.3"
|
||||
}
|
||||
}
|
||||
105
packages/example/src/StackNavigator.tsx
Normal file
105
packages/example/src/StackNavigator.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
/* eslint-disable react-native/no-inline-styles */
|
||||
|
||||
import * as React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import {
|
||||
useNavigationBuilder,
|
||||
NavigationProp,
|
||||
ParamListBase,
|
||||
createNavigator,
|
||||
} from '@navigation-ex/core';
|
||||
import {
|
||||
StackRouter,
|
||||
StackRouterOptions,
|
||||
StackNavigationState,
|
||||
} from '@navigation-ex/routers';
|
||||
|
||||
type Props = StackRouterOptions & {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export type StackNavigationOptions = {
|
||||
/**
|
||||
* Title text for the screen.
|
||||
*/
|
||||
title?: string;
|
||||
};
|
||||
|
||||
export type StackNavigationProp<
|
||||
ParamList extends ParamListBase,
|
||||
RouteName extends keyof ParamList = string
|
||||
> = NavigationProp<
|
||||
ParamList,
|
||||
RouteName,
|
||||
StackNavigationState,
|
||||
StackNavigationOptions
|
||||
> & {
|
||||
/**
|
||||
* Push a new screen onto the stack.
|
||||
*
|
||||
* @param name Name of the route for the tab.
|
||||
* @param [params] Params object for the route.
|
||||
*/
|
||||
push<RouteName extends keyof ParamList>(
|
||||
...args: ParamList[RouteName] extends void
|
||||
? [RouteName]
|
||||
: [RouteName, ParamList[RouteName]]
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Pop a screen from the stack.
|
||||
*/
|
||||
pop(count?: number): void;
|
||||
|
||||
/**
|
||||
* Pop to the first route in the stack, dismissing all other screens.
|
||||
*/
|
||||
popToTop(): void;
|
||||
};
|
||||
|
||||
export function StackNavigator(props: Props) {
|
||||
const { state, descriptors } = useNavigationBuilder<
|
||||
StackNavigationState,
|
||||
StackNavigationOptions,
|
||||
StackRouterOptions
|
||||
>(StackRouter, props);
|
||||
|
||||
return (
|
||||
<View>
|
||||
{state.routes.map((route, i) => (
|
||||
<View
|
||||
key={route.key}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
margin: 20,
|
||||
left: i * 20,
|
||||
top: i * 20,
|
||||
padding: 10,
|
||||
height: 480,
|
||||
width: 320,
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 3,
|
||||
}}
|
||||
>
|
||||
{descriptors[route.key].render()}
|
||||
</View>
|
||||
))}
|
||||
<View
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: 40,
|
||||
width: 120,
|
||||
padding: 10,
|
||||
backgroundColor: 'tomato',
|
||||
borderRadius: 3,
|
||||
}}
|
||||
>
|
||||
<Text>{descriptors[state.routes[state.index].key].options.title}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export default createNavigator<StackNavigationOptions, typeof StackNavigator>(
|
||||
StackNavigator
|
||||
);
|
||||
78
packages/example/src/TabNavigator.tsx
Normal file
78
packages/example/src/TabNavigator.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
/* eslint-disable react-native/no-inline-styles */
|
||||
|
||||
import * as React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import {
|
||||
useNavigationBuilder,
|
||||
NavigationProp,
|
||||
ParamListBase,
|
||||
createNavigator,
|
||||
} from '@navigation-ex/core';
|
||||
import {
|
||||
TabRouter,
|
||||
TabRouterOptions,
|
||||
TabNavigationState,
|
||||
} from '@navigation-ex/routers';
|
||||
|
||||
type Props = TabRouterOptions & {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export type TabNavigationOptions = {
|
||||
/**
|
||||
* Title text for the screen.
|
||||
*/
|
||||
title?: string;
|
||||
};
|
||||
|
||||
export type TabNavigationProp<
|
||||
ParamList extends ParamListBase,
|
||||
RouteName extends keyof ParamList = string
|
||||
> = NavigationProp<
|
||||
ParamList,
|
||||
RouteName,
|
||||
TabNavigationState,
|
||||
TabNavigationOptions
|
||||
> & {
|
||||
/**
|
||||
* Jump to an existing tab.
|
||||
*
|
||||
* @param name Name of the route for the tab.
|
||||
* @param [params] Params object for the route.
|
||||
*/
|
||||
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
|
||||
...args: ParamList[RouteName] extends void
|
||||
? [RouteName]
|
||||
: [RouteName, ParamList[RouteName]]
|
||||
): void;
|
||||
};
|
||||
|
||||
export function TabNavigator(props: Props) {
|
||||
const { state, descriptors } = useNavigationBuilder<
|
||||
TabNavigationState,
|
||||
TabNavigationOptions,
|
||||
TabRouterOptions
|
||||
>(TabRouter, props);
|
||||
|
||||
return (
|
||||
<View style={{ display: 'flex', flexDirection: 'row', height: '100%' }}>
|
||||
{state.routes.map((route, i, self) => (
|
||||
<View
|
||||
key={route.key}
|
||||
style={{
|
||||
width: `${100 / self.length}%`,
|
||||
padding: 10,
|
||||
borderRadius: 3,
|
||||
backgroundColor: i === state.index ? 'tomato' : 'white',
|
||||
}}
|
||||
>
|
||||
{descriptors[route.key].render()}
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export default createNavigator<TabNavigationOptions, typeof TabNavigator>(
|
||||
TabNavigator
|
||||
);
|
||||
211
packages/example/src/index.tsx
Normal file
211
packages/example/src/index.tsx
Normal file
@@ -0,0 +1,211 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
Platform,
|
||||
AsyncStorage,
|
||||
YellowBox,
|
||||
StyleSheet,
|
||||
} from 'react-native';
|
||||
import { Button } from 'react-native-paper';
|
||||
import {
|
||||
NavigationContainer,
|
||||
CompositeNavigationProp,
|
||||
NavigationHelpers,
|
||||
RouteProp,
|
||||
InitialState,
|
||||
useFocusEffect,
|
||||
} from '@navigation-ex/core';
|
||||
import createStackNavigator, { StackNavigationProp } from './StackNavigator';
|
||||
import createTabNavigator, { TabNavigationProp } from './TabNavigator';
|
||||
|
||||
type StackParamList = {
|
||||
first: { author: string };
|
||||
second: undefined;
|
||||
third: undefined;
|
||||
};
|
||||
|
||||
type TabParamList = {
|
||||
fourth: undefined;
|
||||
fifth: undefined;
|
||||
};
|
||||
|
||||
YellowBox.ignoreWarnings(['Require cycle:', 'Warning: Async Storage']);
|
||||
|
||||
const Stack = createStackNavigator<StackParamList>();
|
||||
|
||||
const Tab = createTabNavigator<TabParamList>();
|
||||
|
||||
const First = ({
|
||||
navigation,
|
||||
route,
|
||||
}: {
|
||||
navigation: CompositeNavigationProp<
|
||||
StackNavigationProp<StackParamList, 'first'>,
|
||||
NavigationHelpers<TabParamList>
|
||||
>;
|
||||
route: RouteProp<StackParamList, 'first'>;
|
||||
}) => {
|
||||
const updateTitle = React.useCallback(() => {
|
||||
if (Platform.OS !== 'web') {
|
||||
return;
|
||||
}
|
||||
|
||||
document.title = `${route.name} (${route.params.author})`;
|
||||
|
||||
return () => {
|
||||
document.title = '';
|
||||
};
|
||||
}, [route.name, route.params.author]);
|
||||
|
||||
useFocusEffect(updateTitle);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text style={styles.title}>First, {route.params.author}</Text>
|
||||
<Button onPress={() => navigation.push('second')}>Push second</Button>
|
||||
<Button onPress={() => navigation.push('third')}>Push third</Button>
|
||||
<Button onPress={() => navigation.navigate('fourth')}>
|
||||
Navigate to fourth
|
||||
</Button>
|
||||
<Button onPress={() => navigation.navigate('first', { author: 'John' })}>
|
||||
Navigate with params
|
||||
</Button>
|
||||
<Button onPress={() => navigation.pop()}>Pop</Button>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const Second = ({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: CompositeNavigationProp<
|
||||
StackNavigationProp<StackParamList, 'second'>,
|
||||
NavigationHelpers<TabParamList>
|
||||
>;
|
||||
}) => {
|
||||
const [count, setCount] = React.useState(0);
|
||||
|
||||
React.useEffect(() => {
|
||||
const timer = setInterval(() => setCount(c => c + 1), 1000);
|
||||
|
||||
return () => clearInterval(timer);
|
||||
}, []);
|
||||
|
||||
navigation.setOptions({
|
||||
title: `Count ${count}`,
|
||||
});
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text style={styles.title}>Second</Text>
|
||||
<Button onPress={() => navigation.push('first', { author: 'Joel' })}>
|
||||
Push first
|
||||
</Button>
|
||||
<Button onPress={() => navigation.pop()}>Pop</Button>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const Fourth = ({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: CompositeNavigationProp<
|
||||
TabNavigationProp<TabParamList, 'fourth'>,
|
||||
StackNavigationProp<StackParamList>
|
||||
>;
|
||||
}) => (
|
||||
<View>
|
||||
<Text style={styles.title}>Fourth</Text>
|
||||
<Button onPress={() => navigation.jumpTo('fifth')}>Jump to fifth</Button>
|
||||
<Button onPress={() => navigation.push('first', { author: 'Jake' })}>
|
||||
Push first
|
||||
</Button>
|
||||
<Button onPress={() => navigation.goBack()}>Go back</Button>
|
||||
</View>
|
||||
);
|
||||
|
||||
const Fifth = ({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: CompositeNavigationProp<
|
||||
TabNavigationProp<TabParamList, 'fifth'>,
|
||||
StackNavigationProp<StackParamList>
|
||||
>;
|
||||
}) => (
|
||||
<View>
|
||||
<Text style={styles.title}>Fifth</Text>
|
||||
<Button onPress={() => navigation.jumpTo('fourth')}>Jump to fourth</Button>
|
||||
<Button onPress={() => navigation.push('second')}>Push second</Button>
|
||||
<Button onPress={() => navigation.pop()}>Pop</Button>
|
||||
</View>
|
||||
);
|
||||
|
||||
const PERSISTENCE_KEY = 'NAVIGATION_STATE';
|
||||
|
||||
export default function App() {
|
||||
const [isReady, setIsReady] = React.useState(false);
|
||||
const [initialState, setInitialState] = React.useState<
|
||||
InitialState | undefined
|
||||
>();
|
||||
|
||||
React.useEffect(() => {
|
||||
AsyncStorage.getItem(PERSISTENCE_KEY).then(
|
||||
data => {
|
||||
try {
|
||||
const result = JSON.parse(data || '');
|
||||
|
||||
if (result) {
|
||||
setInitialState(result);
|
||||
}
|
||||
} finally {
|
||||
setIsReady(true);
|
||||
}
|
||||
},
|
||||
() => setIsReady(true)
|
||||
);
|
||||
}, []);
|
||||
|
||||
if (!isReady) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<NavigationContainer
|
||||
initialState={initialState}
|
||||
onStateChange={state =>
|
||||
AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state))
|
||||
}
|
||||
>
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen
|
||||
name="first"
|
||||
component={First}
|
||||
options={({ route }) => ({
|
||||
title: `Foo (${route.params ? route.params.author : ''})`,
|
||||
})}
|
||||
initialParams={{ author: 'Jane' }}
|
||||
/>
|
||||
<Stack.Screen name="second" options={{ title: 'Bar' }}>
|
||||
{props => <Second {...props} />}
|
||||
</Stack.Screen>
|
||||
<Stack.Screen name="third" options={{ title: 'Baz' }}>
|
||||
{() => (
|
||||
<Tab.Navigator initialRouteName="fifth">
|
||||
<Tab.Screen name="fourth" component={Fourth} />
|
||||
<Tab.Screen name="fifth" component={Fifth} />
|
||||
</Tab.Navigator>
|
||||
)}
|
||||
</Stack.Screen>
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
title: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 8,
|
||||
},
|
||||
});
|
||||
17
packages/example/webpack.config.js
Normal file
17
packages/example/webpack.config.js
Normal file
@@ -0,0 +1,17 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
/* eslint-env node */
|
||||
|
||||
const createExpoWebpackConfigAsync = require('@expo/webpack-config');
|
||||
|
||||
module.exports = async function(env, argv) {
|
||||
const config = await createExpoWebpackConfigAsync(env, argv);
|
||||
|
||||
config.module.rules.push({
|
||||
test: /@navigation-ex/,
|
||||
use: 'babel-loader',
|
||||
});
|
||||
|
||||
config.resolve.alias['react'] = require.resolve('react');
|
||||
|
||||
return config;
|
||||
};
|
||||
Reference in New Issue
Block a user