mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-02-01 09:18:28 +08:00
Compare commits
15 Commits
@react-nav
...
@react-nav
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1406eb83ed | ||
|
|
3e069b718d | ||
|
|
7754eb450f | ||
|
|
95b2599877 | ||
|
|
efcfa7121f | ||
|
|
a8e27ef448 | ||
|
|
946d2923d7 | ||
|
|
794339eeed | ||
|
|
53141a6436 | ||
|
|
a2337648bf | ||
|
|
8f764d8b08 | ||
|
|
f8e998b10c | ||
|
|
da35085f1e | ||
|
|
1f5fb5481a | ||
|
|
18bbd177d9 |
42
.github/workflows/check-repro.yml
vendored
Normal file
42
.github/workflows/check-repro.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
name: Check for repro
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened, edited]
|
||||||
|
issue_comment:
|
||||||
|
types: [created, edited]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-repro:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/github-script@v2
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const body = context.payload.comment
|
||||||
|
? context.payload.comment.body
|
||||||
|
: context.payload.issue.body
|
||||||
|
|
||||||
|
if (!/https?:\/\/((github\.com\/[^/]+\/[^/]+\/?[\s\n]+)|(snack\.expo\.io\/.+))/gm.test(body)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await github.issues.addLabels({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
labels: ['repro provided'],
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
await github.issues.removeLabel({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
name: 'needs repro',
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
if (!/Label does not exist/.test(error.message)) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -291,6 +291,7 @@ export default function App() {
|
|||||||
{() => (
|
{() => (
|
||||||
<Drawer.Navigator
|
<Drawer.Navigator
|
||||||
drawerType={isLargeScreen ? 'permanent' : undefined}
|
drawerType={isLargeScreen ? 'permanent' : undefined}
|
||||||
|
screenOptions={{ headerShown: true }}
|
||||||
>
|
>
|
||||||
<Drawer.Screen
|
<Drawer.Screen
|
||||||
name="Examples"
|
name="Examples"
|
||||||
|
|||||||
@@ -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.11.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@5.11.1...@react-navigation/bottom-tabs@5.11.2) (2020-11-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.11.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@5.11.0...@react-navigation/bottom-tabs@5.11.1) (2020-11-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.11.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@5.10.7...@react-navigation/bottom-tabs@5.11.0) (2020-11-09)
|
# [5.11.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@5.10.7...@react-navigation/bottom-tabs@5.11.0) (2020-11-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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.11.0",
|
"version": "5.11.2",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.16.2",
|
"@react-native-community/bob": "^0.16.2",
|
||||||
"@react-navigation/native": "^5.8.8",
|
"@react-navigation/native": "^5.8.10",
|
||||||
"@testing-library/react-native": "^7.1.0",
|
"@testing-library/react-native": "^7.1.0",
|
||||||
"@types/color": "^3.0.1",
|
"@types/color": "^3.0.1",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
|
|||||||
@@ -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.3.10](https://github.com/react-navigation/react-navigation/compare/@react-navigation/compat@5.3.9...@react-navigation/compat@5.3.10) (2020-11-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.9](https://github.com/react-navigation/react-navigation/compare/@react-navigation/compat@5.3.8...@react-navigation/compat@5.3.9) (2020-11-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.3.8](https://github.com/react-navigation/react-navigation/compare/@react-navigation/compat@5.3.7...@react-navigation/compat@5.3.8) (2020-11-09)
|
## [5.3.8](https://github.com/react-navigation/react-navigation/compare/@react-navigation/compat@5.3.7...@react-navigation/compat@5.3.8) (2020-11-09)
|
||||||
|
|
||||||
**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.3.8",
|
"version": "5.3.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.16.2",
|
"@react-native-community/bob": "^0.16.2",
|
||||||
"@react-navigation/native": "^5.8.8",
|
"@react-navigation/native": "^5.8.10",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
|
|||||||
@@ -3,6 +3,28 @@
|
|||||||
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.14.4](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@5.14.3...@react-navigation/core@5.14.4) (2020-11-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix incorrect state change events in independent nested container ([95b2599](https://github.com/react-navigation/react-navigation/commit/95b2599877f5ceedf753e399e0586bb4af54cb87)), closes [#9080](https://github.com/react-navigation/react-navigation/issues/9080)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.14.3](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@5.14.2...@react-navigation/core@5.14.3) (2020-11-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* improve the error message for incorrect screen configuration ([8f764d8](https://github.com/react-navigation/react-navigation/commit/8f764d8b0809604716d5d92ea33cc1beee02e804))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.14.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@5.14.1...@react-navigation/core@5.14.2) (2020-11-09)
|
## [5.14.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@5.14.1...@react-navigation/core@5.14.2) (2020-11-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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.14.2",
|
"version": "5.14.4",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
"react-native",
|
"react-native",
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ import {
|
|||||||
NavigationAction,
|
NavigationAction,
|
||||||
} from '@react-navigation/routers';
|
} from '@react-navigation/routers';
|
||||||
import EnsureSingleNavigator from './EnsureSingleNavigator';
|
import EnsureSingleNavigator from './EnsureSingleNavigator';
|
||||||
|
import UnhandledActionContext from './UnhandledActionContext';
|
||||||
import NavigationBuilderContext from './NavigationBuilderContext';
|
import NavigationBuilderContext from './NavigationBuilderContext';
|
||||||
import NavigationStateContext from './NavigationStateContext';
|
import NavigationStateContext from './NavigationStateContext';
|
||||||
import UnhandledActionContext from './UnhandledActionContext';
|
import NavigationRouteContext from './NavigationRouteContext';
|
||||||
|
import NavigationContext from './NavigationContext';
|
||||||
import { ScheduleUpdateContext } from './useScheduleUpdate';
|
import { ScheduleUpdateContext } from './useScheduleUpdate';
|
||||||
import useChildListeners from './useChildListeners';
|
import useChildListeners from './useChildListeners';
|
||||||
import useKeyedChildListeners from './useKeyedChildListeners';
|
import useKeyedChildListeners from './useKeyedChildListeners';
|
||||||
@@ -397,7 +399,7 @@ const BaseNavigationContainer = React.forwardRef(
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
let element = (
|
||||||
<ScheduleUpdateContext.Provider value={scheduleContext}>
|
<ScheduleUpdateContext.Provider value={scheduleContext}>
|
||||||
<NavigationBuilderContext.Provider value={builderContext}>
|
<NavigationBuilderContext.Provider value={builderContext}>
|
||||||
<NavigationStateContext.Provider value={context}>
|
<NavigationStateContext.Provider value={context}>
|
||||||
@@ -410,6 +412,19 @@ const BaseNavigationContainer = React.forwardRef(
|
|||||||
</NavigationBuilderContext.Provider>
|
</NavigationBuilderContext.Provider>
|
||||||
</ScheduleUpdateContext.Provider>
|
</ScheduleUpdateContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (independent) {
|
||||||
|
// We need to clear any existing contexts for nested independent container to work correctly
|
||||||
|
element = (
|
||||||
|
<NavigationRouteContext.Provider value={undefined}>
|
||||||
|
<NavigationContext.Provider value={undefined}>
|
||||||
|
{element}
|
||||||
|
</NavigationContext.Provider>
|
||||||
|
</NavigationRouteContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -757,3 +757,67 @@ it('invokes the unhandled action listener with the unhandled action', () => {
|
|||||||
type: 'NAVIGATE',
|
type: 'NAVIGATE',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('works with state change events in independent nested container', () => {
|
||||||
|
const TestNavigator = (props: any) => {
|
||||||
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{state.routes.map((route) => descriptors[route.key].render())}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ref = React.createRef<NavigationContainerRef>();
|
||||||
|
|
||||||
|
const onStateChange = jest.fn();
|
||||||
|
|
||||||
|
render(
|
||||||
|
<BaseNavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="foo">
|
||||||
|
{() => (
|
||||||
|
<BaseNavigationContainer
|
||||||
|
independent
|
||||||
|
ref={ref}
|
||||||
|
onStateChange={onStateChange}
|
||||||
|
>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="qux">{() => null}</Screen>
|
||||||
|
<Screen name="lex">{() => null}</Screen>
|
||||||
|
</TestNavigator>
|
||||||
|
</BaseNavigationContainer>
|
||||||
|
)}
|
||||||
|
</Screen>
|
||||||
|
<Screen name="bar">{() => null}</Screen>
|
||||||
|
</TestNavigator>
|
||||||
|
</BaseNavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
act(() => ref.current?.navigate('lex'));
|
||||||
|
|
||||||
|
expect(onStateChange).toBeCalledWith({
|
||||||
|
index: 1,
|
||||||
|
key: '15',
|
||||||
|
routeNames: ['qux', 'lex'],
|
||||||
|
routes: [
|
||||||
|
{ key: 'qux', name: 'qux' },
|
||||||
|
{ key: 'lex', name: 'lex' },
|
||||||
|
],
|
||||||
|
stale: false,
|
||||||
|
type: 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(ref.current?.getRootState()).toEqual({
|
||||||
|
index: 1,
|
||||||
|
key: '15',
|
||||||
|
routeNames: ['qux', 'lex'],
|
||||||
|
routes: [
|
||||||
|
{ key: 'qux', name: 'qux' },
|
||||||
|
{ key: 'lex', name: 'lex' },
|
||||||
|
],
|
||||||
|
stale: false,
|
||||||
|
type: 'test',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1462,6 +1462,51 @@ it('throws when Screen is not the direct children', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('throws when undefined component is a direct children', () => {
|
||||||
|
const TestNavigator = (props: any) => {
|
||||||
|
useNavigationBuilder(MockRouter, props);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Undefined = undefined;
|
||||||
|
|
||||||
|
const spy = jest.spyOn(console, 'error').mockImplementation();
|
||||||
|
const element = (
|
||||||
|
<BaseNavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
<Undefined name="foo" component={jest.fn()} />
|
||||||
|
</TestNavigator>
|
||||||
|
</BaseNavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
spy.mockRestore();
|
||||||
|
|
||||||
|
expect(() => render(element).update(element)).toThrowError(
|
||||||
|
"A navigator can only contain 'Screen' components as its direct children (found 'undefined' for the screen 'foo')"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws when a tag is a direct children', () => {
|
||||||
|
const TestNavigator = (props: any) => {
|
||||||
|
useNavigationBuilder(MockRouter, props);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const element = (
|
||||||
|
<BaseNavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
<screen name="foo" component={jest.fn()} />
|
||||||
|
</TestNavigator>
|
||||||
|
</BaseNavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => render(element).update(element)).toThrowError(
|
||||||
|
"A navigator can only contain 'Screen' components as its direct children (found 'screen' for the screen 'foo')"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('throws when a React Element is not the direct children', () => {
|
it('throws when a React Element is not the direct children', () => {
|
||||||
const TestNavigator = (props: any) => {
|
const TestNavigator = (props: any) => {
|
||||||
useNavigationBuilder(MockRouter, props);
|
useNavigationBuilder(MockRouter, props);
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ type ResultState = PartialState<NavigationState> & {
|
|||||||
state?: ResultState;
|
state?: ResultState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ParsedRoute = {
|
||||||
|
name: string;
|
||||||
|
params?: Record<string, any> | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility to parse a path string to initial state object accepted by the container.
|
* Utility to parse a path string to initial state object accepted by the container.
|
||||||
* This is useful for deep linking when we need to handle the incoming URL.
|
* This is useful for deep linking when we need to handle the incoming URL.
|
||||||
@@ -224,7 +229,7 @@ export default function getStateFromPath(
|
|||||||
if (legacy === false) {
|
if (legacy === false) {
|
||||||
// If we're not in legacy mode,, we match the whole path against the regex instead of segments
|
// If we're not in legacy mode,, we match the whole path against the regex instead of segments
|
||||||
// This makes sure matches such as wildcard will catch any unmatched routes, even if nested
|
// This makes sure matches such as wildcard will catch any unmatched routes, even if nested
|
||||||
const { routeNames, allParams, remainingPath } = matchAgainstConfigs(
|
const { routes, remainingPath } = matchAgainstConfigs(
|
||||||
remaining,
|
remaining,
|
||||||
configs.map((c) => ({
|
configs.map((c) => ({
|
||||||
...c,
|
...c,
|
||||||
@@ -233,39 +238,30 @@ export default function getStateFromPath(
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (routeNames !== undefined) {
|
if (routes !== undefined) {
|
||||||
// This will always be empty if full path matched
|
// This will always be empty if full path matched
|
||||||
|
current = createNestedStateObject(routes, initialRoutes);
|
||||||
remaining = remainingPath;
|
remaining = remainingPath;
|
||||||
current = createNestedStateObject(
|
|
||||||
createRouteObjects(configs, routeNames, allParams),
|
|
||||||
initialRoutes
|
|
||||||
);
|
|
||||||
result = current;
|
result = current;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// In legacy mode, we divide the path into segments and match piece by piece
|
// In legacy mode, we divide the path into segments and match piece by piece
|
||||||
// This preserves the legacy behaviour, but we should remove it in next major
|
// This preserves the legacy behaviour, but we should remove it in next major
|
||||||
while (remaining) {
|
while (remaining) {
|
||||||
let { routeNames, allParams, remainingPath } = matchAgainstConfigs(
|
let { routes, remainingPath } = matchAgainstConfigs(remaining, configs);
|
||||||
remaining,
|
|
||||||
configs
|
|
||||||
);
|
|
||||||
|
|
||||||
remaining = remainingPath;
|
remaining = remainingPath;
|
||||||
|
|
||||||
// If we hadn't matched any segments earlier, use the path as route name
|
// If we hadn't matched any segments earlier, use the path as route name
|
||||||
if (routeNames === undefined) {
|
if (routes === undefined) {
|
||||||
const segments = remaining.split('/');
|
const segments = remaining.split('/');
|
||||||
|
|
||||||
routeNames = [decodeURIComponent(segments[0])];
|
routes = [{ name: decodeURIComponent(segments[0]) }];
|
||||||
segments.shift();
|
segments.shift();
|
||||||
remaining = segments.join('/');
|
remaining = segments.join('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = createNestedStateObject(
|
const state = createNestedStateObject(routes, initialRoutes);
|
||||||
createRouteObjects(configs, routeNames, allParams),
|
|
||||||
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
|
||||||
@@ -309,8 +305,7 @@ const joinPaths = (...paths: string[]): string =>
|
|||||||
.join('/');
|
.join('/');
|
||||||
|
|
||||||
const matchAgainstConfigs = (remaining: string, configs: RouteConfig[]) => {
|
const matchAgainstConfigs = (remaining: string, configs: RouteConfig[]) => {
|
||||||
let routeNames: string[] | undefined;
|
let routes: ParsedRoute[] | undefined;
|
||||||
let allParams: Record<string, any> | undefined;
|
|
||||||
let remainingPath = remaining;
|
let remainingPath = remaining;
|
||||||
|
|
||||||
// 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
|
||||||
@@ -323,21 +318,40 @@ const matchAgainstConfigs = (remaining: string, configs: RouteConfig[]) => {
|
|||||||
|
|
||||||
// If our regex matches, we need to extract params from the path
|
// If our regex matches, we need to extract params from the path
|
||||||
if (match) {
|
if (match) {
|
||||||
routeNames = [...config.routeNames];
|
const matchedParams = config.pattern
|
||||||
|
?.split('/')
|
||||||
|
.filter((p) => p.startsWith(':'))
|
||||||
|
.reduce<Record<string, any>>(
|
||||||
|
(acc, p, i) =>
|
||||||
|
Object.assign(acc, {
|
||||||
|
// The param segments appear every second item starting from 2 in the regex match result
|
||||||
|
[p]: match![(i + 1) * 2].replace(/\//, ''),
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
const paramPatterns = config.pattern
|
routes = config.routeNames.map((name) => {
|
||||||
.split('/')
|
const config = configs.find((c) => c.screen === name);
|
||||||
.filter((p) => p.startsWith(':'));
|
const params = config?.path
|
||||||
|
?.split('/')
|
||||||
|
.filter((p) => p.startsWith(':'))
|
||||||
|
.reduce<Record<string, any>>((acc, p) => {
|
||||||
|
const value = matchedParams[p];
|
||||||
|
|
||||||
if (paramPatterns.length) {
|
if (value) {
|
||||||
allParams = paramPatterns.reduce<Record<string, any>>((acc, p, i) => {
|
const key = p.replace(/^:/, '').replace(/\?$/, '');
|
||||||
const value = match![(i + 1) * 2].replace(/\//, ''); // The param segments appear every second item starting from 2 in the regex match result
|
acc[key] = config.parse?.[key] ? config.parse[key](value) : value;
|
||||||
|
}
|
||||||
|
|
||||||
acc[p] = value;
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
return acc;
|
if (params && Object.keys(params).length) {
|
||||||
}, {});
|
return { name, params };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { name };
|
||||||
|
});
|
||||||
|
|
||||||
remainingPath = remainingPath.replace(match[1], '');
|
remainingPath = remainingPath.replace(match[1], '');
|
||||||
|
|
||||||
@@ -345,7 +359,7 @@ const matchAgainstConfigs = (remaining: string, configs: RouteConfig[]) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { routeNames, allParams, remainingPath };
|
return { routes, remainingPath };
|
||||||
};
|
};
|
||||||
|
|
||||||
const createNormalizedConfigs = (
|
const createNormalizedConfigs = (
|
||||||
@@ -508,57 +522,48 @@ const findInitialRoute = (
|
|||||||
// it is the end of state and if there is initialRoute for this level
|
// it is the end of state and if there is initialRoute for this level
|
||||||
const createStateObject = (
|
const createStateObject = (
|
||||||
initialRoute: string | undefined,
|
initialRoute: string | undefined,
|
||||||
routeName: string,
|
route: ParsedRoute,
|
||||||
params: Record<string, any> | undefined,
|
|
||||||
isEmpty: boolean
|
isEmpty: boolean
|
||||||
): InitialState => {
|
): InitialState => {
|
||||||
if (isEmpty) {
|
if (isEmpty) {
|
||||||
if (initialRoute) {
|
if (initialRoute) {
|
||||||
return {
|
return {
|
||||||
index: 1,
|
index: 1,
|
||||||
routes: [{ name: initialRoute }, { name: routeName as string, params }],
|
routes: [{ name: initialRoute }, route],
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
routes: [{ name: routeName as string, params }],
|
routes: [route],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (initialRoute) {
|
if (initialRoute) {
|
||||||
return {
|
return {
|
||||||
index: 1,
|
index: 1,
|
||||||
routes: [
|
routes: [{ name: initialRoute }, { ...route, state: { routes: [] } }],
|
||||||
{ name: initialRoute },
|
|
||||||
{ name: routeName as string, params, state: { routes: [] } },
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
routes: [{ name: routeName as string, params, state: { routes: [] } }],
|
routes: [{ ...route, state: { routes: [] } }],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const createNestedStateObject = (
|
const createNestedStateObject = (
|
||||||
routes: { name: string; params?: object }[],
|
routes: ParsedRoute[],
|
||||||
initialRoutes: InitialRouteConfig[]
|
initialRoutes: InitialRouteConfig[]
|
||||||
) => {
|
) => {
|
||||||
let state: InitialState;
|
let state: InitialState;
|
||||||
let route = routes.shift() as { name: string; params?: object };
|
let route = routes.shift() as ParsedRoute;
|
||||||
let initialRoute = findInitialRoute(route.name, initialRoutes);
|
let initialRoute = findInitialRoute(route.name, initialRoutes);
|
||||||
|
|
||||||
state = createStateObject(
|
state = createStateObject(initialRoute, route, routes.length === 0);
|
||||||
initialRoute,
|
|
||||||
route.name,
|
|
||||||
route.params,
|
|
||||||
routes.length === 0
|
|
||||||
);
|
|
||||||
|
|
||||||
if (routes.length > 0) {
|
if (routes.length > 0) {
|
||||||
let nestedState = state;
|
let nestedState = state;
|
||||||
|
|
||||||
while ((route = routes.shift() as { name: string; params?: object })) {
|
while ((route = routes.shift() as ParsedRoute)) {
|
||||||
initialRoute = findInitialRoute(route.name, initialRoutes);
|
initialRoute = findInitialRoute(route.name, initialRoutes);
|
||||||
|
|
||||||
const nestedStateIndex =
|
const nestedStateIndex =
|
||||||
@@ -566,8 +571,7 @@ const createNestedStateObject = (
|
|||||||
|
|
||||||
nestedState.routes[nestedStateIndex].state = createStateObject(
|
nestedState.routes[nestedStateIndex].state = createStateObject(
|
||||||
initialRoute,
|
initialRoute,
|
||||||
route.name,
|
route,
|
||||||
route.params,
|
|
||||||
routes.length === 0
|
routes.length === 0
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -581,46 +585,6 @@ const createNestedStateObject = (
|
|||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createRouteObjects = (
|
|
||||||
configs: RouteConfig[],
|
|
||||||
routeNames: string[],
|
|
||||||
allParams?: Record<string, any>
|
|
||||||
) =>
|
|
||||||
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?.[key] ? config.parse[key](value) : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params && Object.keys(params).length) {
|
|
||||||
return { name, params };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { name };
|
|
||||||
});
|
|
||||||
|
|
||||||
const findFocusedRoute = (state: InitialState) => {
|
const findFocusedRoute = (state: InitialState) => {
|
||||||
let current: InitialState | undefined = state;
|
let current: InitialState | undefined = state;
|
||||||
|
|
||||||
|
|||||||
@@ -90,10 +90,17 @@ const getRouteConfigsFromChildren = <
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`A navigator can only contain 'Screen' components as its direct children (found '${
|
`A navigator can only contain 'Screen' components as its direct children (found ${
|
||||||
// @ts-expect-error: child can be any type and we're accessing it safely, but TS doesn't understand it
|
React.isValidElement(child)
|
||||||
child.type?.name ? child.type.name : String(child)
|
? `'${
|
||||||
}'). To render this component in the navigator, pass it in the 'component' prop to 'Screen'.`
|
typeof child.type === 'string' ? child.type : child.type?.name
|
||||||
|
}'${
|
||||||
|
child.props?.name ? ` for the screen '${child.props.name}'` : ''
|
||||||
|
}`
|
||||||
|
: typeof child === 'object'
|
||||||
|
? JSON.stringify(child)
|
||||||
|
: `'${String(child)}'`
|
||||||
|
}). To render this component in the navigator, pass it in the 'component' prop to 'Screen'.`
|
||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -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.18](https://github.com/react-navigation/react-navigation/compare/@react-navigation/devtools@5.1.17...@react-navigation/devtools@5.1.18) (2020-11-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/devtools
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.17](https://github.com/react-navigation/react-navigation/compare/@react-navigation/devtools@5.1.16...@react-navigation/devtools@5.1.17) (2020-11-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/devtools
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.1.16](https://github.com/react-navigation/react-navigation/compare/@react-navigation/devtools@5.1.15...@react-navigation/devtools@5.1.16) (2020-11-09)
|
## [5.1.16](https://github.com/react-navigation/react-navigation/compare/@react-navigation/devtools@5.1.15...@react-navigation/devtools@5.1.16) (2020-11-09)
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/devtools
|
**Note:** Version bump only for package @react-navigation/devtools
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/devtools",
|
"name": "@react-navigation/devtools",
|
||||||
"description": "Developer tools for React Navigation",
|
"description": "Developer tools for React Navigation",
|
||||||
"version": "5.1.16",
|
"version": "5.1.18",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
"react-native",
|
"react-native",
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/core": "^5.14.2",
|
"@react-navigation/core": "^5.14.4",
|
||||||
"deep-equal": "^2.0.4"
|
"deep-equal": "^2.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -3,6 +3,44 @@
|
|||||||
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.11.4](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@5.11.3...@react-navigation/drawer@5.11.4) (2020-11-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.11.3](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@5.11.2...@react-navigation/drawer@5.11.3) (2020-11-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* hide drawer's header by default ([794339e](https://github.com/react-navigation/react-navigation/commit/794339eeed7c0d3b0e8b1752e494fbb4608ddfad))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.11.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@5.11.1...@react-navigation/drawer@5.11.2) (2020-11-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.11.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@5.11.0...@react-navigation/drawer@5.11.1) (2020-11-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* provide correct context to drawe header ([18bbd17](https://github.com/react-navigation/react-navigation/commit/18bbd177d91ccc4308516208a8b9f1a34ca5cc41))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.11.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@5.10.7...@react-navigation/drawer@5.11.0) (2020-11-09)
|
# [5.11.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@5.10.7...@react-navigation/drawer@5.11.0) (2020-11-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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.11.0",
|
"version": "5.11.4",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.16.2",
|
"@react-native-community/bob": "^0.16.2",
|
||||||
"@react-navigation/native": "^5.8.8",
|
"@react-navigation/native": "^5.8.10",
|
||||||
"@testing-library/react-native": "^7.1.0",
|
"@testing-library/react-native": "^7.1.0",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "^0.63.30",
|
"@types/react-native": "^0.63.30",
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import {
|
|||||||
import { ScreenContainer } from 'react-native-screens';
|
import { ScreenContainer } from 'react-native-screens';
|
||||||
import {
|
import {
|
||||||
NavigationHelpersContext,
|
NavigationHelpersContext,
|
||||||
|
NavigationContext,
|
||||||
|
NavigationRouteContext,
|
||||||
DrawerNavigationState,
|
DrawerNavigationState,
|
||||||
DrawerActions,
|
DrawerActions,
|
||||||
useTheme,
|
useTheme,
|
||||||
@@ -174,7 +176,7 @@ export default function DrawerView({
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
header = (props: DrawerHeaderProps) => <Header {...props} />,
|
header = (props: DrawerHeaderProps) => <Header {...props} />,
|
||||||
headerShown = true,
|
headerShown = false,
|
||||||
} = descriptor.options;
|
} = descriptor.options;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -184,12 +186,16 @@ export default function DrawerView({
|
|||||||
isVisible={isFocused}
|
isVisible={isFocused}
|
||||||
enabled={detachInactiveScreens}
|
enabled={detachInactiveScreens}
|
||||||
>
|
>
|
||||||
{headerShown
|
{headerShown ? (
|
||||||
? header({
|
<NavigationContext.Provider value={descriptor.navigation}>
|
||||||
layout: dimensions,
|
<NavigationRouteContext.Provider value={route}>
|
||||||
scene: { route, descriptor },
|
{header({
|
||||||
})
|
layout: dimensions,
|
||||||
: null}
|
scene: { route, descriptor },
|
||||||
|
})}
|
||||||
|
</NavigationRouteContext.Provider>
|
||||||
|
</NavigationContext.Provider>
|
||||||
|
) : null}
|
||||||
{descriptor.render()}
|
{descriptor.render()}
|
||||||
</ResourceSavingScene>
|
</ResourceSavingScene>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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.3.10](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-bottom-tabs@5.3.9...@react-navigation/material-bottom-tabs@5.3.10) (2020-11-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.9](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-bottom-tabs@5.3.8...@react-navigation/material-bottom-tabs@5.3.9) (2020-11-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.3.8](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-bottom-tabs@5.3.7...@react-navigation/material-bottom-tabs@5.3.8) (2020-11-09)
|
## [5.3.8](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-bottom-tabs@5.3.7...@react-navigation/material-bottom-tabs@5.3.8) (2020-11-09)
|
||||||
|
|
||||||
**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.3.8",
|
"version": "5.3.10",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.16.2",
|
"@react-native-community/bob": "^0.16.2",
|
||||||
"@react-navigation/native": "^5.8.8",
|
"@react-navigation/native": "^5.8.10",
|
||||||
"@testing-library/react-native": "^7.1.0",
|
"@testing-library/react-native": "^7.1.0",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "^0.63.30",
|
"@types/react-native": "^0.63.30",
|
||||||
|
|||||||
@@ -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.3.10](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-top-tabs@5.3.9...@react-navigation/material-top-tabs@5.3.10) (2020-11-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.9](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-top-tabs@5.3.8...@react-navigation/material-top-tabs@5.3.9) (2020-11-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.3.8](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-top-tabs@5.3.7...@react-navigation/material-top-tabs@5.3.8) (2020-11-09)
|
## [5.3.8](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-top-tabs@5.3.7...@react-navigation/material-top-tabs@5.3.8) (2020-11-09)
|
||||||
|
|
||||||
**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.3.8",
|
"version": "5.3.10",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.16.2",
|
"@react-native-community/bob": "^0.16.2",
|
||||||
"@react-navigation/native": "^5.8.8",
|
"@react-navigation/native": "^5.8.10",
|
||||||
"@testing-library/react-native": "^7.1.0",
|
"@testing-library/react-native": "^7.1.0",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "^0.63.30",
|
"@types/react-native": "^0.63.30",
|
||||||
|
|||||||
@@ -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.8.10](https://github.com/react-navigation/react-navigation/compare/@react-navigation/native@5.8.9...@react-navigation/native@5.8.10) (2020-11-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.8.9](https://github.com/react-navigation/react-navigation/compare/@react-navigation/native@5.8.8...@react-navigation/native@5.8.9) (2020-11-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.8.8](https://github.com/react-navigation/react-navigation/compare/@react-navigation/native@5.8.7...@react-navigation/native@5.8.8) (2020-11-09)
|
## [5.8.8](https://github.com/react-navigation/react-navigation/compare/@react-navigation/native@5.8.7...@react-navigation/native@5.8.8) (2020-11-09)
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/native
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|||||||
@@ -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.8.8",
|
"version": "5.8.10",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native",
|
"react-native",
|
||||||
"react-navigation",
|
"react-navigation",
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/core": "^5.14.2",
|
"@react-navigation/core": "^5.14.4",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"nanoid": "^3.1.15"
|
"nanoid": "^3.1.15"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,36 @@
|
|||||||
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.12.8](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@5.12.7...@react-navigation/stack@5.12.8) (2020-11-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* force dismiss keyboard if there was no gesture ([3e069b7](https://github.com/react-navigation/react-navigation/commit/3e069b718d60f5381957f2d3838ee04ee9384779)), closes [#9078](https://github.com/react-navigation/react-navigation/issues/9078)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.12.7](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@5.12.6...@react-navigation/stack@5.12.7) (2020-11-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.12.6](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@5.12.5...@react-navigation/stack@5.12.6) (2020-11-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* make sure inactive screen don't increase scroll area on web ([da35085](https://github.com/react-navigation/react-navigation/commit/da35085f1e3440f26eea800c892c88aec64d072f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.12.5](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@5.12.4...@react-navigation/stack@5.12.5) (2020-11-09)
|
## [5.12.5](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@5.12.4...@react-navigation/stack@5.12.5) (2020-11-09)
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/stack
|
**Note:** Version bump only for package @react-navigation/stack
|
||||||
|
|||||||
@@ -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.12.5",
|
"version": "5.12.8",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.16.2",
|
"@react-native-community/bob": "^0.16.2",
|
||||||
"@react-native-community/masked-view": "^0.1.10",
|
"@react-native-community/masked-view": "^0.1.10",
|
||||||
"@react-navigation/native": "^5.8.8",
|
"@react-navigation/native": "^5.8.10",
|
||||||
"@testing-library/react-native": "^7.1.0",
|
"@testing-library/react-native": "^7.1.0",
|
||||||
"@types/color": "^3.0.1",
|
"@types/color": "^3.0.1",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { TextInput, Platform, Keyboard } from 'react-native';
|
import { TextInput, Keyboard, HostComponent } from 'react-native';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
children: (props: {
|
children: (props: {
|
||||||
onPageChangeStart: () => void;
|
onPageChangeStart: () => void;
|
||||||
onPageChangeConfirm: () => void;
|
onPageChangeConfirm: (force: boolean) => void;
|
||||||
onPageChangeCancel: () => void;
|
onPageChangeCancel: () => void;
|
||||||
}) => React.ReactNode;
|
}) => React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type InputRef = React.ElementRef<HostComponent<unknown>> | undefined;
|
||||||
|
|
||||||
export default class KeyboardManager extends React.Component<Props> {
|
export default class KeyboardManager extends React.Component<Props> {
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.clearKeyboardTimeout();
|
this.clearKeyboardTimeout();
|
||||||
@@ -17,7 +19,7 @@ export default class KeyboardManager extends React.Component<Props> {
|
|||||||
|
|
||||||
// Numeric id of the previously focused text input
|
// Numeric id of the previously focused text input
|
||||||
// When a gesture didn't change the tab, we can restore the focused input with this
|
// When a gesture didn't change the tab, we can restore the focused input with this
|
||||||
private previouslyFocusedTextInput: any | null = null;
|
private previouslyFocusedTextInput: InputRef = undefined;
|
||||||
private startTimestamp: number = 0;
|
private startTimestamp: number = 0;
|
||||||
private keyboardTimeout: any;
|
private keyboardTimeout: any;
|
||||||
|
|
||||||
@@ -35,7 +37,8 @@ export default class KeyboardManager extends React.Component<Props> {
|
|||||||
|
|
||||||
this.clearKeyboardTimeout();
|
this.clearKeyboardTimeout();
|
||||||
|
|
||||||
const input: any = TextInput.State.currentlyFocusedInput
|
// @ts-expect-error: blurTextInput accepts both number and ref, but types say only ref
|
||||||
|
const input: InputRef = TextInput.State.currentlyFocusedInput
|
||||||
? TextInput.State.currentlyFocusedInput()
|
? TextInput.State.currentlyFocusedInput()
|
||||||
: TextInput.State.currentlyFocusedField();
|
: TextInput.State.currentlyFocusedField();
|
||||||
|
|
||||||
@@ -49,25 +52,30 @@ export default class KeyboardManager extends React.Component<Props> {
|
|||||||
this.startTimestamp = Date.now();
|
this.startTimestamp = Date.now();
|
||||||
};
|
};
|
||||||
|
|
||||||
private handlePageChangeConfirm = () => {
|
private handlePageChangeConfirm = (force: boolean) => {
|
||||||
if (!this.props.enabled) {
|
if (!this.props.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clearKeyboardTimeout();
|
this.clearKeyboardTimeout();
|
||||||
|
|
||||||
const input = this.previouslyFocusedTextInput;
|
if (force) {
|
||||||
|
// Always dismiss input, even if we don't have a ref to it
|
||||||
|
// We might not have the ref if onPageChangeStart was never called
|
||||||
|
// This can happen if page change was not from a gesture
|
||||||
|
Keyboard.dismiss();
|
||||||
|
} else {
|
||||||
|
const input = this.previouslyFocusedTextInput;
|
||||||
|
|
||||||
if (input) {
|
if (input) {
|
||||||
if (Platform.OS === 'android') {
|
// Dismiss the keyboard only if an input was a focused before
|
||||||
Keyboard.dismiss();
|
// This makes sure we don't dismiss input on going back and focusing an input
|
||||||
} else {
|
|
||||||
TextInput.State.blurTextInput(input);
|
TextInput.State.blurTextInput(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup the ID on successful page change
|
// Cleanup the ID on successful page change
|
||||||
this.previouslyFocusedTextInput = null;
|
this.previouslyFocusedTextInput = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
private handlePageChangeCancel = () => {
|
private handlePageChangeCancel = () => {
|
||||||
@@ -91,11 +99,11 @@ export default class KeyboardManager extends React.Component<Props> {
|
|||||||
if (Date.now() - this.startTimestamp < 100) {
|
if (Date.now() - this.startTimestamp < 100) {
|
||||||
this.keyboardTimeout = setTimeout(() => {
|
this.keyboardTimeout = setTimeout(() => {
|
||||||
TextInput.State.focusTextInput(input);
|
TextInput.State.focusTextInput(input);
|
||||||
this.previouslyFocusedTextInput = null;
|
this.previouslyFocusedTextInput = undefined;
|
||||||
}, 100);
|
}, 100);
|
||||||
} else {
|
} else {
|
||||||
TextInput.State.focusTextInput(input);
|
TextInput.State.focusTextInput(input);
|
||||||
this.previouslyFocusedTextInput = null;
|
this.previouslyFocusedTextInput = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ type Props = ViewProps & {
|
|||||||
gestureDirection: GestureDirection;
|
gestureDirection: GestureDirection;
|
||||||
onOpen: () => void;
|
onOpen: () => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onTransitionStart?: (props: { closing: boolean }) => void;
|
onTransition?: (props: { closing: boolean; gesture: boolean }) => void;
|
||||||
onGestureBegin?: () => void;
|
onGestureBegin?: () => void;
|
||||||
onGestureCanceled?: () => void;
|
onGestureCanceled?: () => void;
|
||||||
onGestureEnd?: () => void;
|
onGestureEnd?: () => void;
|
||||||
@@ -178,7 +178,7 @@ export default class Card extends React.Component<Props> {
|
|||||||
transitionSpec,
|
transitionSpec,
|
||||||
onOpen,
|
onOpen,
|
||||||
onClose,
|
onClose,
|
||||||
onTransitionStart,
|
onTransition,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const toValue = this.getAnimateToValue({
|
const toValue = this.getAnimateToValue({
|
||||||
@@ -198,7 +198,7 @@ export default class Card extends React.Component<Props> {
|
|||||||
|
|
||||||
clearTimeout(this.pendingGestureCallback);
|
clearTimeout(this.pendingGestureCallback);
|
||||||
|
|
||||||
onTransitionStart?.({ closing });
|
onTransition?.({ closing, gesture: velocity !== undefined });
|
||||||
animation(gesture, {
|
animation(gesture, {
|
||||||
...spec.config,
|
...spec.config,
|
||||||
velocity,
|
velocity,
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ type Props = TransitionPreset & {
|
|||||||
) => void;
|
) => void;
|
||||||
onTransitionEnd?: (props: { route: Route<string> }, closing: boolean) => void;
|
onTransitionEnd?: (props: { route: Route<string> }, closing: boolean) => void;
|
||||||
onPageChangeStart?: () => void;
|
onPageChangeStart?: () => void;
|
||||||
onPageChangeConfirm?: () => void;
|
onPageChangeConfirm?: (force: boolean) => void;
|
||||||
onPageChangeCancel?: () => void;
|
onPageChangeCancel?: () => void;
|
||||||
onGestureStart?: (props: { route: Route<string> }) => void;
|
onGestureStart?: (props: { route: Route<string> }) => void;
|
||||||
onGestureEnd?: (props: { route: Route<string> }) => void;
|
onGestureEnd?: (props: { route: Route<string> }) => void;
|
||||||
@@ -116,42 +116,58 @@ function CardContainer({
|
|||||||
scene,
|
scene,
|
||||||
transitionSpec,
|
transitionSpec,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
React.useEffect(() => {
|
|
||||||
onPageChangeConfirm?.();
|
|
||||||
}, [active, onPageChangeConfirm]);
|
|
||||||
|
|
||||||
const handleOpen = () => {
|
const handleOpen = () => {
|
||||||
onTransitionEnd?.({ route: scene.route }, false);
|
const { route } = scene;
|
||||||
onOpenRoute({ route: scene.route });
|
|
||||||
|
onTransitionEnd?.({ route }, false);
|
||||||
|
onOpenRoute({ route });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onTransitionEnd?.({ route: scene.route }, true);
|
const { route } = scene;
|
||||||
onCloseRoute({ route: scene.route });
|
|
||||||
|
onTransitionEnd?.({ route }, true);
|
||||||
|
onCloseRoute({ route });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGestureBegin = () => {
|
const handleGestureBegin = () => {
|
||||||
|
const { route } = scene;
|
||||||
|
|
||||||
onPageChangeStart?.();
|
onPageChangeStart?.();
|
||||||
onGestureStart?.({ route: scene.route });
|
onGestureStart?.({ route });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGestureCanceled = () => {
|
const handleGestureCanceled = () => {
|
||||||
|
const { route } = scene;
|
||||||
|
|
||||||
onPageChangeCancel?.();
|
onPageChangeCancel?.();
|
||||||
onGestureCancel?.({ route: scene.route });
|
onGestureCancel?.({ route });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGestureEnd = () => {
|
const handleGestureEnd = () => {
|
||||||
onGestureEnd?.({ route: scene.route });
|
const { route } = scene;
|
||||||
|
|
||||||
|
onGestureEnd?.({ route });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTransitionStart = ({ closing }: { closing: boolean }) => {
|
const handleTransition = ({
|
||||||
if (active && closing) {
|
closing,
|
||||||
onPageChangeConfirm?.();
|
gesture,
|
||||||
|
}: {
|
||||||
|
closing: boolean;
|
||||||
|
gesture: boolean;
|
||||||
|
}) => {
|
||||||
|
const { route } = scene;
|
||||||
|
|
||||||
|
if (!gesture) {
|
||||||
|
onPageChangeConfirm?.(true);
|
||||||
|
} else if (active && closing) {
|
||||||
|
onPageChangeConfirm?.(false);
|
||||||
} else {
|
} else {
|
||||||
onPageChangeCancel?.();
|
onPageChangeCancel?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
onTransitionStart?.({ route: scene.route }, closing);
|
onTransitionStart?.({ route }, closing);
|
||||||
};
|
};
|
||||||
|
|
||||||
const insets = {
|
const insets = {
|
||||||
@@ -201,7 +217,7 @@ function CardContainer({
|
|||||||
overlay={cardOverlay}
|
overlay={cardOverlay}
|
||||||
overlayEnabled={cardOverlayEnabled}
|
overlayEnabled={cardOverlayEnabled}
|
||||||
shadowEnabled={cardShadowEnabled}
|
shadowEnabled={cardShadowEnabled}
|
||||||
onTransitionStart={handleTransitionStart}
|
onTransition={handleTransition}
|
||||||
onGestureBegin={handleGestureBegin}
|
onGestureBegin={handleGestureBegin}
|
||||||
onGestureCanceled={handleGestureCanceled}
|
onGestureCanceled={handleGestureCanceled}
|
||||||
onGestureEnd={handleGestureEnd}
|
onGestureEnd={handleGestureEnd}
|
||||||
@@ -216,7 +232,14 @@ function CardContainer({
|
|||||||
pageOverflowEnabled={headerMode === 'screen' && mode === 'card'}
|
pageOverflowEnabled={headerMode === 'screen' && mode === 'card'}
|
||||||
containerStyle={hasAbsoluteHeader ? { marginTop: headerHeight } : null}
|
containerStyle={hasAbsoluteHeader ? { marginTop: headerHeight } : null}
|
||||||
contentStyle={[{ backgroundColor: colors.background }, cardStyle]}
|
contentStyle={[{ backgroundColor: colors.background }, cardStyle]}
|
||||||
style={StyleSheet.absoluteFill}
|
style={[
|
||||||
|
{
|
||||||
|
// This is necessary to avoid unfocused larger pages increasing scroll area
|
||||||
|
// The issue can be seen on the web when a smaller screen is pushed over a larger one
|
||||||
|
overflow: active ? undefined : 'hidden',
|
||||||
|
},
|
||||||
|
StyleSheet.absoluteFill,
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.scene}>
|
<View style={styles.scene}>
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ type Props = {
|
|||||||
) => void;
|
) => void;
|
||||||
onTransitionEnd: (props: { route: Route<string> }, closing: boolean) => void;
|
onTransitionEnd: (props: { route: Route<string> }, closing: boolean) => void;
|
||||||
onPageChangeStart?: () => void;
|
onPageChangeStart?: () => void;
|
||||||
onPageChangeConfirm?: () => void;
|
onPageChangeConfirm?: (force: boolean) => void;
|
||||||
onPageChangeCancel?: () => void;
|
onPageChangeCancel?: () => void;
|
||||||
onGestureStart?: (props: { route: Route<string> }) => void;
|
onGestureStart?: (props: { route: Route<string> }) => void;
|
||||||
onGestureEnd?: (props: { route: Route<string> }) => void;
|
onGestureEnd?: (props: { route: Route<string> }) => void;
|
||||||
|
|||||||
Reference in New Issue
Block a user