mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-01-14 22:41:55 +08:00
Compare commits
33 Commits
@react-nav
...
@react-nav
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1dddaff45c | ||
|
|
21b397f0d6 | ||
|
|
2ff0531695 | ||
|
|
0149e85a95 | ||
|
|
3c47716826 | ||
|
|
acc9646426 | ||
|
|
6dce0780ed | ||
|
|
dd7cff2016 | ||
|
|
740c6b6706 | ||
|
|
039017bc2a | ||
|
|
b85a1c3055 | ||
|
|
18f8188dc8 | ||
|
|
47a1229837 | ||
|
|
00b11e303e | ||
|
|
f384706741 | ||
|
|
d1a6f3e30e | ||
|
|
fd6636a8cd | ||
|
|
eb24fea8b9 | ||
|
|
85ae378d8c | ||
|
|
bea14aa26f | ||
|
|
4d1e102f8c | ||
|
|
f07cd13561 | ||
|
|
f6d06768d3 | ||
|
|
3381d680d7 | ||
|
|
fcd1cc64c1 | ||
|
|
3999fc2836 | ||
|
|
9fd2635756 | ||
|
|
6bec620a3f | ||
|
|
c7b8e2e966 | ||
|
|
719e1a7b46 | ||
|
|
10eca8b92e | ||
|
|
b66e3436a7 | ||
|
|
1c075ffb16 |
@@ -1,89 +1,96 @@
|
|||||||
version: 2
|
version: 2.1
|
||||||
|
|
||||||
defaults: &defaults
|
executors:
|
||||||
docker:
|
default:
|
||||||
- image: circleci/node:10
|
docker:
|
||||||
working_directory: ~/project
|
- image: circleci/node:10
|
||||||
|
working_directory: ~/project
|
||||||
|
environment:
|
||||||
|
YARN_CACHE_FOLDER: "~/.cache/yarn"
|
||||||
|
|
||||||
|
commands:
|
||||||
|
attach_project:
|
||||||
|
steps:
|
||||||
|
- attach_workspace:
|
||||||
|
at: ~/project
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
install-dependencies:
|
install-dependencies:
|
||||||
<<: *defaults
|
executor: default
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- attach_workspace:
|
- attach_project
|
||||||
at: ~/project
|
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- v1-dependencies-{{ checksum "yarn.lock" }}
|
- v2-dependencies-{{ checksum "yarn.lock" }}
|
||||||
- v1-dependencies-
|
- v2-dependencies-
|
||||||
- run:
|
- run:
|
||||||
name: Install project dependencies
|
name: Install project dependencies
|
||||||
command: yarn install --frozen-lockfile
|
command: yarn install --frozen-lockfile
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: v1-dependencies-{{ checksum "yarn.lock" }}
|
key: v2-dependencies-{{ checksum "yarn.lock" }}
|
||||||
paths: node_modules
|
paths: ~/.cache/yarn
|
||||||
- persist_to_workspace:
|
- persist_to_workspace:
|
||||||
root: .
|
root: .
|
||||||
paths: .
|
paths: .
|
||||||
|
|
||||||
lint-and-typecheck:
|
lint-and-typecheck:
|
||||||
<<: *defaults
|
executor: default
|
||||||
steps:
|
steps:
|
||||||
- attach_workspace:
|
- attach_project
|
||||||
at: ~/project
|
- run:
|
||||||
- run:
|
name: Lint files
|
||||||
name: Lint files
|
command: yarn lint
|
||||||
command: yarn lint
|
- run:
|
||||||
- run:
|
name: Typecheck files
|
||||||
name: Typecheck files
|
command: yarn typescript
|
||||||
command: yarn typescript
|
|
||||||
unit-tests:
|
unit-tests:
|
||||||
<<: *defaults
|
executor: default
|
||||||
steps:
|
steps:
|
||||||
- attach_workspace:
|
- attach_project
|
||||||
at: ~/project
|
- run:
|
||||||
- run:
|
name: Run unit tests
|
||||||
name: Run unit tests
|
command: yarn test --coverage
|
||||||
command: yarn test --coverage
|
- run:
|
||||||
- run:
|
name: Upload test coverage
|
||||||
name: Upload test coverage
|
command: cat ./coverage/lcov.info | ./node_modules/.bin/codecov
|
||||||
command: cat ./coverage/lcov.info | ./node_modules/.bin/codecov
|
- store_artifacts:
|
||||||
- store_artifacts:
|
path: coverage
|
||||||
path: coverage
|
destination: coverage
|
||||||
destination: coverage
|
|
||||||
integration-tests:
|
integration-tests:
|
||||||
<<: *defaults
|
executor: default
|
||||||
steps:
|
steps:
|
||||||
- attach_workspace:
|
- attach_project
|
||||||
at: ~/project
|
- run:
|
||||||
- run:
|
name: Install Headless Chrome dependencies
|
||||||
name: Install Headless Chrome dependencies
|
command: |
|
||||||
command: |
|
sudo apt-get install -yq \
|
||||||
sudo apt-get install -yq \
|
gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
|
||||||
gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
|
libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
|
||||||
libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
|
libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 \
|
||||||
libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 \
|
libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates \
|
||||||
libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates \
|
fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
|
||||||
fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
|
- run:
|
||||||
- run:
|
name: Build example for web
|
||||||
name: Build example for web
|
command: yarn example expo build:web --no-pwa
|
||||||
command: yarn example expo build:web --no-pwa
|
- run:
|
||||||
- run:
|
name: Run integration tests
|
||||||
name: Run integration tests
|
command: yarn example test --maxWorkers=2
|
||||||
command: yarn example test --maxWorkers=2
|
|
||||||
build-packages:
|
build-packages:
|
||||||
<<: *defaults
|
executor: default
|
||||||
steps:
|
steps:
|
||||||
- attach_workspace:
|
- attach_project
|
||||||
at: ~/project
|
- run:
|
||||||
- run:
|
name: Build packages in the monorepo
|
||||||
name: Build packages in the monorepo
|
command: yarn lerna run prepare
|
||||||
command: yarn lerna run prepare
|
- run:
|
||||||
- run:
|
name: Verify paths for types
|
||||||
name: Verify paths for types
|
command: node scripts/check-types-path.js
|
||||||
command: node scripts/check-types-path.js
|
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
version: 2
|
|
||||||
build-and-test:
|
build-and-test:
|
||||||
jobs:
|
jobs:
|
||||||
- install-dependencies
|
- install-dependencies
|
||||||
|
|||||||
@@ -12,33 +12,33 @@
|
|||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^10.0.0",
|
"@expo/vector-icons": "^10.2.0",
|
||||||
"@react-native-community/masked-view": "^0.1.7",
|
"@react-native-community/masked-view": "^0.1.10",
|
||||||
"color": "^3.1.2",
|
"color": "^3.1.2",
|
||||||
"expo": "^37.0.0",
|
"expo": "^37.0.8",
|
||||||
"expo-asset": "~8.1.3",
|
"expo-asset": "~8.1.3",
|
||||||
"expo-blur": "~8.1.0",
|
"expo-blur": "~8.1.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-dom": "~16.9.0",
|
"react-dom": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-gesture-handler": "^1.6.0",
|
"react-native-gesture-handler": "^1.6.0",
|
||||||
"react-native-paper": "^3.7.0",
|
"react-native-paper": "^3.10.1",
|
||||||
"react-native-reanimated": "^1.7.0",
|
"react-native-reanimated": "^1.8.0",
|
||||||
"react-native-restart": "^0.0.14",
|
"react-native-restart": "^0.0.15",
|
||||||
"react-native-safe-area-context": "^0.7.3",
|
"react-native-safe-area-context": "^0.7.3",
|
||||||
"react-native-screens": "^2.3.0",
|
"react-native-screens": "^2.7.0",
|
||||||
"react-native-tab-view": "2.14.0",
|
"react-native-tab-view": "2.14.0",
|
||||||
"react-native-unimodules": "~0.8.1",
|
"react-native-unimodules": "~0.9.1",
|
||||||
"react-native-web": "^0.11.7"
|
"react-native-web": "^0.11.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@expo/webpack-config": "^0.11.19",
|
"@expo/webpack-config": "^0.11.19",
|
||||||
"@types/jest-dev-server": "^4.2.0",
|
"@types/jest-dev-server": "^4.2.0",
|
||||||
"@types/react": "^16.9.23",
|
"@types/react": "^16.9.34",
|
||||||
"@types/react-native": "^0.60.22",
|
"@types/react-native": "^0.62.7",
|
||||||
"babel-preset-expo": "^8.1.0",
|
"babel-preset-expo": "^8.1.0",
|
||||||
"expo-cli": "^3.17.18",
|
"expo-cli": "^3.20.1",
|
||||||
"jest": "^25.2.7",
|
"jest": "^26.0.1",
|
||||||
"jest-dev-server": "^4.4.0",
|
"jest-dev-server": "^4.4.0",
|
||||||
"playwright": "^0.14.0",
|
"playwright": "^0.14.0",
|
||||||
"serve": "^11.3.0",
|
"serve": "^11.3.0",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
I18nManager,
|
I18nManager,
|
||||||
Dimensions,
|
Dimensions,
|
||||||
ScaledSize,
|
ScaledSize,
|
||||||
|
Linking,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
// eslint-disable-next-line import/no-unresolved
|
// eslint-disable-next-line import/no-unresolved
|
||||||
import { enableScreens } from 'react-native-screens';
|
import { enableScreens } from 'react-native-screens';
|
||||||
@@ -25,7 +26,6 @@ import {
|
|||||||
} from 'react-native-paper';
|
} from 'react-native-paper';
|
||||||
import {
|
import {
|
||||||
InitialState,
|
InitialState,
|
||||||
NavigationContainerRef,
|
|
||||||
NavigationContainer,
|
NavigationContainer,
|
||||||
DefaultTheme,
|
DefaultTheme,
|
||||||
DarkTheme,
|
DarkTheme,
|
||||||
@@ -129,8 +129,6 @@ const THEME_PERSISTENCE_KEY = 'THEME_TYPE';
|
|||||||
Asset.loadAsync(StackAssets);
|
Asset.loadAsync(StackAssets);
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const containerRef = React.useRef<NavigationContainerRef>(null);
|
|
||||||
|
|
||||||
const [theme, setTheme] = React.useState(DefaultTheme);
|
const [theme, setTheme] = React.useState(DefaultTheme);
|
||||||
|
|
||||||
const [isReady, setIsReady] = React.useState(false);
|
const [isReady, setIsReady] = React.useState(false);
|
||||||
@@ -141,18 +139,18 @@ export default function App() {
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const restoreState = async () => {
|
const restoreState = async () => {
|
||||||
try {
|
try {
|
||||||
let state;
|
const initialUrl = await Linking.getInitialURL();
|
||||||
|
|
||||||
if (Platform.OS !== 'web' && state === undefined) {
|
if (Platform.OS !== 'web' || initialUrl === null) {
|
||||||
const savedState = await AsyncStorage.getItem(
|
const savedState = await AsyncStorage.getItem(
|
||||||
NAVIGATION_PERSISTENCE_KEY
|
NAVIGATION_PERSISTENCE_KEY
|
||||||
);
|
);
|
||||||
|
|
||||||
state = savedState ? JSON.parse(savedState) : undefined;
|
const state = savedState ? JSON.parse(savedState) : undefined;
|
||||||
}
|
|
||||||
|
|
||||||
if (state !== undefined) {
|
if (state !== undefined) {
|
||||||
setInitialState(state);
|
setInitialState(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
@@ -208,7 +206,6 @@ export default function App() {
|
|||||||
<StatusBar barStyle={theme.dark ? 'light-content' : 'dark-content'} />
|
<StatusBar barStyle={theme.dark ? 'light-content' : 'dark-content'} />
|
||||||
)}
|
)}
|
||||||
<NavigationContainer
|
<NavigationContainer
|
||||||
ref={containerRef}
|
|
||||||
initialState={initialState}
|
initialState={initialState}
|
||||||
onStateChange={(state) =>
|
onStateChange={(state) =>
|
||||||
AsyncStorage.setItem(
|
AsyncStorage.setItem(
|
||||||
|
|||||||
@@ -24,19 +24,21 @@ module.exports = async function (env, argv) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Object.assign(config.resolve.alias, {
|
Object.assign(config.resolve.alias, {
|
||||||
react: path.resolve(node_modules, 'react'),
|
'react': path.resolve(node_modules, 'react'),
|
||||||
'react-native': path.resolve(node_modules, 'react-native-web'),
|
'react-native': path.resolve(node_modules, 'react-native-web'),
|
||||||
'react-native-web': path.resolve(node_modules, 'react-native-web'),
|
'react-native-web': path.resolve(node_modules, 'react-native-web'),
|
||||||
'@expo/vector-icons': path.resolve(node_modules, '@expo/vector-icons'),
|
'@expo/vector-icons': path.resolve(node_modules, '@expo/vector-icons'),
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.readdirSync(packages).forEach((name) => {
|
fs.readdirSync(packages)
|
||||||
config.resolve.alias[`@react-navigation/${name}`] = path.resolve(
|
.filter((name) => !name.startsWith('.'))
|
||||||
packages,
|
.forEach((name) => {
|
||||||
name,
|
config.resolve.alias[`@react-navigation/${name}`] = path.resolve(
|
||||||
'src'
|
packages,
|
||||||
);
|
name,
|
||||||
});
|
require(`../packages/${name}/package.json`).source
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
};
|
};
|
||||||
|
|||||||
16
package.json
16
package.json
@@ -27,23 +27,23 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.9.0",
|
"@babel/plugin-proposal-optional-chaining": "^7.9.0",
|
||||||
"@babel/preset-env": "^7.9.0",
|
"@babel/preset-env": "^7.9.6",
|
||||||
"@babel/preset-flow": "^7.9.0",
|
"@babel/preset-flow": "^7.9.0",
|
||||||
"@babel/preset-react": "^7.9.4",
|
"@babel/preset-react": "^7.9.4",
|
||||||
"@babel/preset-typescript": "^7.9.0",
|
"@babel/preset-typescript": "^7.9.0",
|
||||||
"@babel/runtime": "^7.9.2",
|
"@babel/runtime": "^7.9.6",
|
||||||
"@commitlint/config-conventional": "^8.3.4",
|
"@commitlint/config-conventional": "^8.3.4",
|
||||||
"@types/jest": "^25.2.1",
|
"@types/jest": "^25.2.1",
|
||||||
"babel-jest": "^25.2.6",
|
"babel-jest": "^26.0.1",
|
||||||
"codecov": "^3.6.5",
|
"codecov": "^3.6.5",
|
||||||
"commitlint": "^8.3.5",
|
"commitlint": "^8.3.5",
|
||||||
"core-js": "^3.6.4",
|
"core-js": "^3.6.5",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
"eslint-config-satya164": "^3.1.6",
|
"eslint-config-satya164": "^3.1.7",
|
||||||
"husky": "^4.2.3",
|
"husky": "^4.2.5",
|
||||||
"jest": "^25.2.7",
|
"jest": "^26.0.1",
|
||||||
"lerna": "^3.20.2",
|
"lerna": "^3.20.2",
|
||||||
"prettier": "^2.0.4",
|
"prettier": "^2.0.5",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
|||||||
@@ -3,6 +3,84 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [5.4.4](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.4.3...@react-navigation/bottom-tabs@5.4.4) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.4.3](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.4.2...@react-navigation/bottom-tabs@5.4.3) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.4.2](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.4.1...@react-navigation/bottom-tabs@5.4.2) (2020-05-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.4.1](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.4.0...@react-navigation/bottom-tabs@5.4.1) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix building typescript definitions. closes [#8216](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/issues/8216) ([47a1229](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/commit/47a12298378747edd2d22e54dc1c8677f98c49b4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.4.0](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.3.4...@react-navigation/bottom-tabs@5.4.0) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add generic type aliases for screen props ([bea14aa](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/commit/bea14aa26fd5cbfebc7973733c5cf1f44fd323aa)), closes [#7971](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/issues/7971)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.4](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.3.3...@react-navigation/bottom-tabs@5.3.4) (2020-05-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.3](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.3.2...@react-navigation/bottom-tabs@5.3.3) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.2](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.3.1...@react-navigation/bottom-tabs@5.3.2) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.1](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.3.0...@react-navigation/bottom-tabs@5.3.1) (2020-04-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.3.0](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.2.8...@react-navigation/bottom-tabs@5.3.0) (2020-04-30)
|
# [5.3.0](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.2.8...@react-navigation/bottom-tabs@5.3.0) (2020-04-30)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/bottom-tabs",
|
"name": "@react-navigation/bottom-tabs",
|
||||||
"description": "Bottom tab navigator following iOS design guidelines",
|
"description": "Bottom tab navigator following iOS design guidelines",
|
||||||
"version": "5.3.0",
|
"version": "5.4.4",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs",
|
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "src/index.tsx",
|
"react-native": "src/index.tsx",
|
||||||
|
"source": "src/index.tsx",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
"types": "lib/typescript/src/index.d.ts",
|
"types": "lib/typescript/src/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -34,16 +35,16 @@
|
|||||||
"react-native-iphone-x-helper": "^1.2.1"
|
"react-native-iphone-x-helper": "^1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.10.0",
|
"@react-native-community/bob": "^0.13.1",
|
||||||
"@react-navigation/native": "^5.2.0",
|
"@react-navigation/native": "^5.3.2",
|
||||||
"@types/color": "^3.0.1",
|
"@types/color": "^3.0.1",
|
||||||
"@types/react": "^16.9.23",
|
"@types/react": "^16.9.34",
|
||||||
"@types/react-native": "^0.61.22",
|
"@types/react-native": "^0.62.7",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-safe-area-context": "^0.7.3",
|
"react-native-safe-area-context": "^0.7.3",
|
||||||
"react-native-screens": "^2.3.0",
|
"react-native-screens": "^2.7.0",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export { default as BottomTabBar } from './views/BottomTabBar';
|
|||||||
export type {
|
export type {
|
||||||
BottomTabNavigationOptions,
|
BottomTabNavigationOptions,
|
||||||
BottomTabNavigationProp,
|
BottomTabNavigationProp,
|
||||||
|
BottomTabScreenProps,
|
||||||
BottomTabBarProps,
|
BottomTabBarProps,
|
||||||
BottomTabBarOptions,
|
BottomTabBarOptions,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
Descriptor,
|
Descriptor,
|
||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
TabActionHelpers,
|
TabActionHelpers,
|
||||||
|
RouteProp,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
|
|
||||||
export type BottomTabNavigationEventMap = {
|
export type BottomTabNavigationEventMap = {
|
||||||
@@ -45,6 +46,14 @@ export type BottomTabNavigationProp<
|
|||||||
> &
|
> &
|
||||||
TabActionHelpers<ParamList>;
|
TabActionHelpers<ParamList>;
|
||||||
|
|
||||||
|
export type BottomTabScreenProps<
|
||||||
|
ParamList extends ParamListBase,
|
||||||
|
RouteName extends keyof ParamList = string
|
||||||
|
> = {
|
||||||
|
navigation: BottomTabNavigationProp<ParamList, RouteName>;
|
||||||
|
route: RouteProp<ParamList, RouteName>;
|
||||||
|
};
|
||||||
|
|
||||||
export type BottomTabNavigationOptions = {
|
export type BottomTabNavigationOptions = {
|
||||||
/**
|
/**
|
||||||
* Title text for the screen.
|
* Title text for the screen.
|
||||||
|
|||||||
@@ -3,6 +3,81 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [5.1.20](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.19...@react-navigation/compat@5.1.20) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.19](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.18...@react-navigation/compat@5.1.19) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.18](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.17...@react-navigation/compat@5.1.18) (2020-05-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.17](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.16...@react-navigation/compat@5.1.17) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix building typescript definitions. closes [#8216](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/issues/8216) ([47a1229](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/commit/47a12298378747edd2d22e54dc1c8677f98c49b4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.16](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.15...@react-navigation/compat@5.1.16) (2020-05-08)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.15](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.14...@react-navigation/compat@5.1.15) (2020-05-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.14](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.13...@react-navigation/compat@5.1.14) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.13](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.12...@react-navigation/compat@5.1.13) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.12](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.11...@react-navigation/compat@5.1.12) (2020-04-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.1.11](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.10...@react-navigation/compat@5.1.11) (2020-04-30)
|
## [5.1.11](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.10...@react-navigation/compat@5.1.11) (2020-04-30)
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/compat
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/compat",
|
"name": "@react-navigation/compat",
|
||||||
"description": "Compatibility layer to write navigator definitions in static configuration format",
|
"description": "Compatibility layer to write navigator definitions in static configuration format",
|
||||||
"version": "5.1.11",
|
"version": "5.1.20",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/compat",
|
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/compat",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
"homepage": "https://reactnavigation.org/docs/compatibility.html",
|
"homepage": "https://reactnavigation.org/docs/compatibility.html",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "src/index.tsx",
|
"react-native": "src/index.tsx",
|
||||||
|
"source": "src/index.tsx",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
"types": "lib/typescript/src/index.d.ts",
|
"types": "lib/typescript/src/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -25,9 +26,9 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.10.0",
|
"@react-native-community/bob": "^0.13.1",
|
||||||
"@react-navigation/native": "^5.2.0",
|
"@react-navigation/native": "^5.3.2",
|
||||||
"@types/react": "^16.9.23",
|
"@types/react": "^16.9.34",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,68 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [5.6.1](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.6.0...@react-navigation/core@5.6.1) (2020-05-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* don't use flat since it's not supported in node ([21b397f](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/21b397f0d6b96ec4875d3172f47533130bb08009))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.6.0](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.5.2...@react-navigation/core@5.6.0) (2020-05-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* ignore extra slashes in the pattern ([3c47716](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/3c47716826d0dfa69dfa6112141c116723372ea1))
|
||||||
|
* ignore state updates when we're not mounted ([0149e85](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/0149e85a95b90c6a9d487fa753ddbf5d01c03e3d)), closes [#8226](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/8226)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* merge path patterns for nested screens ([#8253](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/8253)) ([acc9646](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/acc9646426fee53558d686dfbe5fd0e35361d8c0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.5.2](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.5.1...@react-navigation/core@5.5.2) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix building typescript definitions. closes [#8216](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/8216) ([47a1229](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/47a12298378747edd2d22e54dc1c8677f98c49b4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.5.1](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.5.0...@react-navigation/core@5.5.1) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* avoid cleaning up state when a new navigator is mounted. fixes [#8195](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/8195) ([f6d0676](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/f6d06768d3c36d1f5beaffcb660f3c259209f2e7))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.5.0](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.4.0...@react-navigation/core@5.5.0) (2020-05-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add support for optional params to linking ([#8196](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/8196)) ([fcd1cc6](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/fcd1cc64c151e4941f3f544a54b5048d853821f6))
|
||||||
|
* support params anywhere in path segement ([#8184](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/8184)) ([3999fc2](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/3999fc28365c3a06a17d963c7be7fb7e897f99e0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.4.0](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.3.5...@react-navigation/core@5.4.0) (2020-04-30)
|
# [5.4.0](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.3.5...@react-navigation/core@5.4.0) (2020-04-30)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/core",
|
"name": "@react-navigation/core",
|
||||||
"description": "Core utilities for building navigators",
|
"description": "Core utilities for building navigators",
|
||||||
"version": "5.4.0",
|
"version": "5.6.1",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
"react-native",
|
"react-native",
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
"homepage": "https://reactnavigation.org",
|
"homepage": "https://reactnavigation.org",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "src/index.tsx",
|
"react-native": "src/index.tsx",
|
||||||
|
"source": "src/index.tsx",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
"types": "lib/typescript/src/index.d.ts",
|
"types": "lib/typescript/src/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -29,21 +30,21 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/routers": "^5.4.2",
|
"@react-navigation/routers": "^5.4.4",
|
||||||
"escape-string-regexp": "^2.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"nanoid": "^3.0.2",
|
"nanoid": "^3.1.5",
|
||||||
"query-string": "^6.12.0",
|
"query-string": "^6.12.1",
|
||||||
"react-is": "^16.13.0",
|
"react-is": "^16.13.0",
|
||||||
"use-subscription": "^1.4.0"
|
"use-subscription": "^1.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.10.0",
|
"@react-native-community/bob": "^0.13.1",
|
||||||
"@types/react": "^16.9.23",
|
"@types/react": "^16.9.34",
|
||||||
"@types/react-is": "^16.7.1",
|
"@types/react-is": "^16.7.1",
|
||||||
"@types/use-subscription": "^1.0.0",
|
"@types/use-subscription": "^1.0.0",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native-testing-library": "^1.12.0",
|
"react-native-testing-library": "^1.13.2",
|
||||||
"react-test-renderer": "~16.13.1",
|
"react-test-renderer": "~16.13.1",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -117,7 +117,8 @@ it("doesn't add query param for empty params", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('handles state with config with nested screens', () => {
|
it('handles state with config with nested screens', () => {
|
||||||
const path = '/foe/bar/sweet/apple/baz/jane?answer=42&count=10&valid=true';
|
const path =
|
||||||
|
'/foo/foe/bar/sweet/apple/baz/jane?answer=42&count=10&valid=true';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
@@ -182,8 +183,77 @@ it('handles state with config with nested screens', () => {
|
|||||||
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('handles state with config with nested screens and exact', () => {
|
||||||
|
const path = '/foe/bar/sweet/apple/baz/jane?answer=42&count=10&valid=true';
|
||||||
|
const config = {
|
||||||
|
Foo: {
|
||||||
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: {
|
||||||
|
path: 'foe',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bar: 'bar/:type/:fruit',
|
||||||
|
Baz: {
|
||||||
|
path: 'baz/:author',
|
||||||
|
parse: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
|
count: Number,
|
||||||
|
valid: Boolean,
|
||||||
|
},
|
||||||
|
stringify: {
|
||||||
|
author: (author: string) => author.toLowerCase(),
|
||||||
|
id: (id: number) => `x${id}`,
|
||||||
|
unknown: (_: unknown) => 'x',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bar',
|
||||||
|
params: { fruit: 'apple', type: 'sweet' },
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Baz',
|
||||||
|
params: {
|
||||||
|
author: 'Jane',
|
||||||
|
count: '10',
|
||||||
|
answer: '42',
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
|
});
|
||||||
|
|
||||||
it('handles state with config with nested screens and unused configs', () => {
|
it('handles state with config with nested screens and unused configs', () => {
|
||||||
const path = '/foe/baz/jane?answer=42&count=10&valid=true';
|
const path = '/foo/foe/baz/jane?answer=42&count=10&valid=true';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
@@ -239,6 +309,66 @@ it('handles state with config with nested screens and unused configs', () => {
|
|||||||
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('handles state with config with nested screens and unused configs with exact', () => {
|
||||||
|
const path = '/foe/baz/jane?answer=42&count=10&valid=true';
|
||||||
|
const config = {
|
||||||
|
Foo: {
|
||||||
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: {
|
||||||
|
path: 'foe',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Baz: {
|
||||||
|
path: 'baz/:author',
|
||||||
|
parse: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
|
count: Number,
|
||||||
|
valid: Boolean,
|
||||||
|
},
|
||||||
|
stringify: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
|
unknown: (_: unknown) => 'x',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Baz',
|
||||||
|
params: {
|
||||||
|
author: 'Jane',
|
||||||
|
count: 10,
|
||||||
|
answer: '42',
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
|
});
|
||||||
|
|
||||||
it('handles nested object with stringify in it', () => {
|
it('handles nested object with stringify in it', () => {
|
||||||
const path = '/bar/sweet/apple/foo/bis/jane?answer=42&count=10&valid=true';
|
const path = '/bar/sweet/apple/foo/bis/jane?answer=42&count=10&valid=true';
|
||||||
const config = {
|
const config = {
|
||||||
@@ -252,7 +382,6 @@ it('handles nested object with stringify in it', () => {
|
|||||||
},
|
},
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz',
|
|
||||||
screens: {
|
screens: {
|
||||||
Bos: 'bos',
|
Bos: 'bos',
|
||||||
Bis: {
|
Bis: {
|
||||||
@@ -312,8 +441,82 @@ it('handles nested object with stringify in it', () => {
|
|||||||
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('handles nested object with stringify in it with exact', () => {
|
||||||
|
const path = '/bar/sweet/apple/foo/bis/jane?answer=42&count=10&valid=true';
|
||||||
|
const config = {
|
||||||
|
Foo: {
|
||||||
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: {
|
||||||
|
path: 'foe',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bar: 'bar/:type/:fruit',
|
||||||
|
Baz: {
|
||||||
|
path: 'baz',
|
||||||
|
screens: {
|
||||||
|
Bos: 'bos',
|
||||||
|
Bis: {
|
||||||
|
path: 'bis/:author',
|
||||||
|
exact: true,
|
||||||
|
stringify: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
|
},
|
||||||
|
parse: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
|
count: Number,
|
||||||
|
valid: Boolean,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bar',
|
||||||
|
params: { fruit: 'apple', type: 'sweet' },
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Baz',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bis',
|
||||||
|
params: {
|
||||||
|
author: 'Jane',
|
||||||
|
count: 10,
|
||||||
|
answer: '42',
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
|
});
|
||||||
|
|
||||||
it('handles nested object for second route depth', () => {
|
it('handles nested object for second route depth', () => {
|
||||||
const path = '/baz';
|
const path = '/foo/bar/baz';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
@@ -351,7 +554,95 @@ it('handles nested object for second route depth', () => {
|
|||||||
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles nested object for second route depth and and path and stringify in roots', () => {
|
it('handles nested object for second route depth with exact', () => {
|
||||||
|
const path = '/baz';
|
||||||
|
const config = {
|
||||||
|
Foo: {
|
||||||
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: 'foe',
|
||||||
|
Bar: {
|
||||||
|
path: 'bar',
|
||||||
|
screens: {
|
||||||
|
Baz: {
|
||||||
|
path: 'baz',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bar',
|
||||||
|
state: {
|
||||||
|
routes: [{ name: 'Baz' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles nested object for second route depth and path and stringify in roots', () => {
|
||||||
|
const path = '/foo/dathomir/bar/42/baz';
|
||||||
|
const config = {
|
||||||
|
Foo: {
|
||||||
|
path: 'foo/:planet',
|
||||||
|
stringify: {
|
||||||
|
id: (id: number) => `planet=${id}`,
|
||||||
|
},
|
||||||
|
screens: {
|
||||||
|
Foe: 'foe',
|
||||||
|
Bar: {
|
||||||
|
path: 'bar/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
screens: {
|
||||||
|
Baz: 'baz',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
params: { planet: 'dathomir' },
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bar',
|
||||||
|
state: {
|
||||||
|
routes: [{ name: 'Baz', params: { id: 42 } }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles nested object for second route depth and path and stringify in roots with exact', () => {
|
||||||
const path = '/baz';
|
const path = '/baz';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
@@ -370,7 +661,10 @@ it('handles nested object for second route depth and and path and stringify in r
|
|||||||
id: Number,
|
id: Number,
|
||||||
},
|
},
|
||||||
screens: {
|
screens: {
|
||||||
Baz: 'baz',
|
Baz: {
|
||||||
|
path: 'baz',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -470,7 +764,7 @@ it('keeps query params if path is empty', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('cuts nested configs too', () => {
|
it('cuts nested configs too', () => {
|
||||||
const path = '/baz';
|
const path = '/foo/baz';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
@@ -478,7 +772,48 @@ it('cuts nested configs too', () => {
|
|||||||
Bar: '',
|
Bar: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Baz: { path: 'baz' },
|
Baz: {
|
||||||
|
path: 'baz',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bar',
|
||||||
|
state: {
|
||||||
|
routes: [{ name: 'Baz' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cuts nested configs too with exact', () => {
|
||||||
|
const path = '/baz';
|
||||||
|
const config = {
|
||||||
|
Foo: {
|
||||||
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Bar: {
|
||||||
|
path: '',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Baz: {
|
||||||
|
path: 'baz',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
@@ -504,7 +839,7 @@ it('cuts nested configs too', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('handles empty path at the end', () => {
|
it('handles empty path at the end', () => {
|
||||||
const path = '/bar';
|
const path = '/foo/bar';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
@@ -641,7 +976,6 @@ it('strips undefined query params', () => {
|
|||||||
},
|
},
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz',
|
|
||||||
screens: {
|
screens: {
|
||||||
Bos: 'bos',
|
Bos: 'bos',
|
||||||
Bis: {
|
Bis: {
|
||||||
@@ -681,7 +1015,79 @@ it('strips undefined query params', () => {
|
|||||||
params: {
|
params: {
|
||||||
author: 'Jane',
|
author: 'Jane',
|
||||||
count: 10,
|
count: 10,
|
||||||
answer: undefined,
|
valid: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('strips undefined query params with exact', () => {
|
||||||
|
const path = '/bar/sweet/apple/foo/bis/jane?count=10&valid=true';
|
||||||
|
const config = {
|
||||||
|
Foo: {
|
||||||
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: {
|
||||||
|
path: 'foe',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bar: 'bar/:type/:fruit',
|
||||||
|
Baz: {
|
||||||
|
path: 'baz',
|
||||||
|
screens: {
|
||||||
|
Bos: 'bos',
|
||||||
|
Bis: {
|
||||||
|
path: 'bis/:author',
|
||||||
|
exact: true,
|
||||||
|
stringify: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
|
},
|
||||||
|
parse: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
|
count: Number,
|
||||||
|
valid: Boolean,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bar',
|
||||||
|
params: { fruit: 'apple', type: 'sweet' },
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Baz',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bis',
|
||||||
|
params: {
|
||||||
|
author: 'Jane',
|
||||||
|
count: 10,
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -714,7 +1120,6 @@ it('handles stripping all query params', () => {
|
|||||||
},
|
},
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz',
|
|
||||||
screens: {
|
screens: {
|
||||||
Bos: 'bos',
|
Bos: 'bos',
|
||||||
Bis: {
|
Bis: {
|
||||||
@@ -753,9 +1158,6 @@ it('handles stripping all query params', () => {
|
|||||||
name: 'Bis',
|
name: 'Bis',
|
||||||
params: {
|
params: {
|
||||||
author: 'Jane',
|
author: 'Jane',
|
||||||
count: undefined,
|
|
||||||
answer: undefined,
|
|
||||||
valid: undefined,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -773,3 +1175,93 @@ it('handles stripping all query params', () => {
|
|||||||
expect(getPathFromState(state, config)).toBe(path);
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('handles stripping all query params with exact', () => {
|
||||||
|
const path = '/bar/sweet/apple/foo/bis/jane';
|
||||||
|
const config = {
|
||||||
|
Foo: {
|
||||||
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: {
|
||||||
|
path: 'foe',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bar: 'bar/:type/:fruit',
|
||||||
|
Baz: {
|
||||||
|
path: 'baz',
|
||||||
|
screens: {
|
||||||
|
Bos: 'bos',
|
||||||
|
Bis: {
|
||||||
|
path: 'bis/:author',
|
||||||
|
exact: true,
|
||||||
|
stringify: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
|
},
|
||||||
|
parse: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
|
count: Number,
|
||||||
|
valid: Boolean,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bar',
|
||||||
|
params: { fruit: 'apple', type: 'sweet' },
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Baz',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bis',
|
||||||
|
params: {
|
||||||
|
author: 'Jane',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('replaces undefined query params', () => {
|
||||||
|
const path = '/bar/undefined/apple';
|
||||||
|
const config = {
|
||||||
|
Bar: 'bar/:type/:fruit',
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bar',
|
||||||
|
params: { fruit: 'apple' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
|
});
|
||||||
|
|||||||
@@ -147,7 +147,10 @@ it('converts path string to initial state with config with nested screens', () =
|
|||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
screens: {
|
screens: {
|
||||||
Foe: 'foe',
|
Foe: {
|
||||||
|
path: 'foe',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
@@ -213,7 +216,10 @@ it('converts path string to initial state with config with nested screens and un
|
|||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
screens: {
|
screens: {
|
||||||
Foe: 'foe',
|
Foe: {
|
||||||
|
path: 'foe',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Baz: {
|
Baz: {
|
||||||
@@ -268,16 +274,23 @@ it('handles nested object with unused configs and with parse in it', () => {
|
|||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
screens: {
|
screens: {
|
||||||
Foe: 'foe',
|
Foe: {
|
||||||
|
path: 'foe',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz',
|
path: 'baz',
|
||||||
screens: {
|
screens: {
|
||||||
Bos: 'bos',
|
Bos: {
|
||||||
|
path: 'bos',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
Bis: {
|
Bis: {
|
||||||
path: 'bis/:author',
|
path: 'bis/:author',
|
||||||
|
exact: true,
|
||||||
stringify: {
|
stringify: {
|
||||||
author: (author: string) =>
|
author: (author: string) =>
|
||||||
author.replace(/^\w/, (c) => c.toLowerCase()),
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
@@ -348,11 +361,18 @@ it('handles parse in nested object for second route depth', () => {
|
|||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
screens: {
|
screens: {
|
||||||
Foe: 'foe',
|
Foe: {
|
||||||
|
path: 'foe',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
Bar: {
|
Bar: {
|
||||||
path: 'bar',
|
path: 'bar',
|
||||||
|
exact: true,
|
||||||
screens: {
|
screens: {
|
||||||
Baz: 'baz',
|
Baz: {
|
||||||
|
path: 'baz',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -519,16 +539,23 @@ it('handles two initialRouteNames', () => {
|
|||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
screens: {
|
screens: {
|
||||||
Foe: 'foe',
|
Foe: {
|
||||||
|
path: 'foe',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
Baz: {
|
Baz: {
|
||||||
initialRouteName: 'Bos',
|
initialRouteName: 'Bos',
|
||||||
screens: {
|
screens: {
|
||||||
Bos: 'bos',
|
Bos: {
|
||||||
|
path: 'bos',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
Bis: {
|
Bis: {
|
||||||
path: 'bis/:author',
|
path: 'bis/:author',
|
||||||
|
exact: true,
|
||||||
stringify: {
|
stringify: {
|
||||||
author: (author: string) =>
|
author: (author: string) =>
|
||||||
author.replace(/^\w/, (c) => c.toLowerCase()),
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
@@ -601,16 +628,23 @@ it('accepts initialRouteName without config for it', () => {
|
|||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
screens: {
|
screens: {
|
||||||
Foe: 'foe',
|
Foe: {
|
||||||
|
path: 'foe',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
Baz: {
|
Baz: {
|
||||||
initialRouteName: 'Bas',
|
initialRouteName: 'Bas',
|
||||||
screens: {
|
screens: {
|
||||||
Bos: 'bos',
|
Bos: {
|
||||||
|
path: 'bos',
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
Bis: {
|
Bis: {
|
||||||
path: 'bis/:author',
|
path: 'bis/:author',
|
||||||
|
exact: true,
|
||||||
stringify: {
|
stringify: {
|
||||||
author: (author: string) =>
|
author: (author: string) =>
|
||||||
author.replace(/^\w/, (c) => c.toLowerCase()),
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
@@ -984,3 +1018,868 @@ it('handles not taking path with too many segments', () => {
|
|||||||
state
|
state
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('handles differently ordered params v1', () => {
|
||||||
|
const path = '/foos/5/res/20';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foos/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: 'foos/:id/res/:pwd',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
pwd: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { id: 5, pwd: 20 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles differently ordered params v2', () => {
|
||||||
|
const path = '/5/20/foos/res';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foos/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: ':id/:pwd/foos/res',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
pwd: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { id: 5, pwd: 20 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles differently ordered params v3', () => {
|
||||||
|
const path = '/foos/5/20/res';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foos/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: 'foos/:id/:pwd/res',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
pwd: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { id: 5, pwd: 20 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles differently ordered params v4', () => {
|
||||||
|
const path = '5/foos/res/20';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foos/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: ':id/foos/res/:pwd',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
pwd: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { id: 5, pwd: 20 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles simple optional params', () => {
|
||||||
|
const path = '/foos/5';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: 'foos/:id/:nip?',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
nip: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { id: 5 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handle 2 optional params at the end v1', () => {
|
||||||
|
const path = '/foos/5';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: 'foos/:id/:nip?/:pwd?',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
nip: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { id: 5 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handle 2 optional params at the end v2', () => {
|
||||||
|
const path = '/foos/5/10';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: 'foos/:id/:nip?/:pwd?',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
nip: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { id: 5, nip: 10 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handle 2 optional params at the end v3', () => {
|
||||||
|
const path = '/foos/5/10/15';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: 'foos/:id/:nip?/:pwd?',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
nip: Number,
|
||||||
|
pwd: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { id: 5, nip: 10, pwd: 15 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handle optional params in the middle v1', () => {
|
||||||
|
const path = '/foos/5/10';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: 'foos/:id/:nip?/:pwd',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
nip: Number,
|
||||||
|
pwd: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { id: 5, pwd: 10 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handle optional params in the middle v2', () => {
|
||||||
|
const path = '/foos/5/10/15';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: 'foos/:id/:nip?/:pwd',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
nip: Number,
|
||||||
|
pwd: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { id: 5, nip: 10, pwd: 15 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handle optional params in the middle v3', () => {
|
||||||
|
const path = '/foos/5/10/15';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: 'foos/:id/:nip?/:pwd/:smh',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
nip: Number,
|
||||||
|
pwd: Number,
|
||||||
|
smh: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { id: 5, pwd: 10, smh: 15 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handle optional params in the middle v4', () => {
|
||||||
|
const path = '/foos/5/10';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: 'foos/:nip?/:pwd/:smh?/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
nip: Number,
|
||||||
|
pwd: Number,
|
||||||
|
smh: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { pwd: 5, id: 10 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handle optional params in the middle v5', () => {
|
||||||
|
const path = '/foos/5/10/15';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: 'foos/:nip?/:pwd/:smh?/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
nip: Number,
|
||||||
|
pwd: Number,
|
||||||
|
smh: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { nip: 5, pwd: 10, id: 15 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handle optional params in the beginning v1', () => {
|
||||||
|
const path = '5/10/foos/15';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: ':nip?/:pwd/foos/:smh?/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
nip: Number,
|
||||||
|
pwd: Number,
|
||||||
|
smh: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { nip: 5, pwd: 10, id: 15 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handle optional params in the beginning v2', () => {
|
||||||
|
const path = '5/10/foos/15';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foe: {
|
||||||
|
path: '/',
|
||||||
|
initialRouteName: 'Foo',
|
||||||
|
screens: {
|
||||||
|
Foo: 'foo',
|
||||||
|
Bis: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bas: {
|
||||||
|
path: ':nip?/:smh?/:pwd/foos/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
nip: Number,
|
||||||
|
pwd: Number,
|
||||||
|
smh: Number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foe',
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bas',
|
||||||
|
params: { nip: 5, pwd: 10, id: 15 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('merges parent patterns if needed', () => {
|
||||||
|
const path = 'foo/42/baz/babel';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
Foo: {
|
||||||
|
path: 'foo/:bar',
|
||||||
|
parse: {
|
||||||
|
bar: Number,
|
||||||
|
},
|
||||||
|
screens: {
|
||||||
|
Baz: 'baz/:qux',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
params: { bar: 42 },
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Baz',
|
||||||
|
params: { qux: 'babel' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ignores extra slashes in the pattern', () => {
|
||||||
|
const path = '/bar/42';
|
||||||
|
const config = {
|
||||||
|
Foo: {
|
||||||
|
screens: {
|
||||||
|
Bar: {
|
||||||
|
path: '/bar//:id/',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Foo',
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'Bar',
|
||||||
|
params: { id: '42' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(state);
|
||||||
|
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -379,6 +379,8 @@ it("doesn't update state if action wasn't handled", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('cleans up state when the navigator unmounts', () => {
|
it('cleans up state when the navigator unmounts', () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
|
||||||
const TestNavigator = (props: any) => {
|
const TestNavigator = (props: any) => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
@@ -426,6 +428,8 @@ it('cleans up state when the navigator unmounts', () => {
|
|||||||
<BaseNavigationContainer onStateChange={onStateChange} children={null} />
|
<BaseNavigationContainer onStateChange={onStateChange} children={null} />
|
||||||
);
|
);
|
||||||
|
|
||||||
|
act(() => jest.runAllTimers());
|
||||||
|
|
||||||
expect(onStateChange).toBeCalledTimes(2);
|
expect(onStateChange).toBeCalledTimes(2);
|
||||||
expect(onStateChange).lastCalledWith(undefined);
|
expect(onStateChange).lastCalledWith(undefined);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,16 +9,15 @@ type State = NavigationState | Omit<PartialState<NavigationState>, 'stale'>;
|
|||||||
|
|
||||||
type StringifyConfig = Record<string, (value: any) => string>;
|
type StringifyConfig = Record<string, (value: any) => string>;
|
||||||
|
|
||||||
type Options = {
|
type OptionsItem = {
|
||||||
[routeName: string]:
|
path?: string;
|
||||||
| string
|
exact?: boolean;
|
||||||
| {
|
stringify?: StringifyConfig;
|
||||||
path?: string;
|
screens?: Options;
|
||||||
stringify?: StringifyConfig;
|
|
||||||
screens?: Options;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Options = Record<string, string | OptionsItem>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility to serialize a navigation state object to a path string.
|
* Utility to serialize a navigation state object to a path string.
|
||||||
*
|
*
|
||||||
@@ -53,96 +52,99 @@ export default function getPathFromState(
|
|||||||
if (state === undefined) {
|
if (state === undefined) {
|
||||||
throw Error('NavigationState not passed');
|
throw Error('NavigationState not passed');
|
||||||
}
|
}
|
||||||
let path = '/';
|
|
||||||
|
|
||||||
|
// Create a normalized configs array which will be easier to use
|
||||||
|
const configs = createNormalizedConfigs(options);
|
||||||
|
|
||||||
|
let path = '/';
|
||||||
let current: State | undefined = state;
|
let current: State | undefined = state;
|
||||||
|
|
||||||
|
const allParams: Record<string, any> = {};
|
||||||
|
|
||||||
while (current) {
|
while (current) {
|
||||||
let index = typeof current.index === 'number' ? current.index : 0;
|
let index = typeof current.index === 'number' ? current.index : 0;
|
||||||
let route = current.routes[index] as Route<string> & {
|
let route = current.routes[index] as Route<string> & {
|
||||||
state?: State;
|
state?: State;
|
||||||
};
|
};
|
||||||
let currentOptions = options;
|
|
||||||
let pattern = route.name;
|
|
||||||
// we keep all the route names that appeared during going deeper in config in case the pattern is resolved to undefined
|
|
||||||
let nestedRouteNames = '';
|
|
||||||
|
|
||||||
while (route.name in currentOptions) {
|
let pattern: string | undefined;
|
||||||
if (typeof currentOptions[route.name] === 'string') {
|
|
||||||
pattern = currentOptions[route.name] as string;
|
let currentParams: Record<string, any> = { ...route.params };
|
||||||
break;
|
let currentOptions = configs;
|
||||||
} else if (typeof currentOptions[route.name] === 'object') {
|
|
||||||
// if there is no `screens` property, we return pattern
|
// Keep all the route names that appeared during going deeper in config in case the pattern is resolved to undefined
|
||||||
if (
|
let nestedRouteNames = [];
|
||||||
!(currentOptions[route.name] as {
|
|
||||||
screens: Options;
|
let hasNext = true;
|
||||||
}).screens
|
|
||||||
) {
|
while (route.name in currentOptions && hasNext) {
|
||||||
pattern = (currentOptions[route.name] as { path: string }).path;
|
pattern = currentOptions[route.name].pattern;
|
||||||
nestedRouteNames = `${nestedRouteNames}/${route.name}`;
|
|
||||||
break;
|
nestedRouteNames.push(route.name);
|
||||||
|
|
||||||
|
if (route.params) {
|
||||||
|
const stringify = currentOptions[route.name]?.stringify;
|
||||||
|
|
||||||
|
currentParams = Object.fromEntries(
|
||||||
|
Object.entries(route.params).map(([key, value]) => [
|
||||||
|
key,
|
||||||
|
stringify?.[key] ? stringify[key](value) : String(value),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pattern) {
|
||||||
|
Object.assign(allParams, currentParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no `screens` property or no nested state, we return pattern
|
||||||
|
if (!currentOptions[route.name].screens || route.state === undefined) {
|
||||||
|
hasNext = false;
|
||||||
|
} else {
|
||||||
|
index =
|
||||||
|
typeof route.state.index === 'number'
|
||||||
|
? route.state.index
|
||||||
|
: route.state.routes.length - 1;
|
||||||
|
|
||||||
|
const nextRoute = route.state.routes[index];
|
||||||
|
const nestedConfig = currentOptions[route.name].screens;
|
||||||
|
|
||||||
|
// if there is config for next route name, we go deeper
|
||||||
|
if (nestedConfig && nextRoute.name in nestedConfig) {
|
||||||
|
route = nextRoute as Route<string> & { state?: State };
|
||||||
|
currentOptions = nestedConfig;
|
||||||
} else {
|
} else {
|
||||||
// if it is the end of state, we return pattern
|
// If not, there is no sense in going deeper in config
|
||||||
if (route.state === undefined) {
|
hasNext = false;
|
||||||
pattern = (currentOptions[route.name] as { path: string }).path;
|
|
||||||
nestedRouteNames = `${nestedRouteNames}/${route.name}`;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
index =
|
|
||||||
typeof route.state.index === 'number' ? route.state.index : 0;
|
|
||||||
const nextRoute = route.state.routes[index];
|
|
||||||
const deeperConfig = (currentOptions[route.name] as {
|
|
||||||
screens: Options;
|
|
||||||
}).screens;
|
|
||||||
// if there is config for next route name, we go deeper
|
|
||||||
if (nextRoute.name in deeperConfig) {
|
|
||||||
nestedRouteNames = `${nestedRouteNames}/${route.name}`;
|
|
||||||
route = nextRoute as Route<string> & { state?: State };
|
|
||||||
currentOptions = deeperConfig;
|
|
||||||
} else {
|
|
||||||
// if not, there is no sense in going deeper in config
|
|
||||||
pattern = (currentOptions[route.name] as { path: string }).path;
|
|
||||||
nestedRouteNames = `${nestedRouteNames}/${route.name}`;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pattern === undefined) {
|
if (pattern === undefined) {
|
||||||
// cut the first `/`
|
pattern = nestedRouteNames.join('/');
|
||||||
pattern = nestedRouteNames.substring(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const config =
|
|
||||||
currentOptions[route.name] !== undefined
|
|
||||||
? (currentOptions[route.name] as { stringify?: StringifyConfig })
|
|
||||||
.stringify
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const params = route.params
|
|
||||||
? // Stringify all of the param values before we use them
|
|
||||||
Object.entries(route.params).reduce<{
|
|
||||||
[key: string]: string;
|
|
||||||
}>((acc, [key, value]) => {
|
|
||||||
acc[key] = config?.[key] ? config[key](value) : String(value);
|
|
||||||
return acc;
|
|
||||||
}, {})
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
if (currentOptions[route.name] !== undefined) {
|
if (currentOptions[route.name] !== undefined) {
|
||||||
path += pattern
|
path += pattern
|
||||||
.split('/')
|
.split('/')
|
||||||
.map((p) => {
|
.map((p) => {
|
||||||
const name = p.replace(/^:/, '');
|
const name = p.replace(/^:/, '').replace(/\?$/, '');
|
||||||
|
|
||||||
// If the path has a pattern for a param, put the param in the path
|
// If the path has a pattern for a param, put the param in the path
|
||||||
if (params && name in params && p.startsWith(':')) {
|
if (p.startsWith(':')) {
|
||||||
const value = params[name];
|
const value = allParams[name];
|
||||||
|
|
||||||
// Remove the used value from the params object since we'll use the rest for query string
|
// Remove the used value from the params object since we'll use the rest for query string
|
||||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
if (currentParams) {
|
||||||
delete params[name];
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||||
|
delete currentParams[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === undefined && p.endsWith('?')) {
|
||||||
|
// Optional params without value assigned in route.params should be ignored
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
return encodeURIComponent(value);
|
return encodeURIComponent(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,14 +157,15 @@ export default function getPathFromState(
|
|||||||
|
|
||||||
if (route.state) {
|
if (route.state) {
|
||||||
path += '/';
|
path += '/';
|
||||||
} else if (params) {
|
} else if (currentParams) {
|
||||||
for (let param in params) {
|
for (let param in currentParams) {
|
||||||
if (params[param] === 'undefined') {
|
if (currentParams[param] === 'undefined') {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||||
delete params[param];
|
delete currentParams[param];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const query = queryString.stringify(params);
|
|
||||||
|
const query = queryString.stringify(currentParams);
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
path += `?${query}`;
|
path += `?${query}`;
|
||||||
@@ -173,8 +176,64 @@ export default function getPathFromState(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove multiple as well as trailing slashes
|
// Remove multiple as well as trailing slashes
|
||||||
path = path.replace(/\/+/, '/');
|
path = path.replace(/\/+/g, '/');
|
||||||
path = path.length > 1 ? path.replace(/\/$/, '') : path;
|
path = path.length > 1 ? path.replace(/\/$/, '') : path;
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ConfigItem = {
|
||||||
|
pattern?: string;
|
||||||
|
stringify?: StringifyConfig;
|
||||||
|
screens?: Record<string, ConfigItem>;
|
||||||
|
};
|
||||||
|
|
||||||
|
function joinPaths(...paths: string[]): string {
|
||||||
|
return ([] as string[])
|
||||||
|
.concat(...paths.map((p) => p.split('/')))
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function createConfigItem(
|
||||||
|
config: OptionsItem | string,
|
||||||
|
parentPattern?: string
|
||||||
|
): ConfigItem {
|
||||||
|
if (typeof config === 'string') {
|
||||||
|
// If a string is specified as the value of the key(e.g. Foo: '/path'), use it as the pattern
|
||||||
|
const pattern = parentPattern ? joinPaths(parentPattern, config) : config;
|
||||||
|
|
||||||
|
return { pattern };
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an object is specified as the value (e.g. Foo: { ... }),
|
||||||
|
// It can have `path` property and `screens` prop which has nested configs
|
||||||
|
const pattern =
|
||||||
|
config.exact !== true && parentPattern && config.path
|
||||||
|
? joinPaths(parentPattern, config.path)
|
||||||
|
: config.path;
|
||||||
|
|
||||||
|
const screens = config.screens
|
||||||
|
? createNormalizedConfigs(config.screens, pattern)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
// Normalize pattern to remove any leading, trailing slashes, duplicate slashes etc.
|
||||||
|
pattern: pattern?.split('/').filter(Boolean).join('/'),
|
||||||
|
stringify: config.stringify,
|
||||||
|
screens,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNormalizedConfigs(
|
||||||
|
options: Options,
|
||||||
|
pattern?: string
|
||||||
|
): Record<string, ConfigItem> {
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(options).map(([name, c]) => {
|
||||||
|
const result = createConfigItem(c, pattern);
|
||||||
|
|
||||||
|
return [name, result];
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import escape from 'escape-string-regexp';
|
||||||
import queryString from 'query-string';
|
import queryString from 'query-string';
|
||||||
import {
|
import {
|
||||||
NavigationState,
|
NavigationState,
|
||||||
@@ -12,6 +13,7 @@ type Options = {
|
|||||||
| string
|
| string
|
||||||
| {
|
| {
|
||||||
path?: string;
|
path?: string;
|
||||||
|
exact?: boolean;
|
||||||
parse?: ParseConfig;
|
parse?: ParseConfig;
|
||||||
screens?: Options;
|
screens?: Options;
|
||||||
initialRouteName?: string;
|
initialRouteName?: string;
|
||||||
@@ -20,10 +22,11 @@ type Options = {
|
|||||||
|
|
||||||
type RouteConfig = {
|
type RouteConfig = {
|
||||||
screen: string;
|
screen: string;
|
||||||
match: string | null;
|
regex?: RegExp;
|
||||||
|
path: string;
|
||||||
pattern: string;
|
pattern: string;
|
||||||
routeNames: string[];
|
routeNames: string[];
|
||||||
parse: ParseConfig | undefined;
|
parse?: ParseConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
type InitialRouteConfig = {
|
type InitialRouteConfig = {
|
||||||
@@ -61,40 +64,48 @@ export default function getStateFromPath(
|
|||||||
let initialRoutes: InitialRouteConfig[] = [];
|
let initialRoutes: InitialRouteConfig[] = [];
|
||||||
|
|
||||||
// Create a normalized configs array which will be easier to use
|
// Create a normalized configs array which will be easier to use
|
||||||
const configs = ([] as RouteConfig[]).concat(
|
const configs = ([] as RouteConfig[])
|
||||||
...Object.keys(options).map((key) =>
|
.concat(
|
||||||
createNormalizedConfigs(key, options, [], initialRoutes)
|
...Object.keys(options).map((key) =>
|
||||||
|
createNormalizedConfigs(key, options, [], initialRoutes)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
.sort(
|
||||||
|
(a, b) =>
|
||||||
// sort configs so the most exhaustive is always first to be chosen
|
// Sort configs so the most exhaustive is always first to be chosen
|
||||||
configs.sort(
|
b.pattern.split('/').length - a.pattern.split('/').length
|
||||||
(config1, config2) =>
|
);
|
||||||
config2.pattern.split('/').length - config1.pattern.split('/').length
|
|
||||||
);
|
|
||||||
|
|
||||||
let remaining = path
|
let remaining = path
|
||||||
.replace(/[/]+/, '/') // Replace multiple slash (//) with single ones
|
.replace(/\/+/g, '/') // Replace multiple slash (//) with single ones
|
||||||
.replace(/^\//, '') // Remove extra leading slash
|
.replace(/^\//, '') // Remove extra leading slash
|
||||||
.replace(/\?.*/, ''); // Remove query params which we will handle later
|
.replace(/\?.*$/, ''); // Remove query params which we will handle later
|
||||||
|
|
||||||
if (remaining === '') {
|
// Make sure there is a trailing slash
|
||||||
|
remaining = remaining.endsWith('/') ? remaining : `${remaining}/`;
|
||||||
|
|
||||||
|
if (remaining === '/') {
|
||||||
// We need to add special handling of empty path so navigation to empty path also works
|
// We need to add special handling of empty path so navigation to empty path also works
|
||||||
// When handling empty path, we should only look at the root level config
|
// When handling empty path, we should only look at the root level config
|
||||||
const match = configs.find(
|
const match = configs.find(
|
||||||
(config) =>
|
(config) =>
|
||||||
config.pattern === '' &&
|
config.path === '' &&
|
||||||
config.routeNames.every(
|
config.routeNames.every(
|
||||||
// make sure that none of the parent configs have a non-empty path defined
|
// Make sure that none of the parent configs have a non-empty path defined
|
||||||
(name) => !configs.find((c) => c.screen === name)?.pattern
|
(name) => !configs.find((c) => c.screen === name)?.path
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
return createNestedStateObject(
|
return createNestedStateObject(
|
||||||
match.routeNames,
|
match.routeNames.map((name, i, self) => {
|
||||||
initialRoutes,
|
if (i === self.length - 1) {
|
||||||
parseQueryParams(path, match.parse)
|
return { name, params: parseQueryParams(path, match.parse) };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { name };
|
||||||
|
}),
|
||||||
|
initialRoutes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,35 +117,18 @@ export default function getStateFromPath(
|
|||||||
|
|
||||||
while (remaining) {
|
while (remaining) {
|
||||||
let routeNames: string[] | undefined;
|
let routeNames: string[] | undefined;
|
||||||
let params: Record<string, any> | undefined;
|
let allParams: Record<string, any> | undefined;
|
||||||
|
|
||||||
// Go through all configs, and see if the next path segment matches our regex
|
// Go through all configs, and see if the next path segment matches our regex
|
||||||
for (const config of configs) {
|
for (const config of configs) {
|
||||||
if (!config.match) {
|
if (!config.regex) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let didMatch = true;
|
const match = remaining.match(config.regex);
|
||||||
const matchParts = config.match.split('/');
|
|
||||||
const remainingParts = remaining.split('/');
|
|
||||||
|
|
||||||
// we check if remaining path has enough segments to be handled with this pattern
|
// If our regex matches, we need to extract params from the path
|
||||||
if (config.pattern.split('/').length > remainingParts.length) {
|
if (match) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we keep info about the index of segment on which the params start
|
|
||||||
let paramsIndex = 0;
|
|
||||||
// the beginning of the remaining path should be the same as the part of config before params
|
|
||||||
for (paramsIndex; paramsIndex < matchParts.length; paramsIndex++) {
|
|
||||||
if (matchParts[paramsIndex] !== remainingParts[paramsIndex]) {
|
|
||||||
didMatch = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the first part of the path matches, we need to extract params from the path
|
|
||||||
if (didMatch) {
|
|
||||||
routeNames = [...config.routeNames];
|
routeNames = [...config.routeNames];
|
||||||
|
|
||||||
const paramPatterns = config.pattern
|
const paramPatterns = config.pattern
|
||||||
@@ -142,28 +136,16 @@ export default function getStateFromPath(
|
|||||||
.filter((p) => p.startsWith(':'));
|
.filter((p) => p.startsWith(':'));
|
||||||
|
|
||||||
if (paramPatterns.length) {
|
if (paramPatterns.length) {
|
||||||
params = paramPatterns.reduce<Record<string, any>>((acc, p, i) => {
|
allParams = paramPatterns.reduce<Record<string, any>>((acc, p, i) => {
|
||||||
const key = p.replace(/^:/, '');
|
const value = match![(i + 1) * 2].replace(/\//, ''); // The param segments appear every second item starting from 2 in the regex match result
|
||||||
const value = remainingParts[i + paramsIndex]; // The param segments start from the end of matched part
|
|
||||||
acc[key] =
|
acc[p] = value;
|
||||||
config.parse && config.parse[key]
|
|
||||||
? config.parse[key](value)
|
|
||||||
: value;
|
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// if pattern and remaining path have same amount of segments, there should be nothing left
|
remaining = remaining.replace(match[1], '');
|
||||||
if (config.pattern.split('/').length === remainingParts.length) {
|
|
||||||
remaining = '';
|
|
||||||
} else {
|
|
||||||
// For each segment of the pattern, remove one segment from remaining path
|
|
||||||
let i = config.pattern.split('/').length;
|
|
||||||
while (i--) {
|
|
||||||
remaining = remaining.substr(remaining.indexOf('/') + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -178,7 +160,46 @@ export default function getStateFromPath(
|
|||||||
remaining = segments.join('/');
|
remaining = segments.join('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = createNestedStateObject(routeNames, initialRoutes, params);
|
const state = createNestedStateObject(
|
||||||
|
routeNames.map((name) => {
|
||||||
|
const config = configs.find((c) => c.screen === name);
|
||||||
|
|
||||||
|
let params: object | undefined;
|
||||||
|
|
||||||
|
if (allParams && config?.path) {
|
||||||
|
const pattern = config.path;
|
||||||
|
|
||||||
|
if (pattern) {
|
||||||
|
const paramPatterns = pattern
|
||||||
|
.split('/')
|
||||||
|
.filter((p) => p.startsWith(':'));
|
||||||
|
|
||||||
|
if (paramPatterns.length) {
|
||||||
|
params = paramPatterns.reduce<Record<string, any>>((acc, p) => {
|
||||||
|
const key = p.replace(/^:/, '').replace(/\?$/, '');
|
||||||
|
const value = allParams![p];
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
acc[key] =
|
||||||
|
config.parse && config.parse[key]
|
||||||
|
? config.parse[key](value)
|
||||||
|
: value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params && Object.keys(params).length) {
|
||||||
|
return { name, params };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { name };
|
||||||
|
}),
|
||||||
|
initialRoutes
|
||||||
|
);
|
||||||
|
|
||||||
if (current) {
|
if (current) {
|
||||||
// The state should be nested inside the deepest route we parsed before
|
// The state should be nested inside the deepest route we parsed before
|
||||||
@@ -213,44 +234,66 @@ export default function getStateFromPath(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function joinPaths(...paths: string[]): string {
|
||||||
|
return ([] as string[])
|
||||||
|
.concat(...paths.map((p) => p.split('/')))
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('/');
|
||||||
|
}
|
||||||
|
|
||||||
function createNormalizedConfigs(
|
function createNormalizedConfigs(
|
||||||
key: string,
|
screen: string,
|
||||||
routeConfig: Options,
|
routeConfig: Options,
|
||||||
routeNames: string[] = [],
|
routeNames: string[] = [],
|
||||||
initials: InitialRouteConfig[]
|
initials: InitialRouteConfig[],
|
||||||
|
parentPattern?: string
|
||||||
): RouteConfig[] {
|
): RouteConfig[] {
|
||||||
const configs: RouteConfig[] = [];
|
const configs: RouteConfig[] = [];
|
||||||
|
|
||||||
routeNames.push(key);
|
routeNames.push(screen);
|
||||||
|
|
||||||
const value = routeConfig[key];
|
const config = routeConfig[screen];
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
if (typeof config === 'string') {
|
||||||
// If a string is specified as the value of the key(e.g. Foo: '/path'), use it as the pattern
|
// If a string is specified as the value of the key(e.g. Foo: '/path'), use it as the pattern
|
||||||
configs.push(createConfigItem(key, routeNames, value));
|
const pattern = parentPattern ? joinPaths(parentPattern, config) : config;
|
||||||
} else if (typeof value === 'object') {
|
|
||||||
|
configs.push(createConfigItem(screen, routeNames, pattern, config));
|
||||||
|
} else if (typeof config === 'object') {
|
||||||
|
let pattern: string | undefined;
|
||||||
|
|
||||||
// if an object is specified as the value (e.g. Foo: { ... }),
|
// if an object is specified as the value (e.g. Foo: { ... }),
|
||||||
// it can have `path` property and
|
// it can have `path` property and
|
||||||
// it could have `screens` prop which has nested configs
|
// it could have `screens` prop which has nested configs
|
||||||
if (typeof value.path === 'string') {
|
if (typeof config.path === 'string') {
|
||||||
configs.push(createConfigItem(key, routeNames, value.path, value.parse));
|
pattern =
|
||||||
|
config.exact !== true && parentPattern
|
||||||
|
? joinPaths(parentPattern, config.path)
|
||||||
|
: config.path;
|
||||||
|
|
||||||
|
configs.push(
|
||||||
|
createConfigItem(screen, routeNames, pattern, config.path, config.parse)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value.screens) {
|
if (config.screens) {
|
||||||
// property `initialRouteName` without `screens` has no purpose
|
// property `initialRouteName` without `screens` has no purpose
|
||||||
if (value.initialRouteName) {
|
if (config.initialRouteName) {
|
||||||
initials.push({
|
initials.push({
|
||||||
initialRouteName: value.initialRouteName,
|
initialRouteName: config.initialRouteName,
|
||||||
connectedRoutes: Object.keys(value.screens),
|
connectedRoutes: Object.keys(config.screens),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Object.keys(value.screens).forEach((nestedConfig) => {
|
|
||||||
|
Object.keys(config.screens).forEach((nestedConfig) => {
|
||||||
const result = createNormalizedConfigs(
|
const result = createNormalizedConfigs(
|
||||||
nestedConfig,
|
nestedConfig,
|
||||||
value.screens as Options,
|
config.screens as Options,
|
||||||
routeNames,
|
routeNames,
|
||||||
initials
|
initials,
|
||||||
|
pattern
|
||||||
);
|
);
|
||||||
|
|
||||||
configs.push(...result);
|
configs.push(...result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -265,15 +308,32 @@ function createConfigItem(
|
|||||||
screen: string,
|
screen: string,
|
||||||
routeNames: string[],
|
routeNames: string[],
|
||||||
pattern: string,
|
pattern: string,
|
||||||
|
path: string,
|
||||||
parse?: ParseConfig
|
parse?: ParseConfig
|
||||||
): RouteConfig {
|
): RouteConfig {
|
||||||
// part being matched ends on the first param
|
// Normalize pattern to remove any leading, trailing slashes, duplicate slashes etc.
|
||||||
const match = pattern !== '' ? pattern.split('/:')[0] : null;
|
pattern = pattern.split('/').filter(Boolean).join('/');
|
||||||
|
|
||||||
|
const regex = pattern
|
||||||
|
? new RegExp(
|
||||||
|
`^(${pattern
|
||||||
|
.split('/')
|
||||||
|
.map((it) => {
|
||||||
|
if (it.startsWith(':')) {
|
||||||
|
return `(([^/]+\\/)${it.endsWith('?') ? '?' : ''})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${escape(it)}\\/`;
|
||||||
|
})
|
||||||
|
.join('')})`
|
||||||
|
)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
screen,
|
screen,
|
||||||
match,
|
regex,
|
||||||
pattern,
|
pattern,
|
||||||
|
path,
|
||||||
// The routeNames array is mutated, so copy it to keep the current state
|
// The routeNames array is mutated, so copy it to keep the current state
|
||||||
routeNames: [...routeNames],
|
routeNames: [...routeNames],
|
||||||
parse,
|
parse,
|
||||||
@@ -312,21 +372,18 @@ function findInitialRoute(
|
|||||||
function createStateObject(
|
function createStateObject(
|
||||||
initialRoute: string | undefined,
|
initialRoute: string | undefined,
|
||||||
routeName: string,
|
routeName: string,
|
||||||
isEmpty: boolean,
|
params: Record<string, any> | undefined,
|
||||||
params?: Record<string, any> | undefined
|
isEmpty: boolean
|
||||||
): InitialState {
|
): InitialState {
|
||||||
if (isEmpty) {
|
if (isEmpty) {
|
||||||
if (initialRoute) {
|
if (initialRoute) {
|
||||||
return {
|
return {
|
||||||
index: 1,
|
index: 1,
|
||||||
routes: [
|
routes: [{ name: initialRoute }, { name: routeName as string, params }],
|
||||||
{ name: initialRoute },
|
|
||||||
{ name: routeName as string, ...(params && { params }) },
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
routes: [{ name: routeName as string, ...(params && { params }) }],
|
routes: [{ name: routeName as string, params }],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -335,44 +392,50 @@ function createStateObject(
|
|||||||
index: 1,
|
index: 1,
|
||||||
routes: [
|
routes: [
|
||||||
{ name: initialRoute },
|
{ name: initialRoute },
|
||||||
{ name: routeName as string, state: { routes: [] } },
|
{ name: routeName as string, params, state: { routes: [] } },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return { routes: [{ name: routeName as string, state: { routes: [] } }] };
|
return {
|
||||||
|
routes: [{ name: routeName as string, params, state: { routes: [] } }],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNestedStateObject(
|
function createNestedStateObject(
|
||||||
routeNames: string[],
|
routes: { name: string; params?: object }[],
|
||||||
initialRoutes: InitialRouteConfig[],
|
initialRoutes: InitialRouteConfig[]
|
||||||
params: object | undefined
|
|
||||||
) {
|
) {
|
||||||
let state: InitialState;
|
let state: InitialState;
|
||||||
let routeName = routeNames.shift() as string;
|
let route = routes.shift() as { name: string; params?: object };
|
||||||
let initialRoute = findInitialRoute(routeName, initialRoutes);
|
let initialRoute = findInitialRoute(route.name, initialRoutes);
|
||||||
|
|
||||||
state = createStateObject(
|
state = createStateObject(
|
||||||
initialRoute,
|
initialRoute,
|
||||||
routeName,
|
route.name,
|
||||||
routeNames.length === 0,
|
route.params,
|
||||||
params
|
routes.length === 0
|
||||||
);
|
);
|
||||||
|
|
||||||
if (routeNames.length > 0) {
|
if (routes.length > 0) {
|
||||||
let nestedState = state;
|
let nestedState = state;
|
||||||
|
|
||||||
while ((routeName = routeNames.shift() as string)) {
|
while ((route = routes.shift() as { name: string; params?: object })) {
|
||||||
initialRoute = findInitialRoute(routeName, initialRoutes);
|
initialRoute = findInitialRoute(route.name, initialRoutes);
|
||||||
nestedState.routes[nestedState.index || 0].state = createStateObject(
|
|
||||||
|
const nestedStateIndex =
|
||||||
|
nestedState.index || nestedState.routes.length - 1;
|
||||||
|
|
||||||
|
nestedState.routes[nestedStateIndex].state = createStateObject(
|
||||||
initialRoute,
|
initialRoute,
|
||||||
routeName,
|
route.name,
|
||||||
routeNames.length === 0,
|
route.params,
|
||||||
params
|
routes.length === 0
|
||||||
);
|
);
|
||||||
if (routeNames.length > 0) {
|
|
||||||
nestedState = nestedState.routes[nestedState.index || 0]
|
if (routes.length > 0) {
|
||||||
|
nestedState = nestedState.routes[nestedStateIndex]
|
||||||
.state as InitialState;
|
.state as InitialState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import useNavigation from './useNavigation';
|
|||||||
*/
|
*/
|
||||||
export default function useIsFocused(): boolean {
|
export default function useIsFocused(): boolean {
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
const getCurrentValue = React.useCallback(navigation.isFocused, [navigation]);
|
const getCurrentValue = React.useCallback(navigation.isFocused, [navigation]);
|
||||||
const subscribe = React.useCallback(
|
const subscribe = React.useCallback(
|
||||||
(callback: (value: boolean) => void) => {
|
(callback: (value: boolean) => void) => {
|
||||||
|
|||||||
@@ -362,9 +362,14 @@ export default function useNavigationBuilder<
|
|||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
// We need to clean up state for this navigator on unmount
|
// We need to clean up state for this navigator on unmount
|
||||||
if (getCurrentState() !== undefined && getKey() === navigatorKey) {
|
// We do it in a timeout because we need to detect if another navigator mounted in the meantime
|
||||||
setState(undefined);
|
// For example, if another navigator has started rendering, we should skip cleanup
|
||||||
}
|
// Otherwise, our cleanup step will cleanup state for the other navigator and re-initialize it
|
||||||
|
setTimeout(() => {
|
||||||
|
if (getCurrentState() !== undefined && getKey() === navigatorKey) {
|
||||||
|
setState(undefined);
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -8,6 +8,15 @@ const UNINTIALIZED_STATE = {};
|
|||||||
export default function useSyncState<T>(initialState?: (() => T) | T) {
|
export default function useSyncState<T>(initialState?: (() => T) | T) {
|
||||||
const stateRef = React.useRef<T>(UNINTIALIZED_STATE as any);
|
const stateRef = React.useRef<T>(UNINTIALIZED_STATE as any);
|
||||||
const isSchedulingRef = React.useRef(false);
|
const isSchedulingRef = React.useRef(false);
|
||||||
|
const isMountedRef = React.useRef(true);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
isMountedRef.current = true;
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
isMountedRef.current = false;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (stateRef.current === UNINTIALIZED_STATE) {
|
if (stateRef.current === UNINTIALIZED_STATE) {
|
||||||
stateRef.current =
|
stateRef.current =
|
||||||
@@ -20,7 +29,7 @@ export default function useSyncState<T>(initialState?: (() => T) | T) {
|
|||||||
const getState = React.useCallback(() => stateRef.current, []);
|
const getState = React.useCallback(() => stateRef.current, []);
|
||||||
|
|
||||||
const setState = React.useCallback((state: T) => {
|
const setState = React.useCallback((state: T) => {
|
||||||
if (state === stateRef.current) {
|
if (state === stateRef.current || !isMountedRef.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +51,10 @@ export default function useSyncState<T>(initialState?: (() => T) | T) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const flushUpdates = React.useCallback(() => {
|
const flushUpdates = React.useCallback(() => {
|
||||||
|
if (!isMountedRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure that the tracking state is up-to-date.
|
// Make sure that the tracking state is up-to-date.
|
||||||
// We call it unconditionally, but React should skip the update if state is unchanged.
|
// We call it unconditionally, but React should skip the update if state is unchanged.
|
||||||
setTrackingState(stateRef.current);
|
setTrackingState(stateRef.current);
|
||||||
|
|||||||
@@ -3,6 +3,84 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [5.7.4](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.7.3...@react-navigation/drawer@5.7.4) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.7.3](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.7.2...@react-navigation/drawer@5.7.3) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.7.2](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.7.1...@react-navigation/drawer@5.7.2) (2020-05-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.7.1](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.7.0...@react-navigation/drawer@5.7.1) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix building typescript definitions. closes [#8216](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/8216) ([47a1229](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/47a12298378747edd2d22e54dc1c8677f98c49b4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.7.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.6.4...@react-navigation/drawer@5.7.0) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add generic type aliases for screen props ([bea14aa](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/bea14aa26fd5cbfebc7973733c5cf1f44fd323aa)), closes [#7971](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/7971)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.6.4](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.6.3...@react-navigation/drawer@5.6.4) (2020-05-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.6.3](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.6.2...@react-navigation/drawer@5.6.3) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.6.2](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.6.1...@react-navigation/drawer@5.6.2) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.6.1](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.6.0...@react-navigation/drawer@5.6.1) (2020-04-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.6.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.5.1...@react-navigation/drawer@5.6.0) (2020-04-30)
|
# [5.6.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.5.1...@react-navigation/drawer@5.6.0) (2020-04-30)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/drawer",
|
"name": "@react-navigation/drawer",
|
||||||
"description": "Drawer navigator component with animated transitions and gesturess",
|
"description": "Drawer navigator component with animated transitions and gesturess",
|
||||||
"version": "5.6.0",
|
"version": "5.7.4",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
"homepage": "https://reactnavigation.org/docs/drawer-navigator.html",
|
"homepage": "https://reactnavigation.org/docs/drawer-navigator.html",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "src/index.tsx",
|
"react-native": "src/index.tsx",
|
||||||
|
"source": "src/index.tsx",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
"types": "lib/typescript/src/index.d.ts",
|
"types": "lib/typescript/src/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -39,17 +40,17 @@
|
|||||||
"react-native-iphone-x-helper": "^1.2.1"
|
"react-native-iphone-x-helper": "^1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.10.0",
|
"@react-native-community/bob": "^0.13.1",
|
||||||
"@react-navigation/native": "^5.2.0",
|
"@react-navigation/native": "^5.3.2",
|
||||||
"@types/react": "^16.9.23",
|
"@types/react": "^16.9.34",
|
||||||
"@types/react-native": "^0.61.22",
|
"@types/react-native": "^0.62.7",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-gesture-handler": "^1.6.0",
|
"react-native-gesture-handler": "^1.6.0",
|
||||||
"react-native-reanimated": "^1.7.0",
|
"react-native-reanimated": "^1.8.0",
|
||||||
"react-native-safe-area-context": "^0.7.3",
|
"react-native-safe-area-context": "^0.7.3",
|
||||||
"react-native-screens": "^2.3.0",
|
"react-native-screens": "^2.7.0",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export { default as useIsDrawerOpen } from './utils/useIsDrawerOpen';
|
|||||||
export type {
|
export type {
|
||||||
DrawerNavigationOptions,
|
DrawerNavigationOptions,
|
||||||
DrawerNavigationProp,
|
DrawerNavigationProp,
|
||||||
|
DrawerScreenProps,
|
||||||
DrawerContentOptions,
|
DrawerContentOptions,
|
||||||
DrawerContentComponentProps,
|
DrawerContentComponentProps,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
NavigationHelpers,
|
NavigationHelpers,
|
||||||
DrawerNavigationState,
|
DrawerNavigationState,
|
||||||
DrawerActionHelpers,
|
DrawerActionHelpers,
|
||||||
|
RouteProp,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
import type { PanGestureHandlerProperties } from 'react-native-gesture-handler';
|
import type { PanGestureHandlerProperties } from 'react-native-gesture-handler';
|
||||||
|
|
||||||
@@ -208,6 +209,14 @@ export type DrawerNavigationProp<
|
|||||||
> &
|
> &
|
||||||
DrawerActionHelpers<ParamList>;
|
DrawerActionHelpers<ParamList>;
|
||||||
|
|
||||||
|
export type DrawerScreenProps<
|
||||||
|
ParamList extends ParamListBase,
|
||||||
|
RouteName extends keyof ParamList = string
|
||||||
|
> = {
|
||||||
|
navigation: DrawerNavigationProp<ParamList, RouteName>;
|
||||||
|
route: RouteProp<ParamList, RouteName>;
|
||||||
|
};
|
||||||
|
|
||||||
export type DrawerDescriptor = Descriptor<
|
export type DrawerDescriptor = Descriptor<
|
||||||
ParamListBase,
|
ParamListBase,
|
||||||
string,
|
string,
|
||||||
|
|||||||
@@ -655,14 +655,14 @@ export default class DrawerView extends React.Component<Props> {
|
|||||||
gestureEnabled ? () => this.toggleDrawer(false) : undefined
|
gestureEnabled ? () => this.toggleDrawer(false) : undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Overlay progress={progress} style={overlayStyle} />
|
<Overlay progress={progress} style={overlayStyle as any} />
|
||||||
</TouchableWithoutFeedback>
|
</TouchableWithoutFeedback>
|
||||||
) : (
|
) : (
|
||||||
<TapGestureHandler
|
<TapGestureHandler
|
||||||
enabled={gestureEnabled}
|
enabled={gestureEnabled}
|
||||||
onHandlerStateChange={this.handleTapStateChange}
|
onHandlerStateChange={this.handleTapStateChange}
|
||||||
>
|
>
|
||||||
<Overlay progress={progress} style={overlayStyle} />
|
<Overlay progress={progress} style={overlayStyle as any} />
|
||||||
</TapGestureHandler>
|
</TapGestureHandler>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,85 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [5.2.4](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.2.3...@react-navigation/material-bottom-tabs@5.2.4) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.3](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.2.2...@react-navigation/material-bottom-tabs@5.2.3) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.2](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.2.1...@react-navigation/material-bottom-tabs@5.2.2) (2020-05-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.1](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.2.0...@react-navigation/material-bottom-tabs@5.2.1) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix building typescript definitions. closes [#8216](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/issues/8216) ([47a1229](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/commit/47a12298378747edd2d22e54dc1c8677f98c49b4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.15...@react-navigation/material-bottom-tabs@5.2.0) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add generic type aliases for screen props ([bea14aa](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/commit/bea14aa26fd5cbfebc7973733c5cf1f44fd323aa)), closes [#7971](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/issues/7971)
|
||||||
|
* use links in bottom navigation tabs ([f384706](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/commit/f384706741f7e2422c284b65da10425f7af680c0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.15](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.14...@react-navigation/material-bottom-tabs@5.1.15) (2020-05-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.14](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.13...@react-navigation/material-bottom-tabs@5.1.14) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.13](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.12...@react-navigation/material-bottom-tabs@5.1.13) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.12](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.11...@react-navigation/material-bottom-tabs@5.1.12) (2020-04-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.1.11](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.10...@react-navigation/material-bottom-tabs@5.1.11) (2020-04-30)
|
## [5.1.11](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.10...@react-navigation/material-bottom-tabs@5.1.11) (2020-04-30)
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/material-bottom-tabs",
|
"name": "@react-navigation/material-bottom-tabs",
|
||||||
"description": "Integration for bottom navigation component from react-native-paper",
|
"description": "Integration for bottom navigation component from react-native-paper",
|
||||||
"version": "5.1.11",
|
"version": "5.2.4",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
"homepage": "https://reactnavigation.org/docs/material-bottom-tab-navigator.html",
|
"homepage": "https://reactnavigation.org/docs/material-bottom-tab-navigator.html",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "src/index.tsx",
|
"react-native": "src/index.tsx",
|
||||||
|
"source": "src/index.tsx",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
"types": "lib/typescript/src/index.d.ts",
|
"types": "lib/typescript/src/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -35,15 +36,15 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.10.0",
|
"@react-native-community/bob": "^0.13.1",
|
||||||
"@react-navigation/native": "^5.2.0",
|
"@react-navigation/native": "^5.3.2",
|
||||||
"@types/react": "^16.9.23",
|
"@types/react": "^16.9.34",
|
||||||
"@types/react-native": "^0.61.22",
|
"@types/react-native": "^0.62.7",
|
||||||
"@types/react-native-vector-icons": "^6.4.5",
|
"@types/react-native-vector-icons": "^6.4.5",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-paper": "^3.7.0",
|
"react-native-paper": "^3.10.1",
|
||||||
"react-native-vector-icons": "^6.6.0",
|
"react-native-vector-icons": "^6.6.0",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,4 +14,5 @@ export { default as MaterialBottomTabView } from './views/MaterialBottomTabView'
|
|||||||
export type {
|
export type {
|
||||||
MaterialBottomTabNavigationOptions,
|
MaterialBottomTabNavigationOptions,
|
||||||
MaterialBottomTabNavigationProp,
|
MaterialBottomTabNavigationProp,
|
||||||
|
MaterialBottomTabScreenProps,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
NavigationHelpers,
|
NavigationHelpers,
|
||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
TabActionHelpers,
|
TabActionHelpers,
|
||||||
|
RouteProp,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
|
|
||||||
export type MaterialBottomTabNavigationEventMap = {
|
export type MaterialBottomTabNavigationEventMap = {
|
||||||
@@ -32,6 +33,14 @@ export type MaterialBottomTabNavigationProp<
|
|||||||
> &
|
> &
|
||||||
TabActionHelpers<ParamList>;
|
TabActionHelpers<ParamList>;
|
||||||
|
|
||||||
|
export type MaterialBottomTabScreenProps<
|
||||||
|
ParamList extends ParamListBase,
|
||||||
|
RouteName extends keyof ParamList = string
|
||||||
|
> = {
|
||||||
|
navigation: MaterialBottomTabNavigationProp<ParamList, RouteName>;
|
||||||
|
route: RouteProp<ParamList, RouteName>;
|
||||||
|
};
|
||||||
|
|
||||||
export type MaterialBottomTabNavigationOptions = {
|
export type MaterialBottomTabNavigationOptions = {
|
||||||
/**
|
/**
|
||||||
* Title text for the screen.
|
* Title text for the screen.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet, Platform } from 'react-native';
|
||||||
import { BottomNavigation, DefaultTheme, DarkTheme } from 'react-native-paper';
|
import { BottomNavigation, DefaultTheme, DarkTheme } from 'react-native-paper';
|
||||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
import {
|
import {
|
||||||
@@ -8,6 +8,8 @@ import {
|
|||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
TabActions,
|
TabActions,
|
||||||
useTheme,
|
useTheme,
|
||||||
|
useLinkBuilder,
|
||||||
|
Link,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -24,13 +26,14 @@ type Props = MaterialBottomTabNavigationConfig & {
|
|||||||
|
|
||||||
type Scene = { route: { key: string } };
|
type Scene = { route: { key: string } };
|
||||||
|
|
||||||
export default function MaterialBottomTabView({
|
function MaterialBottomTabViewInner({
|
||||||
state,
|
state,
|
||||||
navigation,
|
navigation,
|
||||||
descriptors,
|
descriptors,
|
||||||
...rest
|
...rest
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { dark, colors } = useTheme();
|
const { dark, colors } = useTheme();
|
||||||
|
const buildLink = useLinkBuilder();
|
||||||
|
|
||||||
const theme = React.useMemo(() => {
|
const theme = React.useMemo(() => {
|
||||||
const t = dark ? DarkTheme : DefaultTheme;
|
const t = dark ? DarkTheme : DefaultTheme;
|
||||||
@@ -46,67 +49,102 @@ export default function MaterialBottomTabView({
|
|||||||
}, [colors, dark]);
|
}, [colors, dark]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationHelpersContext.Provider value={navigation}>
|
<BottomNavigation
|
||||||
<BottomNavigation
|
{...rest}
|
||||||
{...rest}
|
theme={theme}
|
||||||
theme={theme}
|
navigationState={state}
|
||||||
navigationState={state}
|
onIndexChange={(index: number) =>
|
||||||
onIndexChange={(index: number) =>
|
navigation.dispatch({
|
||||||
navigation.dispatch({
|
...TabActions.jumpTo(state.routes[index].name),
|
||||||
...TabActions.jumpTo(state.routes[index].name),
|
target: state.key,
|
||||||
target: state.key,
|
})
|
||||||
})
|
}
|
||||||
|
renderScene={({ route }) => descriptors[route.key].render()}
|
||||||
|
renderTouchable={
|
||||||
|
Platform.OS === 'web'
|
||||||
|
? ({
|
||||||
|
onPress,
|
||||||
|
route,
|
||||||
|
accessibilityRole: _0,
|
||||||
|
borderless: _1,
|
||||||
|
centered: _2,
|
||||||
|
rippleColor: _3,
|
||||||
|
...rest
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
{...rest}
|
||||||
|
// @ts-ignore
|
||||||
|
to={buildLink(route.name, route.params)}
|
||||||
|
accessibilityRole="link"
|
||||||
|
onPress={(e: any) => {
|
||||||
|
if (
|
||||||
|
!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) && // ignore clicks with modifier keys
|
||||||
|
(e.button == null || e.button === 0) // ignore everything but left clicks
|
||||||
|
) {
|
||||||
|
e.preventDefault();
|
||||||
|
onPress?.(e);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
renderIcon={({ route, focused, color }) => {
|
||||||
|
const { options } = descriptors[route.key];
|
||||||
|
|
||||||
|
if (typeof options.tabBarIcon === 'string') {
|
||||||
|
return (
|
||||||
|
<MaterialCommunityIcons
|
||||||
|
name={options.tabBarIcon}
|
||||||
|
color={color}
|
||||||
|
size={24}
|
||||||
|
style={styles.icon}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
renderScene={({ route }) => descriptors[route.key].render()}
|
|
||||||
renderIcon={({ route, focused, color }) => {
|
|
||||||
const { options } = descriptors[route.key];
|
|
||||||
|
|
||||||
if (typeof options.tabBarIcon === 'string') {
|
if (typeof options.tabBarIcon === 'function') {
|
||||||
return (
|
return options.tabBarIcon({ focused, color });
|
||||||
<MaterialCommunityIcons
|
|
||||||
name={options.tabBarIcon}
|
|
||||||
color={color}
|
|
||||||
size={24}
|
|
||||||
style={styles.icon}
|
|
||||||
importantForAccessibility="no-hide-descendants"
|
|
||||||
accessibilityElementsHidden
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof options.tabBarIcon === 'function') {
|
|
||||||
return options.tabBarIcon({ focused, color });
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}}
|
|
||||||
getLabelText={({ route }: Scene) => {
|
|
||||||
const { options } = descriptors[route.key];
|
|
||||||
|
|
||||||
return options.tabBarLabel !== undefined
|
|
||||||
? options.tabBarLabel
|
|
||||||
: options.title !== undefined
|
|
||||||
? options.title
|
|
||||||
: (route as Route<string>).name;
|
|
||||||
}}
|
|
||||||
getColor={({ route }) => descriptors[route.key].options.tabBarColor}
|
|
||||||
getBadge={({ route }) => descriptors[route.key].options.tabBarBadge}
|
|
||||||
getAccessibilityLabel={({ route }) =>
|
|
||||||
descriptors[route.key].options.tabBarAccessibilityLabel
|
|
||||||
}
|
}
|
||||||
getTestID={({ route }) => descriptors[route.key].options.tabBarTestID}
|
|
||||||
onTabPress={({ route, preventDefault }) => {
|
|
||||||
const event = navigation.emit({
|
|
||||||
type: 'tabPress',
|
|
||||||
target: route.key,
|
|
||||||
canPreventDefault: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (event.defaultPrevented) {
|
return null;
|
||||||
preventDefault();
|
}}
|
||||||
}
|
getLabelText={({ route }: Scene) => {
|
||||||
}}
|
const { options } = descriptors[route.key];
|
||||||
/>
|
|
||||||
|
return options.tabBarLabel !== undefined
|
||||||
|
? options.tabBarLabel
|
||||||
|
: options.title !== undefined
|
||||||
|
? options.title
|
||||||
|
: (route as Route<string>).name;
|
||||||
|
}}
|
||||||
|
getColor={({ route }) => descriptors[route.key].options.tabBarColor}
|
||||||
|
getBadge={({ route }) => descriptors[route.key].options.tabBarBadge}
|
||||||
|
getAccessibilityLabel={({ route }) =>
|
||||||
|
descriptors[route.key].options.tabBarAccessibilityLabel
|
||||||
|
}
|
||||||
|
getTestID={({ route }) => descriptors[route.key].options.tabBarTestID}
|
||||||
|
onTabPress={({ route, preventDefault }) => {
|
||||||
|
const event = navigation.emit({
|
||||||
|
type: 'tabPress',
|
||||||
|
target: route.key,
|
||||||
|
canPreventDefault: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (event.defaultPrevented) {
|
||||||
|
preventDefault();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function MaterialBottomTabView(props: Props) {
|
||||||
|
return (
|
||||||
|
<NavigationHelpersContext.Provider value={props.navigation}>
|
||||||
|
<MaterialBottomTabViewInner {...props} />
|
||||||
</NavigationHelpersContext.Provider>
|
</NavigationHelpersContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,84 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [5.2.4](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.2.3...@react-navigation/material-top-tabs@5.2.4) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.3](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.2.2...@react-navigation/material-top-tabs@5.2.3) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.2](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.2.1...@react-navigation/material-top-tabs@5.2.2) (2020-05-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.1](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.2.0...@react-navigation/material-top-tabs@5.2.1) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix building typescript definitions. closes [#8216](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/issues/8216) ([47a1229](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/commit/47a12298378747edd2d22e54dc1c8677f98c49b4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.15...@react-navigation/material-top-tabs@5.2.0) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add generic type aliases for screen props ([bea14aa](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/commit/bea14aa26fd5cbfebc7973733c5cf1f44fd323aa)), closes [#7971](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/issues/7971)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.15](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.14...@react-navigation/material-top-tabs@5.1.15) (2020-05-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.14](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.13...@react-navigation/material-top-tabs@5.1.14) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.13](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.12...@react-navigation/material-top-tabs@5.1.13) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.12](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.11...@react-navigation/material-top-tabs@5.1.12) (2020-04-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.1.11](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.10...@react-navigation/material-top-tabs@5.1.11) (2020-04-30)
|
## [5.1.11](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.10...@react-navigation/material-top-tabs@5.1.11) (2020-04-30)
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/material-top-tabs",
|
"name": "@react-navigation/material-top-tabs",
|
||||||
"description": "Integration for the animated tab view component from react-native-tab-view",
|
"description": "Integration for the animated tab view component from react-native-tab-view",
|
||||||
"version": "5.1.11",
|
"version": "5.2.4",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
"homepage": "https://reactnavigation.org/docs/material-top-tab-navigator.html",
|
"homepage": "https://reactnavigation.org/docs/material-top-tab-navigator.html",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "src/index.tsx",
|
"react-native": "src/index.tsx",
|
||||||
|
"source": "src/index.tsx",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
"types": "lib/typescript/src/index.d.ts",
|
"types": "lib/typescript/src/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -38,15 +39,15 @@
|
|||||||
"color": "^3.1.2"
|
"color": "^3.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.10.0",
|
"@react-native-community/bob": "^0.13.1",
|
||||||
"@react-navigation/native": "^5.2.0",
|
"@react-navigation/native": "^5.3.2",
|
||||||
"@types/react": "^16.9.23",
|
"@types/react": "^16.9.34",
|
||||||
"@types/react-native": "^0.61.22",
|
"@types/react-native": "^0.62.7",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-gesture-handler": "^1.6.0",
|
"react-native-gesture-handler": "^1.6.0",
|
||||||
"react-native-reanimated": "^1.7.0",
|
"react-native-reanimated": "^1.8.0",
|
||||||
"react-native-tab-view": "^2.14.0",
|
"react-native-tab-view": "^2.14.0",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export { default as MaterialTopTabBar } from './views/MaterialTopTabBar';
|
|||||||
export type {
|
export type {
|
||||||
MaterialTopTabNavigationOptions,
|
MaterialTopTabNavigationOptions,
|
||||||
MaterialTopTabNavigationProp,
|
MaterialTopTabNavigationProp,
|
||||||
|
MaterialTopTabScreenProps,
|
||||||
MaterialTopTabBarProps,
|
MaterialTopTabBarProps,
|
||||||
MaterialTopTabBarOptions,
|
MaterialTopTabBarOptions,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
NavigationProp,
|
NavigationProp,
|
||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
TabActionHelpers,
|
TabActionHelpers,
|
||||||
|
RouteProp,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
|
|
||||||
export type MaterialTopTabNavigationEventMap = {
|
export type MaterialTopTabNavigationEventMap = {
|
||||||
@@ -46,6 +47,14 @@ export type MaterialTopTabNavigationProp<
|
|||||||
> &
|
> &
|
||||||
TabActionHelpers<ParamList>;
|
TabActionHelpers<ParamList>;
|
||||||
|
|
||||||
|
export type MaterialTopTabScreenProps<
|
||||||
|
ParamList extends ParamListBase,
|
||||||
|
RouteName extends keyof ParamList = string
|
||||||
|
> = {
|
||||||
|
navigation: MaterialTopTabNavigationProp<ParamList, RouteName>;
|
||||||
|
route: RouteProp<ParamList, RouteName>;
|
||||||
|
};
|
||||||
|
|
||||||
export type MaterialTopTabNavigationOptions = {
|
export type MaterialTopTabNavigationOptions = {
|
||||||
/**
|
/**
|
||||||
* Title text for the screen.
|
* Title text for the screen.
|
||||||
|
|||||||
@@ -3,6 +3,99 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [5.3.2](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.3.1...@react-navigation/native@5.3.2) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.1](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.3.0...@react-navigation/native@5.3.1) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.3.0](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.2.6...@react-navigation/native@5.3.0) (2020-05-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* initialState should take priority over deep link ([039017b](https://github.com/react-navigation/react-navigation/tree/master/packages/native/commit/039017bc2af69120d2d10e8f2c8a62919c37eb65))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.6](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.2.5...@react-navigation/native@5.2.6) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix building typescript definitions. closes [#8216](https://github.com/react-navigation/react-navigation/tree/master/packages/native/issues/8216) ([47a1229](https://github.com/react-navigation/react-navigation/tree/master/packages/native/commit/47a12298378747edd2d22e54dc1c8677f98c49b4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.5](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.2.4...@react-navigation/native@5.2.5) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* return a promise-like from getInitialState ([#8210](https://github.com/react-navigation/react-navigation/tree/master/packages/native/issues/8210)) ([85ae378](https://github.com/react-navigation/react-navigation/tree/master/packages/native/commit/85ae378d8cb1073895b281e13ebccee881d4c062))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.4](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.2.3...@react-navigation/native@5.2.4) (2020-05-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* return undefined for buildLink if linking is not enabled ([9fd2635](https://github.com/react-navigation/react-navigation/tree/master/packages/native/commit/9fd2635756362c8da79656b4d9b101bebaaf7003))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.3](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.2.2...@react-navigation/native@5.2.3) (2020-05-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* default linking enabled to true ([c7b8e2e](https://github.com/react-navigation/react-navigation/tree/master/packages/native/commit/c7b8e2e9666733143eef156b27f3e4995c36b856))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.2](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.2.1...@react-navigation/native@5.2.2) (2020-05-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* don't throw when using 'useLinking'. fixes [#8171](https://github.com/react-navigation/react-navigation/tree/master/packages/native/issues/8171) ([10eca8b](https://github.com/react-navigation/react-navigation/tree/master/packages/native/commit/10eca8b92edbce6dbef8abaf189e4b59a29b3748))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.1](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.2.0...@react-navigation/native@5.2.1) (2020-04-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* render fallback only if linking is enabled. closes [#8161](https://github.com/react-navigation/react-navigation/tree/master/packages/native/issues/8161) ([1c075ff](https://github.com/react-navigation/react-navigation/tree/master/packages/native/commit/1c075ffb169d233ed0515efea264a5a69b4de52e))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.1.7...@react-navigation/native@5.2.0) (2020-04-30)
|
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.1.7...@react-navigation/native@5.2.0) (2020-04-30)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/native",
|
"name": "@react-navigation/native",
|
||||||
"description": "React Native integration for React Navigation",
|
"description": "React Native integration for React Navigation",
|
||||||
"version": "5.2.0",
|
"version": "5.3.2",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native",
|
"react-native",
|
||||||
"react-navigation",
|
"react-navigation",
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
"homepage": "https://reactnavigation.org",
|
"homepage": "https://reactnavigation.org",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "src/index.tsx",
|
"react-native": "src/index.tsx",
|
||||||
|
"source": "src/index.tsx",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
"types": "lib/typescript/src/index.d.ts",
|
"types": "lib/typescript/src/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -31,16 +32,16 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/core": "^5.4.0"
|
"@react-navigation/core": "^5.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.10.0",
|
"@react-native-community/bob": "^0.13.1",
|
||||||
"@types/react": "^16.9.23",
|
"@types/react": "^16.9.34",
|
||||||
"@types/react-native": "^0.61.22",
|
"@types/react-native": "^0.62.7",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-testing-library": "^1.12.0",
|
"react-native-testing-library": "^1.13.2",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type Props = NavigationContainerProps & {
|
|||||||
* Container component which holds the navigation state designed for React Native apps.
|
* Container component which holds the navigation state designed for React Native apps.
|
||||||
* This should be rendered at the root wrapping the whole app.
|
* This should be rendered at the root wrapping the whole app.
|
||||||
*
|
*
|
||||||
* @param props.initialState Initial state object for the navigation tree. When deep link handling is enabled, this will be ignored if there's an incoming link.
|
* @param props.initialState Initial state object for the navigation tree. When deep link handling is enabled, this will override deep links when specified. Make sure that you don't specify an `initialState` when there's a deep link (`Linking.getInitialURL()`).
|
||||||
* @param props.onStateChange Callback which is called with the latest navigation state when it changes.
|
* @param props.onStateChange Callback which is called with the latest navigation state when it changes.
|
||||||
* @param props.theme Theme object for the navigators.
|
* @param props.theme Theme object for the navigators.
|
||||||
* @param props.linking Options for deep linking. Deep link handling is enabled when this prop is provided, unless `linking.enabled` is `false`.
|
* @param props.linking Options for deep linking. Deep link handling is enabled when this prop is provided, unless `linking.enabled` is `false`.
|
||||||
@@ -46,15 +46,13 @@ const NavigationContainer = React.forwardRef(function NavigationContainer(
|
|||||||
...linking,
|
...linking,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [isReady, initialState = rest.initialState] = useThenable(
|
const [isReady, initialState] = useThenable(getInitialState);
|
||||||
getInitialState
|
|
||||||
);
|
|
||||||
|
|
||||||
React.useImperativeHandle(ref, () => refContainer.current);
|
React.useImperativeHandle(ref, () => refContainer.current);
|
||||||
|
|
||||||
const linkingContext = React.useMemo(() => ({ options: linking }), [linking]);
|
const linkingContext = React.useMemo(() => ({ options: linking }), [linking]);
|
||||||
|
|
||||||
if (!isReady) {
|
if (rest.initialState == null && isLinkingEnabled && !isReady) {
|
||||||
// This is temporary until we have Suspense for data-fetching
|
// This is temporary until we have Suspense for data-fetching
|
||||||
// Then the fallback will be handled by a parent `Suspense` component
|
// Then the fallback will be handled by a parent `Suspense` component
|
||||||
return fallback as React.ReactElement;
|
return fallback as React.ReactElement;
|
||||||
@@ -65,7 +63,9 @@ const NavigationContainer = React.forwardRef(function NavigationContainer(
|
|||||||
<ThemeProvider value={theme}>
|
<ThemeProvider value={theme}>
|
||||||
<BaseNavigationContainer
|
<BaseNavigationContainer
|
||||||
{...rest}
|
{...rest}
|
||||||
initialState={initialState}
|
initialState={
|
||||||
|
rest.initialState == null ? initialState : rest.initialState
|
||||||
|
}
|
||||||
ref={refContainer}
|
ref={refContainer}
|
||||||
/>
|
/>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ it('throws if multiple instances of useLinking are used', () => {
|
|||||||
let element;
|
let element;
|
||||||
|
|
||||||
expect(() => (element = render(<Sample />))).toThrowError(
|
expect(() => (element = render(<Sample />))).toThrowError(
|
||||||
"Looks like you are using 'useLinking' in multiple components."
|
'Looks like you have configured linking in multiple places.'
|
||||||
);
|
);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -41,9 +41,7 @@ it('throws if multiple instances of useLinking are used', () => {
|
|||||||
<B />
|
<B />
|
||||||
</>
|
</>
|
||||||
))
|
))
|
||||||
).toThrowError(
|
).toThrowError('Looks like you have configured linking in multiple places.');
|
||||||
"Looks like you are using 'useLinking' in multiple components."
|
|
||||||
);
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
element?.unmount();
|
element?.unmount();
|
||||||
@@ -57,5 +55,19 @@ it('throws if multiple instances of useLinking are used', () => {
|
|||||||
|
|
||||||
render(wrapper2).unmount();
|
render(wrapper2).unmount();
|
||||||
|
|
||||||
expect(() => render(wrapper2)).not.toThrow();
|
expect(() => (element = render(wrapper2))).not.toThrow();
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
element?.unmount();
|
||||||
|
|
||||||
|
function Sample3() {
|
||||||
|
useLinking(ref, options);
|
||||||
|
useLinking(ref, { ...options, enabled: false });
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(() => (element = render(<Sample3 />))).not.toThrowError();
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
element?.unmount();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -52,14 +52,18 @@ export default function useLinkBuilder() {
|
|||||||
(name: string, params?: object) => {
|
(name: string, params?: object) => {
|
||||||
const { options } = linking;
|
const { options } = linking;
|
||||||
|
|
||||||
// If we couldn't find a navigation object in context, we're at root
|
if (options?.enabled === false) {
|
||||||
// So we'll construct a basic state object to use
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const state = navigation
|
const state = navigation
|
||||||
? getRootStateForNavigate(navigation, {
|
? getRootStateForNavigate(navigation, {
|
||||||
index: 0,
|
index: 0,
|
||||||
routes: [{ name, params }],
|
routes: [{ name, params }],
|
||||||
})
|
})
|
||||||
: {
|
: // If we couldn't find a navigation object in context, we're at root
|
||||||
|
// So we'll construct a basic state object to use
|
||||||
|
{
|
||||||
index: 0,
|
index: 0,
|
||||||
routes: [{ name, params }],
|
routes: [{ name, params }],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -49,6 +49,14 @@ export default function useLinkProps({ to, action }: Props) {
|
|||||||
throw new Error("Couldn't find a navigation object.");
|
throw new Error("Couldn't find a navigation object.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (typeof to !== 'string') {
|
||||||
|
throw new Error(
|
||||||
|
`To 'to' option is invalid (found '${String(
|
||||||
|
to
|
||||||
|
)}'. It must be a valid string for navigation.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
linkTo(to);
|
linkTo(to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,22 +12,28 @@ let isUsingLinking = false;
|
|||||||
export default function useLinking(
|
export default function useLinking(
|
||||||
ref: React.RefObject<NavigationContainerRef>,
|
ref: React.RefObject<NavigationContainerRef>,
|
||||||
{
|
{
|
||||||
enabled,
|
enabled = true,
|
||||||
prefixes,
|
prefixes,
|
||||||
config,
|
config,
|
||||||
getStateFromPath = getStateFromPathDefault,
|
getStateFromPath = getStateFromPathDefault,
|
||||||
}: LinkingOptions
|
}: LinkingOptions
|
||||||
) {
|
) {
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (isUsingLinking) {
|
if (enabled !== false && isUsingLinking) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Looks like you are using 'useLinking' in multiple components. This is likely an error since deep links should only be handled in one place to avoid conflicts." +
|
[
|
||||||
(Platform.OS === 'android'
|
'Looks like you have configured linking in multiple places. This is likely an error since deep links should only be handled in one place to avoid conflicts. Make sure that:',
|
||||||
? "\n\nIf you're not using it in multiple components, ensure that you have set 'android:launchMode=singleTask' in the '<activity />' section of the 'AndroidManifest.xml' file to avoid launching multiple activities which run multiple instances of the root component."
|
"- You are not using both 'linking' prop and 'useLinking'",
|
||||||
: '')
|
"- You don't have 'useLinking' in multiple components",
|
||||||
|
Platform.OS === 'android'
|
||||||
|
? "- You have set 'android:launchMode=singleTask' in the '<activity />' section of the 'AndroidManifest.xml' file to avoid launching multiple instances"
|
||||||
|
: '',
|
||||||
|
]
|
||||||
|
.join('\n')
|
||||||
|
.trim()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
isUsingLinking = true;
|
isUsingLinking = enabled !== false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -43,19 +43,25 @@ let isUsingLinking = false;
|
|||||||
export default function useLinking(
|
export default function useLinking(
|
||||||
ref: React.RefObject<NavigationContainerRef>,
|
ref: React.RefObject<NavigationContainerRef>,
|
||||||
{
|
{
|
||||||
enabled,
|
enabled = true,
|
||||||
config,
|
config,
|
||||||
getStateFromPath = getStateFromPathDefault,
|
getStateFromPath = getStateFromPathDefault,
|
||||||
getPathFromState = getPathFromStateDefault,
|
getPathFromState = getPathFromStateDefault,
|
||||||
}: LinkingOptions
|
}: LinkingOptions
|
||||||
) {
|
) {
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (isUsingLinking) {
|
if (enabled !== false && isUsingLinking) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Looks like you are using 'useLinking' in multiple components. This is likely an error since URL integration should only be handled in one place to avoid conflicts. Also ensure that you set your android activity launchMode to single task in your AndroiManifest.xml file."
|
[
|
||||||
|
'Looks like you have configured linking in multiple places. This is likely an error since URL integration should only be handled in one place to avoid conflicts. Make sure that:',
|
||||||
|
"- You are not using both 'linking' prop and 'useLinking'",
|
||||||
|
"- You don't have 'useLinking' in multiple components",
|
||||||
|
]
|
||||||
|
.join('\n')
|
||||||
|
.trim()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
isUsingLinking = true;
|
isUsingLinking = enabled !== false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -89,18 +95,17 @@ export default function useLinking(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const then = (callback: (state: ResultState | undefined) => void) =>
|
|
||||||
Promise.resolve(callback(value));
|
|
||||||
|
|
||||||
// Make it a thenable to keep consistent with the native impl
|
// Make it a thenable to keep consistent with the native impl
|
||||||
const thenable = {
|
const thenable = {
|
||||||
then,
|
then(onfulfilled?: (state: ResultState | undefined) => void) {
|
||||||
|
return Promise.resolve(onfulfilled ? onfulfilled(value) : value);
|
||||||
|
},
|
||||||
catch() {
|
catch() {
|
||||||
return thenable;
|
return thenable;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return thenable;
|
return thenable as PromiseLike<ResultState | undefined>;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const previousStateLengthRef = React.useRef<number | undefined>(undefined);
|
const previousStateLengthRef = React.useRef<number | undefined>(undefined);
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
type Thenable<T> = { then(cb: (result: T) => void): void };
|
export default function useThenable<T>(create: () => PromiseLike<T>) {
|
||||||
|
|
||||||
export default function useThenable<T>(create: () => Thenable<T>) {
|
|
||||||
const [promise] = React.useState(create);
|
const [promise] = React.useState(create);
|
||||||
|
|
||||||
// Check if our thenable is synchronous
|
// Check if our thenable is synchronous
|
||||||
|
|||||||
@@ -3,6 +3,25 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [5.4.4](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.4.3...@react-navigation/routers@5.4.4) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix building typescript definitions. closes [#8216](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/issues/8216) ([47a1229](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/commit/47a12298378747edd2d22e54dc1c8677f98c49b4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.4.3](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.4.2...@react-navigation/routers@5.4.3) (2020-05-08)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/routers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.4.2](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.4.1...@react-navigation/routers@5.4.2) (2020-04-30)
|
## [5.4.2](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.4.1...@react-navigation/routers@5.4.2) (2020-04-30)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/routers",
|
"name": "@react-navigation/routers",
|
||||||
"description": "Routers to help build custom navigators",
|
"description": "Routers to help build custom navigators",
|
||||||
"version": "5.4.2",
|
"version": "5.4.4",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
"react-native",
|
"react-native",
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
"homepage": "https://reactnavigation.org/docs/custom-routers.html",
|
"homepage": "https://reactnavigation.org/docs/custom-routers.html",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "src/index.tsx",
|
"react-native": "src/index.tsx",
|
||||||
|
"source": "src/index.tsx",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
"types": "lib/typescript/src/index.d.ts",
|
"types": "lib/typescript/src/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -30,10 +31,10 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.0.2"
|
"nanoid": "^3.1.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.10.0",
|
"@react-native-community/bob": "^0.13.1",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,101 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [5.3.5](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.3.4...@react-navigation/stack@5.3.5) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.4](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.3.3...@react-navigation/stack@5.3.4) (2020-05-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.3](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.3.2...@react-navigation/stack@5.3.3) (2020-05-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix ios transitionspec settle time ([#8028](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/8028)) ([dd7cff2](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/dd7cff201608365a80f1d50a006df3e0d18e94a1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.2](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.3.1...@react-navigation/stack@5.3.2) (2020-05-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.1](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.3.0...@react-navigation/stack@5.3.1) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix building typescript definitions. closes [#8216](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/8216) ([47a1229](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/47a12298378747edd2d22e54dc1c8677f98c49b4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.3.0](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.19...@react-navigation/stack@5.3.0) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add proper margins to the header title ([f07cd13](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/f07cd135619d635e8841aa0df0b6e687636e7408))
|
||||||
|
* include safe are insets in title's margins ([4d1e102](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/4d1e102f8c3ffab116d0195fbab3086f6345a077))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add generic type aliases for screen props ([bea14aa](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/bea14aa26fd5cbfebc7973733c5cf1f44fd323aa)), closes [#7971](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7971)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.19](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.18...@react-navigation/stack@5.2.19) (2020-05-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.18](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.17...@react-navigation/stack@5.2.18) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.17](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.16...@react-navigation/stack@5.2.17) (2020-05-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.16](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.15...@react-navigation/stack@5.2.16) (2020-04-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.2.15](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.14...@react-navigation/stack@5.2.15) (2020-04-30)
|
## [5.2.15](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.14...@react-navigation/stack@5.2.15) (2020-04-30)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/stack",
|
"name": "@react-navigation/stack",
|
||||||
"description": "Stack navigator component for iOS and Android with animated transitions and gestures",
|
"description": "Stack navigator component for iOS and Android with animated transitions and gestures",
|
||||||
"version": "5.2.15",
|
"version": "5.3.5",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
"homepage": "https://reactnavigation.org/docs/stack-navigator.html",
|
"homepage": "https://reactnavigation.org/docs/stack-navigator.html",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "src/index.tsx",
|
"react-native": "src/index.tsx",
|
||||||
|
"source": "src/index.tsx",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
"types": "lib/typescript/src/index.d.ts",
|
"types": "lib/typescript/src/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -38,18 +39,18 @@
|
|||||||
"react-native-iphone-x-helper": "^1.2.1"
|
"react-native-iphone-x-helper": "^1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.10.0",
|
"@react-native-community/bob": "^0.13.1",
|
||||||
"@react-native-community/masked-view": "^0.1.7",
|
"@react-native-community/masked-view": "^0.1.10",
|
||||||
"@react-navigation/native": "^5.2.0",
|
"@react-navigation/native": "^5.3.2",
|
||||||
"@types/color": "^3.0.1",
|
"@types/color": "^3.0.1",
|
||||||
"@types/react": "^16.9.23",
|
"@types/react": "^16.9.34",
|
||||||
"@types/react-native": "^0.61.22",
|
"@types/react-native": "^0.62.7",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-gesture-handler": "^1.6.0",
|
"react-native-gesture-handler": "^1.6.0",
|
||||||
"react-native-safe-area-context": "^0.7.3",
|
"react-native-safe-area-context": "^0.7.3",
|
||||||
"react-native-screens": "^2.3.0",
|
"react-native-screens": "^2.7.0",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ export const TransitionIOSSpec: TransitionSpec = {
|
|||||||
damping: 500,
|
damping: 500,
|
||||||
mass: 3,
|
mass: 3,
|
||||||
overshootClamping: true,
|
overshootClamping: true,
|
||||||
restDisplacementThreshold: 0.01,
|
restDisplacementThreshold: 10,
|
||||||
restSpeedThreshold: 0.01,
|
restSpeedThreshold: 10,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ export { default as useGestureHandlerRef } from './utils/useGestureHandlerRef';
|
|||||||
export type {
|
export type {
|
||||||
StackNavigationOptions,
|
StackNavigationOptions,
|
||||||
StackNavigationProp,
|
StackNavigationProp,
|
||||||
|
StackScreenProps,
|
||||||
StackHeaderProps,
|
StackHeaderProps,
|
||||||
StackHeaderLeftButtonProps,
|
StackHeaderLeftButtonProps,
|
||||||
StackHeaderTitleProps,
|
StackHeaderTitleProps,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
NavigationHelpers,
|
NavigationHelpers,
|
||||||
StackNavigationState,
|
StackNavigationState,
|
||||||
StackActionHelpers,
|
StackActionHelpers,
|
||||||
|
RouteProp,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
|
|
||||||
export type StackNavigationEventMap = {
|
export type StackNavigationEventMap = {
|
||||||
@@ -45,6 +46,14 @@ export type StackNavigationProp<
|
|||||||
> &
|
> &
|
||||||
StackActionHelpers<ParamList>;
|
StackActionHelpers<ParamList>;
|
||||||
|
|
||||||
|
export type StackScreenProps<
|
||||||
|
ParamList extends ParamListBase,
|
||||||
|
RouteName extends keyof ParamList = string
|
||||||
|
> = {
|
||||||
|
navigation: StackNavigationProp<ParamList, RouteName>;
|
||||||
|
route: RouteProp<ParamList, RouteName>;
|
||||||
|
};
|
||||||
|
|
||||||
export type Layout = { width: number; height: number };
|
export type Layout = { width: number; height: number };
|
||||||
|
|
||||||
export type GestureDirection =
|
export type GestureDirection =
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export default React.memo(function Header(props: StackHeaderProps) {
|
|||||||
: previous.route.name;
|
: previous.route.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
const goBack = React.useCallback(
|
const goBack = React.useCallback(
|
||||||
debounce(() => {
|
debounce(() => {
|
||||||
if (navigation.isFocused() && navigation.canGoBack()) {
|
if (navigation.isFocused() && navigation.canGoBack()) {
|
||||||
|
|||||||
@@ -307,6 +307,8 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
|||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
const rightButton = right ? right({ tintColor: headerTintColor }) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Animated.View
|
<Animated.View
|
||||||
@@ -345,8 +347,17 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
|||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={[
|
style={[
|
||||||
headerTitleAlign === 'left'
|
headerTitleAlign === 'left'
|
||||||
? { position: 'absolute', left: leftButton ? 72 : 16 }
|
? {
|
||||||
: { marginHorizontal: 18 },
|
position: 'absolute',
|
||||||
|
left: (leftButton ? 72 : 16) + insets.left,
|
||||||
|
right: (rightButton ? 72 : 16) + insets.right,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
marginHorizontal:
|
||||||
|
(leftButton ? 32 : 16) +
|
||||||
|
(leftLabelLayout?.width || 0) +
|
||||||
|
Math.max(insets.left, insets.right),
|
||||||
|
},
|
||||||
titleStyle,
|
titleStyle,
|
||||||
titleContainerStyle,
|
titleContainerStyle,
|
||||||
]}
|
]}
|
||||||
@@ -359,7 +370,7 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
|||||||
style: customTitleStyle,
|
style: customTitleStyle,
|
||||||
})}
|
})}
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
{right ? (
|
{rightButton ? (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={[
|
style={[
|
||||||
@@ -369,7 +380,7 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
|||||||
rightContainerStyle,
|
rightContainerStyle,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{right({ tintColor: headerTintColor })}
|
{rightButton}
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
) : null}
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|||||||
import { Animated, StyleSheet, Platform } from 'react-native';
|
import { Animated, StyleSheet, Platform } from 'react-native';
|
||||||
import { useTheme } from '@react-navigation/native';
|
import { useTheme } from '@react-navigation/native';
|
||||||
|
|
||||||
type Props = React.ComponentProps<typeof Animated.Text> & {
|
type Props = Omit<React.ComponentProps<typeof Animated.Text>, 'key'> & {
|
||||||
tintColor?: string;
|
tintColor?: string;
|
||||||
children?: string;
|
children?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user