Compare commits

...

24 Commits

Author SHA1 Message Date
Satyajit Sahoo
49f658fbc0 chore: publish
- @react-navigation/bottom-tabs@5.2.6
 - @react-navigation/compat@5.1.8
 - @react-navigation/core@5.3.3
 - @react-navigation/drawer@5.4.1
 - @react-navigation/material-bottom-tabs@5.1.8
 - @react-navigation/material-top-tabs@5.1.8
 - @react-navigation/native@5.1.5
 - @react-navigation/routers@5.3.0
 - @react-navigation/stack@5.2.10
2020-04-08 12:17:31 +02:00
Satyajit Sahoo
cb2f157a56 fix: don't hide content from accessibility with permanent drawer
closes #7976
2020-04-08 12:17:09 +02:00
Juang, Yi-Lin
c4acdaa703 docs: fix typo (#7865) 2020-04-08 11:35:45 +02:00
Satyajit Sahoo
f1a8bceba5 fix: make color of shadow element same as card color in stack 2020-04-07 23:34:55 +02:00
Ruben Grimm
44081172d4 fix: use 1 as default in compatibility pop action 2020-04-07 23:33:38 +02:00
Satyajit Sahoo
de5d985f3b chore: upgrade depenendecies 2020-04-07 15:44:58 +02:00
Satyajit Sahoo
b71de6cc79 fix: mark type exports for all packages 2020-04-07 11:22:47 +02:00
raajnadar
303f0b78a5 fix: separate normal exports and type exports 2020-04-07 11:17:06 +02:00
Satyajit Sahoo
ce3994c82c fix: switch order of focus and blur events. closes #7963 2020-04-07 11:07:16 +02:00
Satyajit Sahoo
ba1f405129 feat: make replace bubble up 2020-04-07 00:02:54 +02:00
Satyajit Sahoo
d4fd906915 fix: workaround warning about setState in another component in render 2020-04-06 23:58:25 +02:00
Vinícius Fraga Modesto
b7fa90bf8d docs: fixes typo (#7923)
This PR fixes a typo in activeBackgroundColor's description
2020-03-31 17:56:26 +02:00
Satyajit Sahoo
9556aa9eff chore: publish
- @react-navigation/bottom-tabs@5.2.5
 - @react-navigation/compat@5.1.7
 - @react-navigation/core@5.3.2
 - @react-navigation/drawer@5.4.0
 - @react-navigation/material-bottom-tabs@5.1.7
 - @react-navigation/material-top-tabs@5.1.7
 - @react-navigation/native@5.1.4
 - @react-navigation/routers@5.2.1
 - @react-navigation/stack@5.2.9
2020-03-30 22:22:25 +02:00
Satyajit Sahoo
9a8fea8f2c fix: when comparing changed routes, only check keys 2020-03-30 22:20:16 +02:00
Satyajit Sahoo
9973db86f0 chore: use non-secure nanoid to be able to run in RN 2020-03-30 22:04:53 +02:00
max
8432e5ab25 fix: dismiss keyboard on screen change for android 2020-03-30 21:50:52 +02:00
Satyajit Sahoo
9bb5cfded3 refactor: replace shortid with nanoid. closes #7858 2020-03-30 21:42:58 +02:00
Satyajit Sahoo
4ac40b5c5d chore: update typescript and babel 2020-03-30 21:42:58 +02:00
Wojciech Lewicki
cd47915861 fix: handle no path property and undefined query params (#7911) 2020-03-30 17:11:33 +02:00
Andrius Janauskas
d649fbc669 fix: finish stack animation on CANCELLED event (#7898)
fixes #7897
2020-03-30 14:36:04 +02:00
Satyajit Sahoo
105da6ab2f fix: disable only swipe gesture on safari 2020-03-30 13:56:30 +02:00
Rajendran Nadar
ac7f972e92 feat: add swipeEnabled option to disable swipe gesture in drawer (#7834) 2020-03-30 13:51:32 +02:00
Satyajit Sahoo
babb5027f9 chore: publish
- @react-navigation/stack@5.2.8
2020-03-27 15:01:32 +01:00
Satyajit Sahoo
78d7a66b2b chore: remove detox dep coz we don't use it 2020-03-27 14:54:54 +01:00
60 changed files with 3231 additions and 3443 deletions

View File

@@ -7,7 +7,7 @@
"slug": "react-navigation-example", "slug": "react-navigation-example",
"description": "Demo app to showcase various functionality of React Navigation", "description": "Demo app to showcase various functionality of React Navigation",
"privacy": "public", "privacy": "public",
"sdkVersion": "36.0.0", "sdkVersion": "37.0.0",
"platforms": [ "platforms": [
"ios", "ios",
"android", "android",

View File

@@ -1,4 +1,4 @@
/* eslint-disable jest/no-jasmine-globals, import/no-commonjs */ /* eslint-disable import/no-commonjs */
const detox = require('detox'); const detox = require('detox');
const config = require('../../package.json').detox; const config = require('../../package.json').detox;

View File

@@ -12,31 +12,30 @@
}, },
"dependencies": { "dependencies": {
"@expo/vector-icons": "^10.0.0", "@expo/vector-icons": "^10.0.0",
"@react-native-community/masked-view": "0.1.7", "@react-native-community/masked-view": "^0.1.7",
"@types/react-native-restart": "^0.0.0",
"color": "^3.1.2", "color": "^3.1.2",
"expo": "^36.0.2", "expo": "^37.0.0",
"expo-asset": "~8.0.0", "expo-asset": "~8.1.3",
"expo-blur": "^8.0.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.6.0", "react-native-paper": "^3.7.0",
"react-native-reanimated": "^1.7.0", "react-native-reanimated": "^1.7.0",
"react-native-restart": "^0.0.14", "react-native-restart": "^0.0.14",
"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.3.0",
"react-native-tab-view": "2.13.0", "react-native-tab-view": "2.14.0",
"react-native-unimodules": "^0.7.0", "react-native-unimodules": "~0.8.1",
"react-native-web": "^0.11.7" "react-native-web": "^0.11.7"
}, },
"devDependencies": { "devDependencies": {
"@expo/webpack-config": "^0.11.7", "@expo/webpack-config": "^0.11.19",
"@types/react": "^16.9.23", "@types/react": "^16.9.23",
"@types/react-native": "^0.61.22", "@types/react-native": "^0.60.22",
"babel-preset-expo": "^8.0.0", "babel-preset-expo": "^8.1.0",
"expo-cli": "^3.13.8", "expo-cli": "^3.17.18",
"typescript": "^3.7.5" "typescript": "^3.8.3"
} }
} }

View File

@@ -116,7 +116,7 @@ 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>(); const containerRef = React.useRef<NavigationContainerRef>(null);
// To test deep linking on, run the following in the Terminal: // To test deep linking on, run the following in the Terminal:
// Android: adb shell am start -a android.intent.action.VIEW -d "exp://127.0.0.1:19000/--/simple-stack" // Android: adb shell am start -a android.intent.action.VIEW -d "exp://127.0.0.1:19000/--/simple-stack"

View File

@@ -18,7 +18,7 @@
"author": "Satyajit Sahoo <satyajit.happy@gmail.com> (https://github.com/satya164/), Michał Osadnik <micosa97@gmail.com> (https://github.com/osdnk/)", "author": "Satyajit Sahoo <satyajit.happy@gmail.com> (https://github.com/satya164/), Michał Osadnik <micosa97@gmail.com> (https://github.com/osdnk/)",
"scripts": { "scripts": {
"lint": "eslint --ext '.js,.ts,.tsx' .", "lint": "eslint --ext '.js,.ts,.tsx' .",
"typescript": "tsc --noEmit", "typescript": "tsc --noEmit --composite false",
"test": "jest", "test": "jest",
"prerelease": "lerna run clean", "prerelease": "lerna run clean",
"release": "lerna publish", "release": "lerna publish",
@@ -26,25 +26,25 @@
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.8.3", "@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-optional-chaining": "^7.8.3", "@babel/plugin-proposal-optional-chaining": "^7.9.0",
"@babel/preset-env": "^7.8.7", "@babel/preset-env": "^7.9.0",
"@babel/preset-flow": "^7.8.3", "@babel/preset-flow": "^7.9.0",
"@babel/preset-react": "^7.8.3", "@babel/preset-react": "^7.9.4",
"@babel/preset-typescript": "^7.8.3", "@babel/preset-typescript": "^7.9.0",
"@babel/runtime": "^7.8.7", "@babel/runtime": "^7.9.2",
"@commitlint/config-conventional": "^8.3.4", "@commitlint/config-conventional": "^8.3.4",
"@types/jest": "^25.1.4", "@types/jest": "^25.2.1",
"babel-jest": "^25.2.6",
"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.4",
"detox": "^16.0.0",
"eslint": "^6.8.0", "eslint": "^6.8.0",
"eslint-config-satya164": "^3.1.5", "eslint-config-satya164": "^3.1.6",
"husky": "^4.2.3", "husky": "^4.2.3",
"jest": "^25.1.0", "jest": "^25.2.7",
"lerna": "^3.20.2", "lerna": "^3.20.2",
"prettier": "^2.0.1", "prettier": "^2.0.4",
"typescript": "^3.7.5" "typescript": "^3.8.3"
}, },
"resolutions": { "resolutions": {
"react": "~16.9.0", "react": "~16.9.0",

View File

@@ -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.2.6](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.2.5...@react-navigation/bottom-tabs@5.2.6) (2020-04-08)
### Bug Fixes
* mark type exports for all packages ([b71de6c](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/commit/b71de6cc799143f1d0e8a0cfcc34f0a2381f9840))
## [5.2.5](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.2.4...@react-navigation/bottom-tabs@5.2.5) (2020-03-30)
**Note:** Version bump only for package @react-navigation/bottom-tabs
## [5.2.4](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.2.3...@react-navigation/bottom-tabs@5.2.4) (2020-03-23) ## [5.2.4](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.2.3...@react-navigation/bottom-tabs@5.2.4) (2020-03-23)
**Note:** Version bump only for package @react-navigation/bottom-tabs **Note:** Version bump only for package @react-navigation/bottom-tabs

View File

@@ -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.2.4", "version": "5.2.6",
"keywords": [ "keywords": [
"react-native-component", "react-native-component",
"react-component", "react-component",
@@ -35,7 +35,7 @@
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.10.0", "@react-native-community/bob": "^0.10.0",
"@react-navigation/native": "^5.1.3", "@react-navigation/native": "^5.1.5",
"@types/color": "^3.0.1", "@types/color": "^3.0.1",
"@types/react": "^16.9.23", "@types/react": "^16.9.23",
"@types/react-native": "^0.61.22", "@types/react-native": "^0.61.22",
@@ -44,7 +44,7 @@
"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.3.0",
"typescript": "^3.7.5" "typescript": "^3.8.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/native": "^5.0.5", "@react-navigation/native": "^5.0.5",

View File

@@ -12,7 +12,7 @@ export { default as BottomTabBar } from './views/BottomTabBar';
/** /**
* Types * Types
*/ */
export { export type {
BottomTabNavigationOptions, BottomTabNavigationOptions,
BottomTabNavigationProp, BottomTabNavigationProp,
BottomTabBarProps, BottomTabBarProps,

View File

@@ -138,7 +138,7 @@ export type BottomTabBarOptions = {
*/ */
inactiveTintColor?: string; inactiveTintColor?: string;
/** /**
* Background olor for the active tab. * Background color for the active tab.
*/ */
activeBackgroundColor?: string; activeBackgroundColor?: string;
/** /**

View File

@@ -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.1.8](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.7...@react-navigation/compat@5.1.8) (2020-04-08)
### Bug Fixes
* use 1 as default in compatibility pop action ([4408117](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/commit/44081172d440c713ad3543a2d5e1e18ebc8f72a4))
## [5.1.7](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.6...@react-navigation/compat@5.1.7) (2020-03-30)
**Note:** Version bump only for package @react-navigation/compat
## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.5...@react-navigation/compat@5.1.6) (2020-03-23) ## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.5...@react-navigation/compat@5.1.6) (2020-03-23)
**Note:** Version bump only for package @react-navigation/compat **Note:** Version bump only for package @react-navigation/compat

View File

@@ -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.6", "version": "5.1.8",
"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": {
@@ -26,10 +26,10 @@
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.10.0", "@react-native-community/bob": "^0.10.0",
"@react-navigation/native": "^5.1.3", "@react-navigation/native": "^5.1.5",
"@types/react": "^16.9.23", "@types/react": "^16.9.23",
"react": "~16.9.0", "react": "~16.9.0",
"typescript": "^3.7.5" "typescript": "^3.8.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/native": "^5.0.5", "@react-navigation/native": "^5.0.5",

View File

@@ -57,7 +57,7 @@ export function push(routeName: string, params?: object, action?: never) {
}); });
} }
export function pop(n: number) { export function pop(n: number = 1) {
return StackActions.pop(typeof n === 'number' ? { n } : n); return StackActions.pop(typeof n === 'number' ? { n } : n);
} }

View File

@@ -3,6 +3,29 @@
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.3](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.3.2...@react-navigation/core@5.3.3) (2020-04-08)
### Bug Fixes
* switch order of focus and blur events. closes [#7963](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/7963) ([ce3994c](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/ce3994c82c28669d5742017eb7627e9adf996933))
* workaround warning about setState in another component in render ([d4fd906](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/d4fd906915cc20d6fb21508384c05a540d8644d8))
## [5.3.2](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.3.1...@react-navigation/core@5.3.2) (2020-03-30)
### Bug Fixes
* handle no path property and undefined query params ([#7911](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/7911)) ([cd47915](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/cd47915861a56cd7eaa9ac79f5139cde56ca95a7))
## [5.3.1](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.3.0...@react-navigation/core@5.3.1) (2020-03-23) ## [5.3.1](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.3.0...@react-navigation/core@5.3.1) (2020-03-23)

View File

@@ -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.3.1", "version": "5.3.3",
"keywords": [ "keywords": [
"react", "react",
"react-native", "react-native",
@@ -29,24 +29,23 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/routers": "^5.2.0", "@react-navigation/routers": "^5.3.0",
"escape-string-regexp": "^2.0.0", "escape-string-regexp": "^2.0.0",
"query-string": "^6.11.1", "nanoid": "^3.0.2",
"query-string": "^6.12.0",
"react-is": "^16.13.0", "react-is": "^16.13.0",
"shortid": "^2.2.15",
"use-subscription": "^1.4.0" "use-subscription": "^1.4.0"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.10.0", "@react-native-community/bob": "^0.10.0",
"@types/react": "^16.9.23", "@types/react": "^16.9.23",
"@types/react-is": "^16.7.1", "@types/react-is": "^16.7.1",
"@types/shortid": "^0.0.29",
"@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.12.0",
"react-test-renderer": "~16.9.0", "react-test-renderer": "~16.13.1",
"typescript": "^3.7.5" "typescript": "^3.8.3"
}, },
"peerDependencies": { "peerDependencies": {
"react": "*" "react": "*"

View File

@@ -9,14 +9,15 @@ import {
} from '@react-navigation/routers'; } from '@react-navigation/routers';
import EnsureSingleNavigator from './EnsureSingleNavigator'; import EnsureSingleNavigator from './EnsureSingleNavigator';
import NavigationBuilderContext from './NavigationBuilderContext'; import NavigationBuilderContext from './NavigationBuilderContext';
import { ScheduleUpdateContext } from './useScheduleUpdate';
import useFocusedListeners from './useFocusedListeners'; import useFocusedListeners from './useFocusedListeners';
import useDevTools from './useDevTools'; import useDevTools from './useDevTools';
import useStateGetters from './useStateGetters'; import useStateGetters from './useStateGetters';
import useEventEmitter from './useEventEmitter';
import useSyncState from './useSyncState';
import isSerializable from './isSerializable'; import isSerializable from './isSerializable';
import { NavigationContainerRef, NavigationContainerProps } from './types'; import { NavigationContainerRef, NavigationContainerProps } from './types';
import useEventEmitter from './useEventEmitter';
import useSyncState from './useSyncState';
type State = NavigationState | PartialState<NavigationState> | undefined; type State = NavigationState | PartialState<NavigationState> | undefined;
@@ -102,7 +103,7 @@ const BaseNavigationContainer = React.forwardRef(
independent, independent,
children, children,
}: NavigationContainerProps, }: NavigationContainerProps,
ref: React.Ref<NavigationContainerRef> ref?: React.Ref<NavigationContainerRef>
) { ) {
const parent = React.useContext(NavigationStateContext); const parent = React.useContext(NavigationStateContext);
@@ -112,7 +113,13 @@ const BaseNavigationContainer = React.forwardRef(
); );
} }
const [state, getState, setState] = useSyncState<State>(() => const [
state,
getState,
setState,
scheduleUpdate,
flushUpdates,
] = useSyncState<State>(() =>
getPartialState(initialState == null ? undefined : initialState) getPartialState(initialState == null ? undefined : initialState)
); );
@@ -218,6 +225,11 @@ const BaseNavigationContainer = React.forwardRef(
[addFocusedListener, trackAction, addStateGetter] [addFocusedListener, trackAction, addStateGetter]
); );
const scheduleContext = React.useMemo(
() => ({ scheduleUpdate, flushUpdates }),
[scheduleUpdate, flushUpdates]
);
const context = React.useMemo( const context = React.useMemo(
() => ({ () => ({
state, state,
@@ -263,11 +275,13 @@ const BaseNavigationContainer = React.forwardRef(
}, [onStateChange, trackState, getRootState, emitter, state]); }, [onStateChange, trackState, getRootState, emitter, state]);
return ( return (
<NavigationBuilderContext.Provider value={builderContext}> <ScheduleUpdateContext.Provider value={scheduleContext}>
<NavigationStateContext.Provider value={context}> <NavigationBuilderContext.Provider value={builderContext}>
<EnsureSingleNavigator>{children}</EnsureSingleNavigator> <NavigationStateContext.Provider value={context}>
</NavigationStateContext.Provider> <EnsureSingleNavigator>{children}</EnsureSingleNavigator>
</NavigationBuilderContext.Provider> </NavigationStateContext.Provider>
</NavigationBuilderContext.Provider>
</ScheduleUpdateContext.Provider>
); );
} }
); );

View File

@@ -521,3 +521,209 @@ it('returns "/" for empty path', () => {
expect(getPathFromState(state, config)).toBe('/'); expect(getPathFromState(state, config)).toBe('/');
}); });
it('parses no path specified', () => {
const path = '/Foo/bar';
const config = {
Foo: {
screens: {
Foe: {},
},
},
Bar: 'bar',
};
const state = {
routes: [
{
name: 'Foo',
state: {
routes: [{ name: 'Bar' }],
},
},
],
};
expect(getPathFromState(state, config)).toBe(path);
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
});
it('parses no path specified in nested config', () => {
const path = '/Foo/Foe/bar';
const config = {
Foo: {
path: 'foo',
screens: {
Foe: {},
},
},
Bar: 'bar',
};
const state = {
routes: [
{
name: 'Foo',
state: {
routes: [
{
name: 'Foe',
state: {
routes: [{ name: 'Bar' }],
},
},
],
},
},
],
};
expect(getPathFromState(state, config)).toBe(path);
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
});
it('strips undefined query params', () => {
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',
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: undefined,
valid: true,
},
},
],
},
},
],
},
},
],
},
},
],
};
expect(getPathFromState(state, config)).toBe(path);
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
});
it('handles stripping all query params', () => {
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',
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: undefined,
answer: undefined,
valid: undefined,
},
},
],
},
},
],
},
},
],
},
},
],
};
expect(getPathFromState(state, config)).toBe(path);
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
});

View File

@@ -626,7 +626,7 @@ it('updates route params with setParams applied to parent', () => {
}); });
}); });
it('handles change in route names', () => { it('handles change in route names', async () => {
const TestNavigator = (props: any): any => { const TestNavigator = (props: any): any => {
useNavigationBuilder(MockRouter, props); useNavigationBuilder(MockRouter, props);
return null; return null;
@@ -635,7 +635,7 @@ it('handles change in route names', () => {
const onStateChange = jest.fn(); const onStateChange = jest.fn();
const root = render( const root = render(
<BaseNavigationContainer onStateChange={onStateChange}> <BaseNavigationContainer>
<TestNavigator initialRouteName="bar"> <TestNavigator initialRouteName="bar">
<Screen name="foo" component={jest.fn()} /> <Screen name="foo" component={jest.fn()} />
<Screen name="bar" component={jest.fn()} /> <Screen name="bar" component={jest.fn()} />

View File

@@ -262,8 +262,10 @@ it('sets initial options with setOptions', () => {
}; };
const TestScreen = ({ navigation }: any): any => { const TestScreen = ({ navigation }: any): any => {
navigation.setOptions({ React.useEffect(() => {
title: 'Hello world', navigation.setOptions({
title: 'Hello world',
});
}); });
return 'Test screen'; return 'Test screen';
@@ -315,12 +317,12 @@ it('updates options with setOptions', () => {
}; };
const TestScreen = ({ navigation }: any): any => { const TestScreen = ({ navigation }: any): any => {
navigation.setOptions({
title: 'Hello world',
description: 'Something here',
});
React.useEffect(() => { React.useEffect(() => {
navigation.setOptions({
title: 'Hello world',
description: 'Something here',
});
const timer = setTimeout(() => const timer = setTimeout(() =>
navigation.setOptions({ navigation.setOptions({
title: 'Hello again', title: 'Hello again',

View File

@@ -97,6 +97,69 @@ it('fires focus and blur events in root navigator', () => {
expect(fourthBlurCallback).toBeCalledTimes(0); expect(fourthBlurCallback).toBeCalledTimes(0);
}); });
it('fires focus event after blur', () => {
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
const { state, navigation, descriptors } = useNavigationBuilder(
MockRouter,
props
);
React.useImperativeHandle(ref, () => navigation, [navigation]);
return state.routes.map((route) => descriptors[route.key].render());
});
const callback = jest.fn();
const Test = ({ route, navigation }: any) => {
React.useEffect(
() =>
navigation.addListener('focus', () => callback(route.name, 'focus')),
[navigation, route.name]
);
React.useEffect(
() => navigation.addListener('blur', () => callback(route.name, 'blur')),
[navigation, route.name]
);
return null;
};
const navigation = React.createRef<any>();
const element = (
<BaseNavigationContainer>
<TestNavigator ref={navigation}>
<Screen name="first" component={Test} />
<Screen name="second" component={Test} />
</TestNavigator>
</BaseNavigationContainer>
);
render(element);
expect(callback.mock.calls).toEqual([['first', 'focus']]);
act(() => navigation.current.navigate('second'));
expect(callback.mock.calls).toEqual([
['first', 'focus'],
['first', 'blur'],
['second', 'focus'],
]);
act(() => navigation.current.navigate('first'));
expect(callback.mock.calls).toEqual([
['first', 'focus'],
['first', 'blur'],
['second', 'focus'],
['second', 'blur'],
['first', 'focus'],
]);
});
it('fires focus and blur events in nested navigator', () => { it('fires focus and blur events in nested navigator', () => {
const TestNavigator = React.forwardRef((props: any, ref: any): any => { const TestNavigator = React.forwardRef((props: any, ref: any): any => {
const { state, navigation, descriptors } = useNavigationBuilder( const { state, navigation, descriptors } = useNavigationBuilder(

View File

@@ -64,6 +64,8 @@ export default function getPathFromState(
}; };
let currentOptions = options; let currentOptions = options;
let pattern = route.name; 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) { while (route.name in currentOptions) {
if (typeof currentOptions[route.name] === 'string') { if (typeof currentOptions[route.name] === 'string') {
@@ -77,11 +79,13 @@ export default function getPathFromState(
}).screens }).screens
) { ) {
pattern = (currentOptions[route.name] as { path: string }).path; pattern = (currentOptions[route.name] as { path: string }).path;
nestedRouteNames = `${nestedRouteNames}/${route.name}`;
break; break;
} else { } else {
// if it is the end of state, we return pattern // if it is the end of state, we return pattern
if (route.state === undefined) { if (route.state === undefined) {
pattern = (currentOptions[route.name] as { path: string }).path; pattern = (currentOptions[route.name] as { path: string }).path;
nestedRouteNames = `${nestedRouteNames}/${route.name}`;
break; break;
} else { } else {
index = index =
@@ -92,11 +96,13 @@ export default function getPathFromState(
}).screens; }).screens;
// if there is config for next route name, we go deeper // if there is config for next route name, we go deeper
if (nextRoute.name in deeperConfig) { if (nextRoute.name in deeperConfig) {
nestedRouteNames = `${nestedRouteNames}/${route.name}`;
route = nextRoute as Route<string> & { state?: State }; route = nextRoute as Route<string> & { state?: State };
currentOptions = deeperConfig; currentOptions = deeperConfig;
} else { } else {
// if not, there is no sense in going deeper in config // if not, there is no sense in going deeper in config
pattern = (currentOptions[route.name] as { path: string }).path; pattern = (currentOptions[route.name] as { path: string }).path;
nestedRouteNames = `${nestedRouteNames}/${route.name}`;
break; break;
} }
} }
@@ -104,6 +110,11 @@ export default function getPathFromState(
} }
} }
if (pattern === undefined) {
// cut the first `/`
pattern = nestedRouteNames.substring(1);
}
// we don't add empty path strings to path // we don't add empty path strings to path
if (pattern !== '') { if (pattern !== '') {
const config = const config =
@@ -147,6 +158,12 @@ export default function getPathFromState(
if (route.state) { if (route.state) {
path += '/'; path += '/';
} else if (params) { } else if (params) {
for (let param in params) {
if (params[param] === 'undefined') {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete params[param];
}
}
const query = queryString.stringify(params); const query = queryString.stringify(params);
if (query) { if (query) {

View File

@@ -410,24 +410,19 @@ export type RouteConfig<
} }
); );
export type NavigationContainerRef = export type NavigationContainerRef = NavigationHelpers<ParamListBase> &
| (NavigationHelpers<ParamListBase> & EventConsumer<{ state: { data: { state: NavigationState } } }> & {
EventConsumer<{ state: { data: { state: NavigationState } } }> & { /**
/** * Reset the navigation state of the root navigator to the provided state.
* Reset the navigation state of the root navigator to the provided state. *
* * @param state Navigation state object.
* @param state Navigation state object. */
*/ resetRoot(state?: PartialState<NavigationState> | NavigationState): void;
resetRoot( /**
state?: PartialState<NavigationState> | NavigationState * Get the rehydrated navigation state of the navigation tree.
): void; */
/** getRootState(): NavigationState;
* Get the rehydrated navigation state of the navigation tree. };
*/
getRootState(): NavigationState;
})
| undefined
| null;
export type TypedNavigator< export type TypedNavigator<
ParamList extends ParamListBase, ParamList extends ParamListBase,

View File

@@ -48,7 +48,7 @@ export default function useFocusEvents({ state, emitter }: Options) {
emitter.emit({ type: 'focus', target: currentFocusedKey }); emitter.emit({ type: 'focus', target: currentFocusedKey });
} }
// We should only dispatch events when the focused key changed and navigator is focused // We should only emit events when the focused key changed and navigator is focused
// When navigator is not focused, screens inside shouldn't receive focused status either // When navigator is not focused, screens inside shouldn't receive focused status either
if ( if (
lastFocusedKey === currentFocusedKey || lastFocusedKey === currentFocusedKey ||
@@ -62,7 +62,7 @@ export default function useFocusEvents({ state, emitter }: Options) {
return; return;
} }
emitter.emit({ type: 'focus', target: currentFocusedKey });
emitter.emit({ type: 'blur', target: lastFocusedKey }); emitter.emit({ type: 'blur', target: lastFocusedKey });
emitter.emit({ type: 'focus', target: currentFocusedKey });
}, [currentFocusedKey, emitter, navigation]); }, [currentFocusedKey, emitter, navigation]);
} }

View File

@@ -32,6 +32,7 @@ import {
} from './types'; } from './types';
import useStateGetters from './useStateGetters'; import useStateGetters from './useStateGetters';
import useOnGetState from './useOnGetState'; import useOnGetState from './useOnGetState';
import useScheduleUpdate from './useScheduleUpdate';
// This is to make TypeScript compiler happy // This is to make TypeScript compiler happy
// eslint-disable-next-line babel/no-unused-expressions // eslint-disable-next-line babel/no-unused-expressions
@@ -308,16 +309,13 @@ export default function useNavigationBuilder<
} }
if ( if (
previousRouteRef.current && typeof route?.params?.screen === 'string' &&
route && route.params !== previousRouteRef.current?.params
route.params &&
typeof route.params.screen === 'string' &&
route.params !== previousRouteRef.current.params
) { ) {
// If the route was updated with new name and/or params, we should navigate there // If the route was updated with new name and/or params, we should navigate there
// The update should be limited to current navigator only, so we call the router manually // The update should be limited to current navigator only, so we call the router manually
const updatedState = router.getStateForAction( const updatedState = router.getStateForAction(
state, nextState,
CommonActions.navigate(route.params.screen, route.params.params), CommonActions.navigate(route.params.screen, route.params.params),
{ {
routeNames, routeNames,
@@ -331,17 +329,17 @@ export default function useNavigationBuilder<
routeNames, routeNames,
routeParamList, routeParamList,
}) })
: state; : nextState;
} }
const shouldUpdate = state !== nextState; const shouldUpdate = state !== nextState;
React.useEffect(() => { useScheduleUpdate(() => {
if (shouldUpdate) { if (shouldUpdate) {
// If the state needs to be updated, we'll schedule an update with React // If the state needs to be updated, we'll schedule an update
setState(nextState); setState(nextState);
} }
}, [nextState, setState, shouldUpdate]); });
// The up-to-date state will come in next render, but we don't need to wait for it // The up-to-date state will come in next render, but we don't need to wait for it
// We can't use the outdated state since the screens have changed, which will cause error due to mismatched config // We can't use the outdated state since the screens have changed, which will cause error due to mismatched config

View File

@@ -1,5 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import shortid from 'shortid'; import { nanoid } from 'nanoid/non-secure';
import { SingleNavigatorContext } from './EnsureSingleNavigator'; import { SingleNavigatorContext } from './EnsureSingleNavigator';
/** /**
@@ -7,7 +7,7 @@ import { SingleNavigatorContext } from './EnsureSingleNavigator';
* This is used to prevent multiple navigators under a single container or screen. * This is used to prevent multiple navigators under a single container or screen.
*/ */
export default function useRegisterNavigator() { export default function useRegisterNavigator() {
const [key] = React.useState(() => shortid()); const [key] = React.useState(() => nanoid());
const container = React.useContext(SingleNavigatorContext); const container = React.useContext(SingleNavigatorContext);
if (container === undefined) { if (container === undefined) {

View File

@@ -0,0 +1,32 @@
import * as React from 'react';
const MISSING_CONTEXT_ERROR = "Couldn't find a schedule context.";
export const ScheduleUpdateContext = React.createContext<{
scheduleUpdate: (callback: () => void) => void;
flushUpdates: () => void;
}>({
scheduleUpdate() {
throw new Error(MISSING_CONTEXT_ERROR);
},
flushUpdates() {
throw new Error(MISSING_CONTEXT_ERROR);
},
});
/**
* When screen config changes, we want to update the navigator in the same update phase.
* However, navigation state is in the root component and React won't let us update it from a child.
* This is a workaround for that, the scheduled update is stored in the ref without actually calling setState.
* It lets all subsequent updates access the latest state so it stays correct.
* Then we call setState during after the component updates.
*/
export default function useScheduleUpdate(callback: () => void) {
const { scheduleUpdate, flushUpdates } = React.useContext(
ScheduleUpdateContext
);
scheduleUpdate(callback);
React.useEffect(flushUpdates);
}

View File

@@ -2,8 +2,12 @@ import * as React from 'react';
const UNINTIALIZED_STATE = {}; const UNINTIALIZED_STATE = {};
/**
* This is definitely not compatible with concurrent mode, but we don't have a solution for sync state yet.
*/
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);
if (stateRef.current === UNINTIALIZED_STATE) { if (stateRef.current === UNINTIALIZED_STATE) {
stateRef.current = stateRef.current =
@@ -11,7 +15,7 @@ export default function useSyncState<T>(initialState?: (() => T) | T) {
typeof initialState === 'function' ? initialState() : initialState; typeof initialState === 'function' ? initialState() : initialState;
} }
const [state, setTrackingState] = React.useState(stateRef.current); const [trackingState, setTrackingState] = React.useState(stateRef.current);
const getState = React.useCallback(() => stateRef.current, []); const getState = React.useCallback(() => stateRef.current, []);
@@ -21,8 +25,35 @@ export default function useSyncState<T>(initialState?: (() => T) | T) {
} }
stateRef.current = state; stateRef.current = state;
setTrackingState(state);
if (!isSchedulingRef.current) {
setTrackingState(state);
}
}, []); }, []);
return [state, getState, setState] as const; const scheduleUpdate = React.useCallback((callback: () => void) => {
isSchedulingRef.current = true;
try {
callback();
} finally {
isSchedulingRef.current = false;
}
}, []);
const flushUpdates = React.useCallback(() => {
// Make sure that the tracking state is up-to-date.
// We call it unconditionally, but React should skip the update if state is unchanged.
setTrackingState(stateRef.current);
}, []);
// If we're rendering and the tracking state is out of date, update it immediately
// This will make sure that our updates are applied as early as possible.
if (trackingState !== stateRef.current) {
setTrackingState(stateRef.current);
}
const state = stateRef.current;
return [state, getState, setState, scheduleUpdate, flushUpdates] as const;
} }

View File

@@ -3,6 +3,34 @@
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.1](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.4.0...@react-navigation/drawer@5.4.1) (2020-04-08)
### Bug Fixes
* don't hide content from accessibility with permanent drawer ([cb2f157](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/cb2f157a561a2ce3f073eb4ccb567532c77bd869)), closes [#7976](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/7976)
* mark type exports for all packages ([b71de6c](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/b71de6cc799143f1d0e8a0cfcc34f0a2381f9840))
# [5.4.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.3.4...@react-navigation/drawer@5.4.0) (2020-03-30)
### Bug Fixes
* disable only swipe gesture on safari ([105da6a](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/105da6ab2fe69847b676c4d4117638212cda1f9a))
### Features
* add swipeEnabled option to disable swipe gesture in drawer ([#7834](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/7834)) ([ac7f972](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/ac7f972e922a82cd32d943356941d100b68bd8b0))
## [5.3.4](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.3.3...@react-navigation/drawer@5.3.4) (2020-03-23) ## [5.3.4](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.3.3...@react-navigation/drawer@5.3.4) (2020-03-23)
**Note:** Version bump only for package @react-navigation/drawer **Note:** Version bump only for package @react-navigation/drawer

View File

@@ -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.3.4", "version": "5.4.1",
"keywords": [ "keywords": [
"react-native-component", "react-native-component",
"react-component", "react-component",
@@ -40,7 +40,7 @@
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.10.0", "@react-native-community/bob": "^0.10.0",
"@react-navigation/native": "^5.1.3", "@react-navigation/native": "^5.1.5",
"@types/react": "^16.9.23", "@types/react": "^16.9.23",
"@types/react-native": "^0.61.22", "@types/react-native": "^0.61.22",
"del-cli": "^3.0.0", "del-cli": "^3.0.0",
@@ -50,7 +50,7 @@
"react-native-reanimated": "^1.7.0", "react-native-reanimated": "^1.7.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.3.0",
"typescript": "^3.7.5" "typescript": "^3.8.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/native": "^5.0.5", "@react-navigation/native": "^5.0.5",

View File

@@ -22,7 +22,7 @@ export { default as useIsDrawerOpen } from './utils/useIsDrawerOpen';
/** /**
* Types * Types
*/ */
export { export type {
DrawerNavigationOptions, DrawerNavigationOptions,
DrawerNavigationProp, DrawerNavigationProp,
DrawerContentOptions, DrawerContentOptions,

View File

@@ -111,9 +111,18 @@ export type DrawerNavigationOptions = {
/** /**
* Whether you can use gestures to open or close the drawer. * Whether you can use gestures to open or close the drawer.
* Setting this to `false` disables swipe gestures as well as tap on overlay to close.
* See `swipeEnabled` to disable only the swipe gesture.
* Defaults to `true` * Defaults to `true`
*/ */
gestureEnabled?: boolean; gestureEnabled?: boolean;
/**
* Whether you can use swipe gestures to open or close the drawer.
* Defaults to `true`
*/
swipeEnabled?: boolean;
/** /**
* Whether this screen should be unmounted when navigating away from it. * Whether this screen should be unmounted when navigating away from it.
* Defaults to `false`. * Defaults to `false`.

View File

@@ -80,6 +80,7 @@ type Props = {
onClose: () => void; onClose: () => void;
onGestureRef?: (ref: PanGestureHandler | null) => void; onGestureRef?: (ref: PanGestureHandler | null) => void;
gestureEnabled: boolean; gestureEnabled: boolean;
swipeEnabled: boolean;
drawerPosition: 'left' | 'right'; drawerPosition: 'left' | 'right';
drawerType: 'front' | 'back' | 'slide' | 'permanent'; drawerType: 'front' | 'back' | 'slide' | 'permanent';
keyboardDismissMode: 'none' | 'on-drag'; keyboardDismissMode: 'none' | 'on-drag';
@@ -100,7 +101,7 @@ type Props = {
* Disables the pan gesture by default on Apple devices in the browser. * Disables the pan gesture by default on Apple devices in the browser.
* https://stackoverflow.com/a/9039885 * https://stackoverflow.com/a/9039885
*/ */
function shouldEnableGesture(): boolean { function shouldEnableSwipeGesture(): boolean {
if ( if (
Platform.OS === 'web' && Platform.OS === 'web' &&
typeof navigator !== 'undefined' && typeof navigator !== 'undefined' &&
@@ -115,11 +116,12 @@ function shouldEnableGesture(): boolean {
return true; return true;
} }
export default class DrawerView extends React.PureComponent<Props> { export default class DrawerView extends React.Component<Props> {
static defaultProps = { static defaultProps = {
drawerPostion: I18nManager.isRTL ? 'left' : 'right', drawerPostion: I18nManager.isRTL ? 'left' : 'right',
drawerType: 'front', drawerType: 'front',
gestureEnabled: shouldEnableGesture(), gestureEnabled: true,
swipeEnabled: shouldEnableSwipeGesture(),
swipeEdgeWidth: 32, swipeEdgeWidth: 32,
swipeVelocityThreshold: 500, swipeVelocityThreshold: 500,
keyboardDismissMode: 'on-drag', keyboardDismissMode: 'on-drag',
@@ -138,16 +140,11 @@ export default class DrawerView extends React.PureComponent<Props> {
open, open,
drawerPosition, drawerPosition,
drawerType, drawerType,
gestureEnabled,
swipeDistanceThreshold, swipeDistanceThreshold,
swipeVelocityThreshold, swipeVelocityThreshold,
hideStatusBar, hideStatusBar,
} = this.props; } = this.props;
if (prevProps.gestureEnabled !== gestureEnabled) {
this.isGestureEnabled.setValue(gestureEnabled ? TRUE : FALSE);
}
if ( if (
// If we're not in the middle of a transition, sync the drawer's open state // If we're not in the middle of a transition, sync the drawer's open state
typeof this.pendingOpenValue !== 'boolean' || typeof this.pendingOpenValue !== 'boolean' ||
@@ -223,9 +220,6 @@ export default class DrawerView extends React.PureComponent<Props> {
private isDrawerTypeFront = new Value<Binary>( private isDrawerTypeFront = new Value<Binary>(
this.props.drawerType === 'front' ? TRUE : FALSE this.props.drawerType === 'front' ? TRUE : FALSE
); );
private isGestureEnabled = new Value(
this.props.gestureEnabled ? TRUE : FALSE
);
private isOpen = new Value<Binary>(this.props.open ? TRUE : FALSE); private isOpen = new Value<Binary>(this.props.open ? TRUE : FALSE);
private nextIsOpen = new Value<Binary | -1>(UNSET); private nextIsOpen = new Value<Binary | -1>(UNSET);
@@ -554,6 +548,7 @@ export default class DrawerView extends React.PureComponent<Props> {
const { const {
open, open,
gestureEnabled, gestureEnabled,
swipeEnabled,
drawerPosition, drawerPosition,
drawerType, drawerType,
swipeEdgeWidth, swipeEdgeWidth,
@@ -605,7 +600,7 @@ export default class DrawerView extends React.PureComponent<Props> {
onGestureEvent={this.handleGestureEvent} onGestureEvent={this.handleGestureEvent}
onHandlerStateChange={this.handleGestureStateChange} onHandlerStateChange={this.handleGestureStateChange}
hitSlop={hitSlop} hitSlop={hitSlop}
enabled={drawerType !== 'permanent' && gestureEnabled} enabled={drawerType !== 'permanent' && gestureEnabled && swipeEnabled}
{...gestureHandlerProps} {...gestureHandlerProps}
> >
<Animated.View <Animated.View
@@ -628,23 +623,27 @@ export default class DrawerView extends React.PureComponent<Props> {
]} ]}
> >
<View <View
accessibilityElementsHidden={isOpen} accessibilityElementsHidden={isOpen && drawerType !== 'permanent'}
importantForAccessibility={ importantForAccessibility={
isOpen ? 'no-hide-descendants' : 'auto' isOpen && drawerType !== 'permanent'
? 'no-hide-descendants'
: 'auto'
} }
style={styles.content} style={styles.content}
> >
{renderSceneContent({ progress })} {renderSceneContent({ progress })}
</View> </View>
{// Disable overlay if sidebar is permanent {
drawerType === 'permanent' ? null : ( // Disable overlay if sidebar is permanent
<TapGestureHandler drawerType === 'permanent' ? null : (
enabled={gestureEnabled} <TapGestureHandler
onHandlerStateChange={this.handleTapStateChange} enabled={gestureEnabled}
> onHandlerStateChange={this.handleTapStateChange}
<Overlay progress={progress} style={overlayStyle} /> >
</TapGestureHandler> <Overlay progress={progress} style={overlayStyle} />
)} </TapGestureHandler>
)
}
</Animated.View> </Animated.View>
{drawerType === 'permanent' ? null : ( {drawerType === 'permanent' ? null : (
<Animated.Code <Animated.Code
@@ -659,7 +658,7 @@ export default class DrawerView extends React.PureComponent<Props> {
/> />
)} )}
<Animated.View <Animated.View
accessibilityViewIsModal={isOpen} accessibilityViewIsModal={isOpen && drawerType !== 'permanent'}
removeClippedSubviews={Platform.OS !== 'ios'} removeClippedSubviews={Platform.OS !== 'ios'}
onLayout={this.handleDrawerLayout} onLayout={this.handleDrawerLayout}
style={[ style={[

View File

@@ -200,7 +200,7 @@ export default function DrawerView({
}; };
const activeKey = state.routes[state.index].key; const activeKey = state.routes[state.index].key;
const { gestureEnabled } = descriptors[activeKey].options; const { gestureEnabled, swipeEnabled } = descriptors[activeKey].options;
return ( return (
<GestureHandlerWrapper style={styles.content}> <GestureHandlerWrapper style={styles.content}>
@@ -210,6 +210,7 @@ export default function DrawerView({
<Drawer <Drawer
open={isDrawerOpen} open={isDrawerOpen}
gestureEnabled={gestureEnabled} gestureEnabled={gestureEnabled}
swipeEnabled={swipeEnabled}
onOpen={handleDrawerOpen} onOpen={handleDrawerOpen}
onClose={handleDrawerClose} onClose={handleDrawerClose}
onGestureRef={(ref) => { onGestureRef={(ref) => {

View File

@@ -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.1.8](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.7...@react-navigation/material-bottom-tabs@5.1.8) (2020-04-08)
### Bug Fixes
* mark type exports for all packages ([b71de6c](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/commit/b71de6cc799143f1d0e8a0cfcc34f0a2381f9840))
## [5.1.7](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.6...@react-navigation/material-bottom-tabs@5.1.7) (2020-03-30)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.5...@react-navigation/material-bottom-tabs@5.1.6) (2020-03-23) ## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.5...@react-navigation/material-bottom-tabs@5.1.6) (2020-03-23)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs **Note:** Version bump only for package @react-navigation/material-bottom-tabs

View File

@@ -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.6", "version": "5.1.8",
"keywords": [ "keywords": [
"react-native-component", "react-native-component",
"react-component", "react-component",
@@ -36,16 +36,16 @@
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.10.0", "@react-native-community/bob": "^0.10.0",
"@react-navigation/native": "^5.1.3", "@react-navigation/native": "^5.1.5",
"@types/react": "^16.9.23", "@types/react": "^16.9.23",
"@types/react-native": "^0.61.22", "@types/react-native": "^0.61.22",
"@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.6.0", "react-native-paper": "^3.7.0",
"react-native-vector-icons": "^6.6.0", "react-native-vector-icons": "^6.6.0",
"typescript": "^3.7.5" "typescript": "^3.8.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/native": "^5.0.5", "@react-navigation/native": "^5.0.5",

View File

@@ -11,7 +11,7 @@ export { default as MaterialBottomTabView } from './views/MaterialBottomTabView'
/** /**
* Types * Types
*/ */
export { export type {
MaterialBottomTabNavigationOptions, MaterialBottomTabNavigationOptions,
MaterialBottomTabNavigationProp, MaterialBottomTabNavigationProp,
} from './types'; } from './types';

View File

@@ -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.1.8](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.7...@react-navigation/material-top-tabs@5.1.8) (2020-04-08)
### Bug Fixes
* mark type exports for all packages ([b71de6c](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/commit/b71de6cc799143f1d0e8a0cfcc34f0a2381f9840))
## [5.1.7](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.6...@react-navigation/material-top-tabs@5.1.7) (2020-03-30)
**Note:** Version bump only for package @react-navigation/material-top-tabs
## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.5...@react-navigation/material-top-tabs@5.1.6) (2020-03-23) ## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.5...@react-navigation/material-top-tabs@5.1.6) (2020-03-23)
**Note:** Version bump only for package @react-navigation/material-top-tabs **Note:** Version bump only for package @react-navigation/material-top-tabs

View File

@@ -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.6", "version": "5.1.8",
"keywords": [ "keywords": [
"react-native-component", "react-native-component",
"react-component", "react-component",
@@ -39,7 +39,7 @@
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.10.0", "@react-native-community/bob": "^0.10.0",
"@react-navigation/native": "^5.1.3", "@react-navigation/native": "^5.1.5",
"@types/react": "^16.9.23", "@types/react": "^16.9.23",
"@types/react-native": "^0.61.22", "@types/react-native": "^0.61.22",
"del-cli": "^3.0.0", "del-cli": "^3.0.0",
@@ -47,8 +47,8 @@
"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.7.0",
"react-native-tab-view": "^2.13.0", "react-native-tab-view": "^2.14.0",
"typescript": "^3.7.5" "typescript": "^3.8.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/native": "^5.0.5", "@react-navigation/native": "^5.0.5",

View File

@@ -12,7 +12,7 @@ export { default as MaterialTopTabBar } from './views/MaterialTopTabBar';
/** /**
* Types * Types
*/ */
export { export type {
MaterialTopTabNavigationOptions, MaterialTopTabNavigationOptions,
MaterialTopTabNavigationProp, MaterialTopTabNavigationProp,
MaterialTopTabBarProps, MaterialTopTabBarProps,

View File

@@ -3,6 +3,22 @@
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.5](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.1.4...@react-navigation/native@5.1.5) (2020-04-08)
**Note:** Version bump only for package @react-navigation/native
## [5.1.4](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.1.3...@react-navigation/native@5.1.4) (2020-03-30)
**Note:** Version bump only for package @react-navigation/native
## [5.1.3](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.1.2...@react-navigation/native@5.1.3) (2020-03-23) ## [5.1.3](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.1.2...@react-navigation/native@5.1.3) (2020-03-23)

View File

@@ -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.1.3", "version": "5.1.5",
"keywords": [ "keywords": [
"react-native", "react-native",
"react-navigation", "react-navigation",
@@ -31,7 +31,7 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/core": "^5.3.1" "@react-navigation/core": "^5.3.3"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.10.0", "@react-native-community/bob": "^0.10.0",
@@ -41,7 +41,7 @@
"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.12.0",
"typescript": "^3.7.5" "typescript": "^3.8.3"
}, },
"peerDependencies": { "peerDependencies": {
"react": "*", "react": "*",

View File

@@ -26,7 +26,7 @@ type Props = NavigationContainerProps & {
*/ */
const NavigationContainer = React.forwardRef(function NavigationContainer( const NavigationContainer = React.forwardRef(function NavigationContainer(
{ theme = DefaultTheme, ...rest }: Props, { theme = DefaultTheme, ...rest }: Props,
ref: React.Ref<NavigationContainerRef> ref?: React.Ref<NavigationContainerRef | null>
) { ) {
const refContainer = React.useRef<NavigationContainerRef>(null); const refContainer = React.useRef<NavigationContainerRef>(null);

View File

@@ -41,7 +41,7 @@ export type LinkingOptions = {
*/ */
getStateFromPath?: typeof getStateFromPathDefault; getStateFromPath?: typeof getStateFromPathDefault;
/** /**
* Custom function to conver the state object to a valid URL (advanced). * Custom function to convert the state object to a valid URL (advanced).
*/ */
getPathFromState?: typeof getPathFromStateDefault; getPathFromState?: typeof getPathFromStateDefault;
}; };

View File

@@ -3,6 +3,30 @@
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.0](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.2.1...@react-navigation/routers@5.3.0) (2020-04-08)
### Bug Fixes
* separate normal exports and type exports ([303f0b7](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/commit/303f0b78a5ab717b2d606cd9c8a22f3dae051f0f))
### Features
* make replace bubble up ([ba1f405](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/commit/ba1f4051299ad86001592b8d3601c16fece159df))
## [5.2.1](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.2.0...@react-navigation/routers@5.2.1) (2020-03-30)
**Note:** Version bump only for package @react-navigation/routers
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.1.1...@react-navigation/routers@5.2.0) (2020-03-22) # [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.1.1...@react-navigation/routers@5.2.0) (2020-03-22)

View File

@@ -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.2.0", "version": "5.3.0",
"keywords": [ "keywords": [
"react", "react",
"react-native", "react-native",
@@ -30,12 +30,12 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"shortid": "^2.2.15" "nanoid": "^3.0.2"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.10.0", "@react-native-community/bob": "^0.10.0",
"del-cli": "^3.0.0", "del-cli": "^3.0.0",
"typescript": "^3.7.5" "typescript": "^3.8.3"
}, },
"@react-native-community/bob": { "@react-native-community/bob": {
"source": "src", "source": "src",

View File

@@ -1,4 +1,4 @@
import shortid from 'shortid'; import { nanoid } from 'nanoid/non-secure';
import { CommonNavigationAction, NavigationState, PartialState } from './types'; import { CommonNavigationAction, NavigationState, PartialState } from './types';
/** /**
@@ -55,9 +55,7 @@ const BaseRouter = {
return { return {
...nextState, ...nextState,
routes: nextState.routes.map((route) => routes: nextState.routes.map((route) =>
route.key route.key ? route : { ...route, key: `${route.name}-${nanoid()}` }
? route
: { ...route, key: `${route.name}-${shortid()}` }
), ),
}; };
} }

View File

@@ -1,4 +1,4 @@
import shortid from 'shortid'; import { nanoid } from 'nanoid/non-secure';
import { import {
PartialState, PartialState,
CommonNavigationAction, CommonNavigationAction,
@@ -115,7 +115,7 @@ export default function DrawerRouter(
...state, ...state,
stale: false, stale: false,
type: 'drawer', type: 'drawer',
key: `drawer-${shortid()}`, key: `drawer-${nanoid()}`,
}; };
}, },
@@ -136,7 +136,7 @@ export default function DrawerRouter(
return { return {
...state, ...state,
type: 'drawer', type: 'drawer',
key: `drawer-${shortid()}`, key: `drawer-${nanoid()}`,
}; };
}, },

View File

@@ -1,4 +1,4 @@
import shortid from 'shortid'; import { nanoid } from 'nanoid/non-secure';
import BaseRouter from './BaseRouter'; import BaseRouter from './BaseRouter';
import { import {
NavigationState, NavigationState,
@@ -113,12 +113,12 @@ export default function StackRouter(options: StackRouterOptions) {
return { return {
stale: false, stale: false,
type: 'stack', type: 'stack',
key: `stack-${shortid()}`, key: `stack-${nanoid()}`,
index: 0, index: 0,
routeNames, routeNames,
routes: [ routes: [
{ {
key: `${initialRouteName}-${shortid()}`, key: `${initialRouteName}-${nanoid()}`,
name: initialRouteName, name: initialRouteName,
params: routeParamList[initialRouteName], params: routeParamList[initialRouteName],
}, },
@@ -139,7 +139,7 @@ export default function StackRouter(options: StackRouterOptions) {
(route) => (route) =>
({ ({
...route, ...route,
key: route.key || `${route.name}-${shortid()}`, key: route.key || `${route.name}-${nanoid()}`,
params: params:
routeParamList[route.name] !== undefined routeParamList[route.name] !== undefined
? { ? {
@@ -157,7 +157,7 @@ export default function StackRouter(options: StackRouterOptions) {
: routeNames[0]; : routeNames[0];
routes.push({ routes.push({
key: `${initialRouteName}-${shortid()}`, key: `${initialRouteName}-${nanoid()}`,
name: initialRouteName, name: initialRouteName,
params: routeParamList[initialRouteName], params: routeParamList[initialRouteName],
}); });
@@ -166,7 +166,7 @@ export default function StackRouter(options: StackRouterOptions) {
return { return {
stale: false, stale: false,
type: 'stack', type: 'stack',
key: `stack-${shortid()}`, key: `stack-${nanoid()}`,
index: routes.length - 1, index: routes.length - 1,
routeNames, routeNames,
routes, routes,
@@ -186,7 +186,7 @@ export default function StackRouter(options: StackRouterOptions) {
: routeNames[0]; : routeNames[0];
routes.push({ routes.push({
key: `${initialRouteName}-${shortid()}`, key: `${initialRouteName}-${nanoid()}`,
name: initialRouteName, name: initialRouteName,
params: routeParamList[initialRouteName], params: routeParamList[initialRouteName],
}); });
@@ -219,9 +219,10 @@ export default function StackRouter(options: StackRouterOptions) {
switch (action.type) { switch (action.type) {
case 'REPLACE': { case 'REPLACE': {
const index = action.source const index =
? state.routes.findIndex((r) => r.key === action.source) action.target === state.key && action.source
: state.index; ? state.routes.findIndex((r) => r.key === action.source)
: state.index;
if (index === -1) { if (index === -1) {
return null; return null;
@@ -238,7 +239,7 @@ export default function StackRouter(options: StackRouterOptions) {
routes: state.routes.map((route, i) => routes: state.routes.map((route, i) =>
i === index i === index
? { ? {
key: key !== undefined ? key : `${name}-${shortid()}`, key: key !== undefined ? key : `${name}-${nanoid()}`,
name, name,
params: params:
routeParamList[name] !== undefined routeParamList[name] !== undefined
@@ -263,7 +264,7 @@ export default function StackRouter(options: StackRouterOptions) {
{ {
key: key:
action.payload.key === undefined action.payload.key === undefined
? `${action.payload.name}-${shortid()}` ? `${action.payload.name}-${nanoid()}`
: action.payload.key, : action.payload.key,
name: action.payload.name, name: action.payload.name,
params: params:

View File

@@ -1,4 +1,4 @@
import shortid from 'shortid'; import { nanoid } from 'nanoid/non-secure';
import BaseRouter from './BaseRouter'; import BaseRouter from './BaseRouter';
import { import {
NavigationState, NavigationState,
@@ -126,7 +126,7 @@ export default function TabRouter({
const routes = routeNames.map((name) => ({ const routes = routeNames.map((name) => ({
name, name,
key: `${name}-${shortid()}`, key: `${name}-${nanoid()}`,
params: routeParamList[name], params: routeParamList[name],
})); }));
@@ -135,7 +135,7 @@ export default function TabRouter({
return { return {
stale: false, stale: false,
type: 'tab', type: 'tab',
key: `tab-${shortid()}`, key: `tab-${nanoid()}`,
index, index,
routeNames, routeNames,
history, history,
@@ -161,7 +161,7 @@ export default function TabRouter({
key: key:
route && route.name === name && route.key route && route.name === name && route.key
? route.key ? route.key
: `${name}-${shortid()}`, : `${name}-${nanoid()}`,
params: params:
routeParamList[name] !== undefined routeParamList[name] !== undefined
? { ? {
@@ -195,7 +195,7 @@ export default function TabRouter({
return { return {
stale: false, stale: false,
type: 'tab', type: 'tab',
key: `tab-${shortid()}`, key: `tab-${nanoid()}`,
index, index,
routeNames, routeNames,
history, history,
@@ -208,7 +208,7 @@ export default function TabRouter({
(name) => (name) =>
state.routes.find((r) => r.name === name) || { state.routes.find((r) => r.name === name) || {
name, name,
key: `${name}-${shortid()}`, key: `${name}-${nanoid()}`,
params: routeParamList[name], params: routeParamList[name],
} }
); );

View File

@@ -1,7 +1,7 @@
import BaseRouter from '../BaseRouter'; import BaseRouter from '../BaseRouter';
import * as CommonActions from '../CommonActions'; import * as CommonActions from '../CommonActions';
jest.mock('shortid', () => () => 'test'); jest.mock('nanoid/non-secure', () => ({ nanoid: () => 'test' }));
const STATE = { const STATE = {
stale: false as const, stale: false as const,

View File

@@ -5,7 +5,7 @@ import {
DrawerNavigationState, DrawerNavigationState,
} from '..'; } from '..';
jest.mock('shortid', () => () => 'test'); jest.mock('nanoid/non-secure', () => ({ nanoid: () => 'test' }));
it('gets initial state from route names and params with initialRouteName', () => { it('gets initial state from route names and params with initialRouteName', () => {
const router = DrawerRouter({ initialRouteName: 'baz' }); const router = DrawerRouter({ initialRouteName: 'baz' });

View File

@@ -1,6 +1,6 @@
import { CommonActions, StackRouter, StackActions } from '..'; import { CommonActions, StackRouter, StackActions } from '..';
jest.mock('shortid', () => () => 'test'); jest.mock('nanoid/non-secure', () => ({ nanoid: () => 'test' }));
it('gets initial state from route names and params with initialRouteName', () => { it('gets initial state from route names and params with initialRouteName', () => {
const router = StackRouter({ initialRouteName: 'baz' }); const router = StackRouter({ initialRouteName: 'baz' });
@@ -720,7 +720,7 @@ it('replaces focused screen with replace', () => {
}); });
}); });
it('replaces source screen with replace', () => { it('replaces active screen with replace', () => {
const router = StackRouter({}); const router = StackRouter({});
const options = { const options = {
routeNames: ['foo', 'bar', 'baz', 'qux'], routeNames: ['foo', 'bar', 'baz', 'qux'],
@@ -754,8 +754,8 @@ it('replaces source screen with replace', () => {
index: 1, index: 1,
routes: [ routes: [
{ key: 'foo', name: 'foo' }, { key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar', params: { fruit: 'orange' } },
{ key: 'qux-test', name: 'qux', params: { answer: 42 } }, { key: 'qux-test', name: 'qux', params: { answer: 42 } },
{ key: 'baz', name: 'baz' },
], ],
routeNames: ['foo', 'bar', 'baz', 'qux'], routeNames: ['foo', 'bar', 'baz', 'qux'],
}); });
@@ -785,6 +785,7 @@ it("doesn't handle replace if source key isn't present", () => {
{ {
...StackActions.replace('qux', { answer: 42 }), ...StackActions.replace('qux', { answer: 42 }),
source: 'magic', source: 'magic',
target: 'root',
}, },
options options
) )

View File

@@ -1,6 +1,6 @@
import { CommonActions, TabRouter, TabActions, TabNavigationState } from '..'; import { CommonActions, TabRouter, TabActions, TabNavigationState } from '..';
jest.mock('shortid', () => () => 'test'); jest.mock('nanoid/non-secure', () => ({ nanoid: () => 'test' }));
it('gets initial state from route names and params with initialRouteName', () => { it('gets initial state from route names and params with initialRouteName', () => {
const router = TabRouter({ initialRouteName: 'baz' }); const router = TabRouter({ initialRouteName: 'baz' });

View File

@@ -4,27 +4,27 @@ export { CommonActions };
export { default as BaseRouter } from './BaseRouter'; export { default as BaseRouter } from './BaseRouter';
export { export { default as StackRouter, StackActions } from './StackRouter';
default as StackRouter,
StackActions, export type {
StackActionHelpers, StackActionHelpers,
StackActionType, StackActionType,
StackRouterOptions, StackRouterOptions,
StackNavigationState, StackNavigationState,
} from './StackRouter'; } from './StackRouter';
export { export { default as TabRouter, TabActions } from './TabRouter';
default as TabRouter,
TabActions, export type {
TabActionHelpers, TabActionHelpers,
TabActionType, TabActionType,
TabRouterOptions, TabRouterOptions,
TabNavigationState, TabNavigationState,
} from './TabRouter'; } from './TabRouter';
export { export { default as DrawerRouter, DrawerActions } from './DrawerRouter';
default as DrawerRouter,
DrawerActions, export type {
DrawerActionHelpers, DrawerActionHelpers,
DrawerActionType, DrawerActionType,
DrawerRouterOptions, DrawerRouterOptions,

View File

@@ -3,6 +3,31 @@
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.10](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.9...@react-navigation/stack@5.2.10) (2020-04-08)
### Bug Fixes
* make color of shadow element same as card color in stack ([f1a8bce](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/f1a8bceba5b736e9f59862a8ae819342209a46f2))
* mark type exports for all packages ([b71de6c](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/b71de6cc799143f1d0e8a0cfcc34f0a2381f9840))
## [5.2.9](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.8...@react-navigation/stack@5.2.9) (2020-03-30)
### Bug Fixes
* dismiss keyboard on screen change for android ([8432e5a](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/8432e5ab25f041af8538ea7fb35e97cfcf1f983e))
* finish stack animation on CANCELLED event ([#7898](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7898)) ([d649fbc](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/d649fbc6691871f0348076bce185d11a183c02cf)), closes [#7897](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7897)
* when comparing changed routes, only check keys ([9a8fea8](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/9a8fea8f2c1bdabfc5dd87e5c3ff4e7b97aef47d))
## [5.2.7](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.6...@react-navigation/stack@5.2.7) (2020-03-26) ## [5.2.7](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.6...@react-navigation/stack@5.2.7) (2020-03-26)

View File

@@ -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.7", "version": "5.2.10",
"keywords": [ "keywords": [
"react-native-component", "react-native-component",
"react-component", "react-component",
@@ -40,7 +40,7 @@
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.10.0", "@react-native-community/bob": "^0.10.0",
"@react-native-community/masked-view": "^0.1.7", "@react-native-community/masked-view": "^0.1.7",
"@react-navigation/native": "^5.1.3", "@react-navigation/native": "^5.1.5",
"@types/color": "^3.0.1", "@types/color": "^3.0.1",
"@types/react": "^16.9.23", "@types/react": "^16.9.23",
"@types/react-native": "^0.61.22", "@types/react-native": "^0.61.22",
@@ -50,7 +50,7 @@
"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.3.0",
"typescript": "^3.7.5" "typescript": "^3.8.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-native-community/masked-view": ">= 0.1.0", "@react-native-community/masked-view": ">= 0.1.0",

View File

@@ -48,7 +48,7 @@ export { default as useGestureHandlerRef } from './utils/useGestureHandlerRef';
/** /**
* Types * Types
*/ */
export { export type {
StackNavigationOptions, StackNavigationOptions,
StackNavigationProp, StackNavigationProp,
StackHeaderProps, StackHeaderProps,

View File

@@ -1,5 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import { TextInput } from 'react-native'; import { TextInput, Platform, Keyboard } from 'react-native';
type Props = { type Props = {
enabled: boolean; enabled: boolean;
@@ -56,7 +56,9 @@ export default class KeyboardManager extends React.Component<Props> {
const input = this.previouslyFocusedTextInput; const input = this.previouslyFocusedTextInput;
if (input) { if (Platform.OS === 'android') {
Keyboard.dismiss();
} else if (input) {
TextInput.State.blurTextInput(input); TextInput.State.blurTextInput(input);
} }

View File

@@ -246,11 +246,21 @@ export default class Card extends React.Component<Props> {
this.handleStartInteraction(); this.handleStartInteraction();
onGestureBegin?.(); onGestureBegin?.();
break; break;
case GestureState.CANCELLED: case GestureState.CANCELLED: {
this.isSwiping.setValue(FALSE); this.isSwiping.setValue(FALSE);
this.handleEndInteraction(); this.handleEndInteraction();
const velocity =
gestureDirection === 'vertical' ||
gestureDirection === 'vertical-inverted'
? nativeEvent.velocityY
: nativeEvent.velocityX;
this.animate({ closing: this.props.closing, velocity });
onGestureCanceled?.(); onGestureCanceled?.();
break; break;
}
case GestureState.END: { case GestureState.END: {
this.isSwiping.setValue(FALSE); this.isSwiping.setValue(FALSE);
@@ -507,6 +517,7 @@ export default class Card extends React.Component<Props> {
: gestureDirection === 'vertical' : gestureDirection === 'vertical'
? [styles.shadowVertical, styles.shadowTop] ? [styles.shadowVertical, styles.shadowTop]
: [styles.shadowVertical, styles.shadowBottom], : [styles.shadowVertical, styles.shadowBottom],
{ backgroundColor },
shadowStyle, shadowStyle,
]} ]}
pointerEvents="none" pointerEvents="none"
@@ -543,7 +554,6 @@ const styles = StyleSheet.create({
}, },
shadow: { shadow: {
position: 'absolute', position: 'absolute',
backgroundColor: '#fff',
shadowRadius: 5, shadowRadius: 5,
shadowColor: '#000', shadowColor: '#000',
shadowOpacity: 0.3, shadowOpacity: 0.3,

View File

@@ -46,31 +46,63 @@ type State = {
const GestureHandlerWrapper = GestureHandlerRootView ?? View; const GestureHandlerWrapper = GestureHandlerRootView ?? View;
/**
* Compare two arrays with primitive values as the content.
* We need to make sure that both values and order match.
*/
const isArrayEqual = (a: any[], b: any[]) =>
a.length === b.length && a.every((it, index) => it === b[index]);
export default class StackView extends React.Component<Props, State> { export default class StackView extends React.Component<Props, State> {
static getDerivedStateFromProps( static getDerivedStateFromProps(
props: Readonly<Props>, props: Readonly<Props>,
state: Readonly<State> state: Readonly<State>
) { ) {
// If there was no change in routes, we don't need to compute anything // If there was no change in routes, we don't need to compute anything
if (props.state.routes === state.previousRoutes && state.routes.length) { if (
if (props.descriptors !== state.previousDescriptors) { (props.state.routes === state.previousRoutes ||
const descriptors = state.routes.reduce<StackDescriptorMap>( isArrayEqual(
(acc, route) => { props.state.routes.map((r) => r.key),
acc[route.key] = state.previousRoutes.map((r) => r.key)
props.descriptors[route.key] || state.descriptors[route.key]; )) &&
state.routes.length
) {
let routes = state.routes;
let previousRoutes = state.previousRoutes;
let descriptors = props.descriptors;
let previousDescriptors = state.previousDescriptors;
if (props.descriptors !== state.previousDescriptors) {
descriptors = state.routes.reduce<StackDescriptorMap>((acc, route) => {
acc[route.key] =
props.descriptors[route.key] || state.descriptors[route.key];
return acc;
}, {});
previousDescriptors = props.descriptors;
}
if (props.state.routes !== state.previousRoutes) {
// if any route objects have changed, we should update them
const map = props.state.routes.reduce<Record<string, Route<string>>>(
(acc, route) => {
acc[route.key] = route;
return acc; return acc;
}, },
{} {}
); );
return { routes = state.routes.map((route) => map[route.key] || route);
previousDescriptors: props.descriptors, previousRoutes = props.state.routes;
descriptors,
};
} }
return null; return {
routes,
previousRoutes,
descriptors,
previousDescriptors,
};
} }
// Here we determine which routes were added or removed to animate them // Here we determine which routes were added or removed to animate them

5665
yarn.lock

File diff suppressed because it is too large Load Diff