mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-01-12 09:24:23 +08:00
chore: setup monorepo with yarn workspaces (#38)
This commit is contained in:
committed by
Michał Osadnik
parent
0d68f1ed59
commit
ce7d163073
16
.babelrc
16
.babelrc
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"useBuiltIns": "usage",
|
||||
"corejs": 3
|
||||
}
|
||||
],
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-typescript"
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-class-properties"
|
||||
]
|
||||
}
|
||||
@@ -2,4 +2,5 @@ node_modules/
|
||||
coverage/
|
||||
dist/
|
||||
lib/
|
||||
types/
|
||||
web-build/
|
||||
web-report/
|
||||
|
||||
11
.eslintrc
11
.eslintrc
@@ -1,11 +0,0 @@
|
||||
{
|
||||
extends: 'satya164',
|
||||
settings: {
|
||||
react: {
|
||||
version: '16'
|
||||
}
|
||||
},
|
||||
env: {
|
||||
browser: true
|
||||
}
|
||||
}
|
||||
8
.eslintrc.json
Normal file
8
.eslintrc.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "satya164",
|
||||
"settings": {
|
||||
"react": { "version": "16" },
|
||||
"import/core-modules": ["@navigation-ex/core", "@navigation-ex/routers"]
|
||||
},
|
||||
"env": { "browser": true }
|
||||
}
|
||||
15
.gitignore
vendored
15
.gitignore
vendored
@@ -2,9 +2,22 @@
|
||||
.cache
|
||||
.vscode
|
||||
.idea
|
||||
.expo
|
||||
|
||||
/coverage/
|
||||
/types/
|
||||
/lib/
|
||||
/dist/
|
||||
/node_modules/
|
||||
|
||||
node_modules/
|
||||
web-build/
|
||||
web-report/
|
||||
|
||||
npm-debug.*
|
||||
|
||||
*.jks
|
||||
*.p8
|
||||
*.p12
|
||||
*.key
|
||||
*.mobileprovision
|
||||
*.orig.*
|
||||
|
||||
1
.watchmanconfig
Normal file
1
.watchmanconfig
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
17
babel.config.js
Normal file
17
babel.config.js
Normal file
@@ -0,0 +1,17 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
/* eslint-env node */
|
||||
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
useBuiltIns: 'usage',
|
||||
corejs: 3,
|
||||
},
|
||||
],
|
||||
'@babel/preset-react',
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
plugins: ['@babel/plugin-proposal-class-properties'],
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
<style type="text/css">
|
||||
html {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
*:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
*:focus-visible {
|
||||
outline: auto;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
background-color: #E2E1E0;
|
||||
}
|
||||
</style>
|
||||
<div id="root"></div>
|
||||
<script src="./index.tsx"></script>
|
||||
67
package.json
67
package.json
@@ -1,16 +1,20 @@
|
||||
{
|
||||
"name": "navigation-ex",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"description": "Rethinking navigation",
|
||||
"keywords": [],
|
||||
"types": "types/index.d.ts",
|
||||
"main": "lib/index.js",
|
||||
"files": [
|
||||
"lib/",
|
||||
"types/",
|
||||
"index.d.ts"
|
||||
],
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"nohoist": [
|
||||
"**/expo",
|
||||
"**/expo/**",
|
||||
"**/react-native",
|
||||
"**/react-native/**"
|
||||
]
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -21,48 +25,25 @@
|
||||
"lint": "eslint --ext '.js,.ts,.tsx' .",
|
||||
"typescript": "tsc --noEmit",
|
||||
"test": "jest",
|
||||
"prebuild": "del lib/ types/",
|
||||
"babel": "babel src --out-dir lib --ignore '**/__tests__/**' --source-maps",
|
||||
"declarations": "tsc --declaration --emitDeclarationOnly --outDir types",
|
||||
"build": "yarn babel && yarn declarations",
|
||||
"example": "parcel example/index.html",
|
||||
"prepare": "yarn build",
|
||||
"release": "release-it"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.1.3",
|
||||
"shortid": "^2.2.14"
|
||||
"example": "yarn --cwd packages/example"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.4.4",
|
||||
"@babel/core": "^7.4.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.5.0",
|
||||
"@babel/preset-env": "^7.4.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.5.5",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/preset-typescript": "^7.3.3",
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"@commitlint/config-conventional": "^8.0.0",
|
||||
"@release-it/conventional-changelog": "^1.1.0",
|
||||
"@types/jest": "^24.0.13",
|
||||
"@types/react": "^16.8.19",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"@types/shortid": "^0.0.29",
|
||||
"codecov": "^3.5.0",
|
||||
"commitlint": "^8.0.0",
|
||||
"core-js": "^3.1.4",
|
||||
"del-cli": "^2.0.0",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-satya164": "^2.4.1",
|
||||
"husky": "^2.4.0",
|
||||
"jest": "^24.8.0",
|
||||
"parcel": "^1.12.3",
|
||||
"prettier": "^1.18.2",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-native-testing-library": "^1.9.1",
|
||||
"react-test-renderer": "^16.8.6",
|
||||
"release-it": "^12.3.0",
|
||||
"typescript": "^3.5.1"
|
||||
},
|
||||
"husky": {
|
||||
@@ -73,14 +54,12 @@
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "node",
|
||||
"modulePathIgnorePatterns": [
|
||||
"<rootDir>/types/",
|
||||
"<rootDir>/lib/"
|
||||
],
|
||||
"testRegex": "/__tests__/.*\\.(test|spec)\\.(js|tsx?)$",
|
||||
"transform": {
|
||||
"^.+\\.(js|ts|tsx)$": "babel-jest"
|
||||
},
|
||||
"setupFiles": ["<rootDir>/jest/setup.js"]
|
||||
"setupFiles": [
|
||||
"<rootDir>/jest/setup.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
20
packages/core/package.json
Normal file
20
packages/core/package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "@navigation-ex/core",
|
||||
"version": "0.0.1",
|
||||
"main": "src/index",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"shortid": "^2.2.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.4.5",
|
||||
"react": "^16.8.3",
|
||||
"react-native-testing-library": "^1.9.1",
|
||||
"react-test-renderer": "^16.8.3",
|
||||
"@types/react": "^16.8.19",
|
||||
"@types/shortid": "^0.0.29"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.3"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import useNavigation from './useNavigation';
|
||||
|
||||
type EffectCallback = (() => undefined) | (() => () => void);
|
||||
type EffectCallback = (() => void) | (() => () => void);
|
||||
|
||||
/**
|
||||
* Hook to an effect in a focused screen, similar to `React.useEffect`.
|
||||
@@ -15,7 +15,7 @@ export default function useFocusEffect(callback: EffectCallback) {
|
||||
|
||||
React.useEffect(() => {
|
||||
let isFocused = false;
|
||||
let cleanup: (() => void) | undefined;
|
||||
let cleanup: (() => void) | void;
|
||||
|
||||
// We need to run the effect on intial render/dep changes if the screen is focused
|
||||
if (navigation.isFocused()) {
|
||||
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
|
||||
);
|
||||
@@ -1,5 +1,13 @@
|
||||
import * as React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
Platform,
|
||||
AsyncStorage,
|
||||
YellowBox,
|
||||
StyleSheet,
|
||||
} from 'react-native';
|
||||
import { Button } from 'react-native-paper';
|
||||
import {
|
||||
NavigationContainer,
|
||||
CompositeNavigationProp,
|
||||
@@ -7,7 +15,7 @@ import {
|
||||
RouteProp,
|
||||
InitialState,
|
||||
useFocusEffect,
|
||||
} from '../src';
|
||||
} from '@navigation-ex/core';
|
||||
import createStackNavigator, { StackNavigationProp } from './StackNavigator';
|
||||
import createTabNavigator, { TabNavigationProp } from './TabNavigator';
|
||||
|
||||
@@ -22,6 +30,8 @@ type TabParamList = {
|
||||
fifth: undefined;
|
||||
};
|
||||
|
||||
YellowBox.ignoreWarnings(['Require cycle:', 'Warning: Async Storage']);
|
||||
|
||||
const Stack = createStackNavigator<StackParamList>();
|
||||
|
||||
const Tab = createTabNavigator<TabParamList>();
|
||||
@@ -37,35 +47,32 @@ const First = ({
|
||||
route: RouteProp<StackParamList, 'first'>;
|
||||
}) => {
|
||||
const updateTitle = React.useCallback(() => {
|
||||
if (Platform.OS !== 'web') {
|
||||
return;
|
||||
}
|
||||
|
||||
document.title = `${route.name} (${route.params.author})`;
|
||||
|
||||
return () => (document.title = '');
|
||||
return () => {
|
||||
document.title = '';
|
||||
};
|
||||
}, [route.name, route.params.author]);
|
||||
|
||||
useFocusEffect(updateTitle);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>First, {route.params.author}</h1>
|
||||
<button type="button" onClick={() => navigation.push('second')}>
|
||||
Push second
|
||||
</button>
|
||||
<button type="button" onClick={() => navigation.push('third')}>
|
||||
Push third
|
||||
</button>
|
||||
<button type="button" onClick={() => navigation.navigate('fourth')}>
|
||||
<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
|
||||
type="button"
|
||||
onClick={() => navigation.navigate('first', { author: 'John' })}
|
||||
>
|
||||
</Button>
|
||||
<Button onPress={() => navigation.navigate('first', { author: 'John' })}>
|
||||
Navigate with params
|
||||
</button>
|
||||
<button type="button" onClick={() => navigation.pop()}>
|
||||
Pop
|
||||
</button>
|
||||
</div>
|
||||
</Button>
|
||||
<Button onPress={() => navigation.pop()}>Pop</Button>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -90,18 +97,13 @@ const Second = ({
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Second</h1>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigation.push('first', { author: 'Joel' })}
|
||||
>
|
||||
<View>
|
||||
<Text style={styles.title}>Second</Text>
|
||||
<Button onPress={() => navigation.push('first', { author: 'Joel' })}>
|
||||
Push first
|
||||
</button>
|
||||
<button type="button" onClick={() => navigation.pop()}>
|
||||
Pop
|
||||
</button>
|
||||
</div>
|
||||
</Button>
|
||||
<Button onPress={() => navigation.pop()}>Pop</Button>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -113,21 +115,14 @@ const Fourth = ({
|
||||
StackNavigationProp<StackParamList>
|
||||
>;
|
||||
}) => (
|
||||
<div>
|
||||
<h1>Fourth</h1>
|
||||
<button type="button" onClick={() => navigation.jumpTo('fifth')}>
|
||||
Jump to fifth
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigation.push('first', { author: 'Jake' })}
|
||||
>
|
||||
<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 type="button" onClick={() => navigation.goBack()}>
|
||||
Go back
|
||||
</button>
|
||||
</div>
|
||||
</Button>
|
||||
<Button onPress={() => navigation.goBack()}>Go back</Button>
|
||||
</View>
|
||||
);
|
||||
|
||||
const Fifth = ({
|
||||
@@ -138,36 +133,48 @@ const Fifth = ({
|
||||
StackNavigationProp<StackParamList>
|
||||
>;
|
||||
}) => (
|
||||
<div>
|
||||
<h1>Fifth</h1>
|
||||
<button type="button" onClick={() => navigation.jumpTo('fourth')}>
|
||||
Jump to fourth
|
||||
</button>
|
||||
<button type="button" onClick={() => navigation.push('second')}>
|
||||
Push second
|
||||
</button>
|
||||
<button type="button" onClick={() => navigation.pop()}>
|
||||
Pop
|
||||
</button>
|
||||
</div>
|
||||
<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';
|
||||
|
||||
let initialState: InitialState | undefined;
|
||||
export default function App() {
|
||||
const [isReady, setIsReady] = React.useState(false);
|
||||
const [initialState, setInitialState] = React.useState<
|
||||
InitialState | undefined
|
||||
>();
|
||||
|
||||
try {
|
||||
initialState = JSON.parse(localStorage.getItem(PERSISTENCE_KEY) || '');
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<NavigationContainer
|
||||
initialState={initialState}
|
||||
onStateChange={state =>
|
||||
localStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state))
|
||||
AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state))
|
||||
}
|
||||
>
|
||||
<Stack.Navigator>
|
||||
@@ -195,4 +202,10 @@ function App() {
|
||||
);
|
||||
}
|
||||
|
||||
render(<App />, document.getElementById('root'));
|
||||
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;
|
||||
};
|
||||
10
packages/routers/package.json
Normal file
10
packages/routers/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@navigation-ex/routers",
|
||||
"version": "0.0.1",
|
||||
"main": "src/index",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"shortid": "^2.2.14",
|
||||
"@navigation-ex/core": "^0.0.1"
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,11 @@
|
||||
/* eslint-disable react-native/no-inline-styles */
|
||||
|
||||
import * as React from 'react';
|
||||
import shortid from 'shortid';
|
||||
import {
|
||||
useNavigationBuilder,
|
||||
NavigationProp,
|
||||
NavigationState,
|
||||
CommonAction,
|
||||
ParamListBase,
|
||||
Router,
|
||||
BaseRouter,
|
||||
createNavigator,
|
||||
DefaultRouterOptions,
|
||||
} from '../src/index';
|
||||
|
||||
type Props = DefaultRouterOptions & {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
} from '@navigation-ex/core';
|
||||
|
||||
type Action =
|
||||
| {
|
||||
@@ -29,47 +18,12 @@ type Action =
|
||||
}
|
||||
| { type: 'POP_TO_TOP' };
|
||||
|
||||
export type StackNavigationOptions = {
|
||||
/**
|
||||
* Title text for the screen.
|
||||
*/
|
||||
title?: string;
|
||||
};
|
||||
export type StackRouterOptions = DefaultRouterOptions;
|
||||
|
||||
export type StackNavigationProp<
|
||||
ParamList extends ParamListBase,
|
||||
RouteName extends keyof ParamList = string
|
||||
> = NavigationProp<
|
||||
ParamList,
|
||||
RouteName,
|
||||
NavigationState,
|
||||
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;
|
||||
export type StackNavigationState = NavigationState;
|
||||
|
||||
/**
|
||||
* Pop a screen from the stack.
|
||||
*/
|
||||
pop(count?: number): void;
|
||||
|
||||
/**
|
||||
* Pop to the first route in the stack, dismissing all other screens.
|
||||
*/
|
||||
popToTop(): void;
|
||||
};
|
||||
|
||||
function StackRouter(options: DefaultRouterOptions) {
|
||||
const router: Router<NavigationState, CommonAction | Action> = {
|
||||
export default function StackRouter(options: StackRouterOptions) {
|
||||
const router: Router<StackNavigationState, CommonAction | Action> = {
|
||||
...BaseRouter,
|
||||
|
||||
getInitialState({ routeNames, routeParamList }) {
|
||||
@@ -257,53 +211,3 @@ function StackRouter(options: DefaultRouterOptions) {
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
export function StackNavigator(props: Props) {
|
||||
const { state, descriptors } = useNavigationBuilder<
|
||||
NavigationState,
|
||||
StackNavigationOptions,
|
||||
DefaultRouterOptions
|
||||
>(StackRouter, props);
|
||||
|
||||
return (
|
||||
<div style={{ position: 'relative' }}>
|
||||
{state.routes.map((route, i) => (
|
||||
<div
|
||||
key={route.key}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
margin: 20,
|
||||
left: i * 20,
|
||||
top: i * 20,
|
||||
padding: 10,
|
||||
height: 480,
|
||||
width: 320,
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 3,
|
||||
boxShadow:
|
||||
'0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)',
|
||||
}}
|
||||
>
|
||||
{descriptors[route.key].render()}
|
||||
</div>
|
||||
))}
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: 40,
|
||||
width: 120,
|
||||
padding: 10,
|
||||
backgroundColor: 'tomato',
|
||||
borderRadius: 3,
|
||||
boxShadow: '0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)',
|
||||
}}
|
||||
>
|
||||
{descriptors[state.routes[state.index].key].options.title}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default createNavigator<StackNavigationOptions, typeof StackNavigator>(
|
||||
StackNavigator
|
||||
);
|
||||
@@ -1,22 +1,11 @@
|
||||
/* eslint-disable react-native/no-inline-styles */
|
||||
|
||||
import * as React from 'react';
|
||||
import shortid from 'shortid';
|
||||
import {
|
||||
useNavigationBuilder,
|
||||
NavigationProp,
|
||||
CommonAction,
|
||||
ParamListBase,
|
||||
Router,
|
||||
createNavigator,
|
||||
BaseRouter,
|
||||
NavigationState,
|
||||
DefaultRouterOptions,
|
||||
} from '../src/index';
|
||||
|
||||
type Props = TabRouterOptions & {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
Router,
|
||||
} from '@navigation-ex/core';
|
||||
|
||||
type Action = {
|
||||
type: 'JUMP_TO';
|
||||
@@ -27,13 +16,6 @@ export type TabRouterOptions = DefaultRouterOptions & {
|
||||
backBehavior?: 'initialRoute' | 'order' | 'history' | 'none';
|
||||
};
|
||||
|
||||
export type TabNavigationOptions = {
|
||||
/**
|
||||
* Title text for the screen.
|
||||
*/
|
||||
title?: string;
|
||||
};
|
||||
|
||||
export type TabNavigationState = NavigationState & {
|
||||
/**
|
||||
* List of previously visited route keys.
|
||||
@@ -41,29 +23,7 @@ export type TabNavigationState = NavigationState & {
|
||||
routeKeyHistory: 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;
|
||||
};
|
||||
|
||||
function TabRouter({
|
||||
export default function TabRouter({
|
||||
initialRouteName,
|
||||
backBehavior = 'history',
|
||||
}: TabRouterOptions) {
|
||||
@@ -252,33 +212,3 @@ function TabRouter({
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
export function TabNavigator(props: Props) {
|
||||
const { state, descriptors } = useNavigationBuilder<
|
||||
TabNavigationState,
|
||||
TabNavigationOptions,
|
||||
TabRouterOptions
|
||||
>(TabRouter, props);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'row', height: '100%' }}>
|
||||
{state.routes.map((route, i, self) => (
|
||||
<div
|
||||
key={route.key}
|
||||
style={{
|
||||
width: `${100 / self.length}%`,
|
||||
padding: 10,
|
||||
borderRadius: 3,
|
||||
backgroundColor: i === state.index ? 'tomato' : 'white',
|
||||
}}
|
||||
>
|
||||
{descriptors[route.key].render()}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default createNavigator<TabNavigationOptions, typeof TabNavigator>(
|
||||
TabNavigator
|
||||
);
|
||||
11
packages/routers/src/index.tsx
Normal file
11
packages/routers/src/index.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
export {
|
||||
default as StackRouter,
|
||||
StackRouterOptions,
|
||||
StackNavigationState,
|
||||
} from './StackRouter';
|
||||
|
||||
export {
|
||||
default as TabRouter,
|
||||
TabRouterOptions,
|
||||
TabNavigationState,
|
||||
} from './TabRouter';
|
||||
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@navigation-ex": ["./packages"]
|
||||
},
|
||||
"allowUnreachableCode": false,
|
||||
"allowUnusedLabels": false,
|
||||
"esModuleInterop": true,
|
||||
|
||||
Reference in New Issue
Block a user