Compare commits

..

19 Commits

Author SHA1 Message Date
satyajit.happy
3de9edbe72 chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.17
 - @react-navigation/compat@5.0.0-alpha.11
 - @react-navigation/core@5.0.0-alpha.19
 - @react-navigation/drawer@5.0.0-alpha.18
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.17
 - @react-navigation/material-top-tabs@5.0.0-alpha.14
 - @react-navigation/native-stack@5.0.0-alpha.6
 - @react-navigation/native@5.0.0-alpha.14
 - @react-navigation/routers@5.0.0-alpha.11
 - @react-navigation/stack@5.0.0-alpha.31
2019-10-30 23:51:33 +01:00
satyajit.happy
12d597fcc0 feat: add an 'unmountInactiveScreens' option 2019-10-30 23:50:33 +01:00
satyajit.happy
50dea65377 fix: support scroll to top in navigators nested in tab 2019-10-30 21:34:00 +01:00
Satyajit Sahoo
3d9db6ff25 refactor: add a type property to router and state (#146)
The `type` property denotes the type of the router. It can be used to verify compatibility of navigation state and the router when rehydrating state, making rehydration more resilient.

It can also help our utilities to detect the type of the navigator to properly implement some functionality. For example, the `useScrollToTop` hook can now know if it's not inside a tab navigator and needs to find the tab navigator in a parent.
2019-10-30 12:03:53 +01:00
Satyajit Sahoo
fb749ac064 fix: hide screen from screen reader when drawer is open (#147) 2019-10-30 11:59:55 +01:00
Satyajit Sahoo
58f7115298 fix: hide inactive pages from screen reader in tabs (#148) 2019-10-30 11:59:31 +01:00
Satyajit Sahoo
3a77107968 fix: drop isFirstRouteInParent method (#145)
The `isFirstRouteInParent` method was added to determine whether the back button should be shown in the header for stack navigator or not.
This was mainly due to the API of the old version of stack whose public API of header didn't have all required info to determine whether it should be shown.
It was probably a mistake to add it, because this method doesn't look at history and so pretty much useless for other navigators which aren't stack.

In the new stack, the header receives a `previous` prop and the `headerLeft` option receives a `canGoBack` prop which can be used for this purpose.
It's also possible to check if a route is the first by doing `navigation.dangerouslyGetState().routes[0].key === route.key`.

So it's time to drop this method.
2019-10-30 08:51:59 +01:00
satyajit.happy
aa40130266 chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.16
 - @react-navigation/compat@5.0.0-alpha.10
 - @react-navigation/core@5.0.0-alpha.18
 - @react-navigation/drawer@5.0.0-alpha.17
 - @react-navigation/example@5.0.0-alpha.17
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.16
 - @react-navigation/material-top-tabs@5.0.0-alpha.13
 - @react-navigation/native-stack@5.0.0-alpha.5
 - @react-navigation/routers@5.0.0-alpha.10
 - @react-navigation/stack@5.0.0-alpha.30
2019-10-29 21:20:18 +01:00
satyajit.happy
7635373366 fix: use index of first route when rehydrating tab state 2019-10-29 21:15:02 +01:00
satyajit.happy
941f4e2dec chore: update react-native-paper and screens 2019-10-29 02:42:37 +01:00
osdnk
876c3183e1 fix: make clearKeyboardTimeout private 2019-10-25 09:29:36 +02:00
satyajit.happy
1cc31bf900 chore: fix cocoa pods 2019-10-24 19:32:33 +02:00
satyajit.happy
8f16085808 fix: improve type annotation for screens 2019-10-24 18:56:26 +02:00
satyajit.happy
58fbfdf5c3 chore: remove log 2019-10-24 18:56:26 +02:00
osdnk
07bfc86327 fix: keyboard manager in stack for fast swipe 2019-10-24 18:50:16 +02:00
osdnk
e54d87c41c chore: publish
- @react-navigation/stack@5.0.0-alpha.29
2019-10-22 21:06:37 +02:00
osdnk
225e760a54 fix: conditions in gesture direction 2019-10-22 21:06:02 +02:00
satyajit.happy
f9cfbd01d8 chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.15
 - @react-navigation/example@5.0.0-alpha.16
2019-10-22 15:45:16 +02:00
satyajit.happy
3bf46e1ad2 refactor: don't pass orientation to label 2019-10-22 15:30:49 +02:00
54 changed files with 723 additions and 147 deletions

View File

@@ -3,6 +3,38 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.17](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.16...@react-navigation/bottom-tabs@5.0.0-alpha.17) (2019-10-30)
### Bug Fixes
* hide inactive pages from screen reader in tabs ([#148](https://github.com/react-navigation/navigation-ex/issues/148)) ([58f7115](https://github.com/react-navigation/navigation-ex/commit/58f7115))
### Features
* add an 'unmountInactiveScreens' option ([12d597f](https://github.com/react-navigation/navigation-ex/commit/12d597f))
# [5.0.0-alpha.16](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.15...@react-navigation/bottom-tabs@5.0.0-alpha.16) (2019-10-29)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [5.0.0-alpha.15](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.14...@react-navigation/bottom-tabs@5.0.0-alpha.15) (2019-10-22)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [5.0.0-alpha.14](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.13...@react-navigation/bottom-tabs@5.0.0-alpha.14) (2019-10-15)

View File

@@ -10,7 +10,7 @@
"android",
"tab"
],
"version": "5.0.0-alpha.14",
"version": "5.0.0-alpha.17",
"license": "MIT",
"repository": {
"type": "git",
@@ -33,7 +33,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.9"
"@react-navigation/routers": "^5.0.0-alpha.11"
},
"devDependencies": {
"@react-native-community/bob": "^0.7.0",

View File

@@ -71,11 +71,7 @@ export type BottomTabNavigationOptions = {
*/
tabBarLabel?:
| React.ReactNode
| ((props: {
focused: boolean;
color: string;
size: number;
}) => React.ReactNode);
| ((props: { focused: boolean; color: string }) => React.ReactNode);
/**
* React Element or a function that given { focused: boolean, color: string } returns a React.Node, to display in the tab bar.
@@ -127,6 +123,11 @@ export type BottomTabNavigationConfig = {
* Set it to `false` if you want to render all screens on initial render.
*/
lazy?: boolean;
/**
* Whether a screen should be unmounted when navigating away from it.
* Defaults to `false`.
*/
unmountInactiveScreens?: boolean;
/**
* Custom tab bar component.
*/
@@ -221,7 +222,6 @@ export type BottomTabBarProps = BottomTabBarOptions & {
| ((scene: {
focused: boolean;
color: string;
orientation: 'horizontal' | 'vertical';
}) => React.ReactNode | undefined)
| React.ReactNode;
getTestID: (props: { route: Route<string> }) => string | undefined;

View File

@@ -157,11 +157,7 @@ export default class TabBarBottom extends React.Component<Props, State> {
}
if (typeof label === 'function') {
return label({
focused,
color,
orientation: horizontal ? 'horizontal' : 'vertical',
});
return label({ focused, color });
}
return label;

View File

@@ -194,7 +194,7 @@ export default class BottomTabView extends React.Component<Props, State> {
};
render() {
const { state, descriptors, lazy } = this.props;
const { state, descriptors, lazy, unmountInactiveScreens } = this.props;
const { routes } = state;
const { loaded } = this.state;
@@ -203,6 +203,10 @@ export default class BottomTabView extends React.Component<Props, State> {
<View style={styles.container}>
<ScreenContainer style={styles.pages}>
{routes.map((route, index) => {
if (unmountInactiveScreens && index !== state.index) {
return null;
}
if (lazy && !loaded.includes(index)) {
// Don't render a screen if we've never navigated to it
return null;
@@ -216,7 +220,15 @@ export default class BottomTabView extends React.Component<Props, State> {
style={StyleSheet.absoluteFill}
isVisible={isFocused}
>
{descriptors[route.key].render()}
<View
accessibilityElementsHidden={!isFocused}
importantForAccessibility={
isFocused ? 'auto' : 'no-hide-descendants'
}
style={styles.content}
>
{descriptors[route.key].render()}
</View>
</ResourceSavingScene>
);
})}
@@ -236,4 +248,7 @@ const styles = StyleSheet.create({
pages: {
flex: 1,
},
content: {
flex: 1,
},
});

View File

@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.11](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/compat@5.0.0-alpha.10...@react-navigation/compat@5.0.0-alpha.11) (2019-10-30)
### Bug Fixes
* drop isFirstRouteInParent method ([#145](https://github.com/react-navigation/navigation-ex/issues/145)) ([3a77107](https://github.com/react-navigation/navigation-ex/commit/3a77107))
# [5.0.0-alpha.10](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/compat@5.0.0-alpha.9...@react-navigation/compat@5.0.0-alpha.10) (2019-10-29)
**Note:** Version bump only for package @react-navigation/compat
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/compat@5.0.0-alpha.8...@react-navigation/compat@5.0.0-alpha.9) (2019-10-22)
**Note:** Version bump only for package @react-navigation/compat

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/compat",
"description": "Compatibility layer to write navigator definitions in static configuration format",
"version": "5.0.0-alpha.9",
"version": "5.0.0-alpha.11",
"license": "MIT",
"repository": {
"type": "git",
@@ -24,7 +24,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.9"
"@react-navigation/routers": "^5.0.0-alpha.11"
},
"devDependencies": {
"@types/react": "^16.9.4",

View File

@@ -173,6 +173,12 @@ export default function createCompatNavigationProp<
return defaultValue;
},
isFirstRouteInParent(): boolean {
const { routes } = navigation.dangerouslyGetState();
// @ts-ignore
return routes[0].key === state.key;
},
dangerouslyGetParent() {
const parent = navigation.dangerouslyGetParent();

View File

@@ -25,6 +25,7 @@ export type CompatNavigationProp<
paramName: T,
defaultValue?: ParamList[RouteName][T]
): ParamList[RouteName][T];
isFirstRouteInParent(): boolean;
dangerouslyGetParent<
T = NavigationProp<ParamListBase> | undefined
>(): T extends NavigationProp<ParamListBase>

View File

@@ -3,6 +3,28 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.19](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.18...@react-navigation/core@5.0.0-alpha.19) (2019-10-30)
### Bug Fixes
* drop isFirstRouteInParent method ([#145](https://github.com/react-navigation/navigation-ex/issues/145)) ([3a77107](https://github.com/react-navigation/navigation-ex/commit/3a77107))
# [5.0.0-alpha.18](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.17...@react-navigation/core@5.0.0-alpha.18) (2019-10-29)
### Bug Fixes
* improve type annotation for screens ([8f16085](https://github.com/react-navigation/navigation-ex/commit/8f16085))
# [5.0.0-alpha.17](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.16...@react-navigation/core@5.0.0-alpha.17) (2019-10-22)
**Note:** Version bump only for package @react-navigation/core

View File

@@ -6,7 +6,7 @@
"react-native",
"react-navigation"
],
"version": "5.0.0-alpha.17",
"version": "5.0.0-alpha.19",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -90,8 +90,10 @@ export default function SceneView<
route={route}
>
{'component' in screen && screen.component !== undefined ? (
// @ts-ignore
<screen.component navigation={navigation} route={route} />
) : 'children' in screen && screen.children !== undefined ? (
// @ts-ignore
screen.children({ navigation, route })
) : null}
</StaticContainer>

View File

@@ -4,7 +4,8 @@ import * as CommonActions from '../CommonActions';
jest.mock('shortid', () => () => 'test');
const STATE = {
stale: false as false,
stale: false as const,
type: 'test',
key: 'root',
index: 1,
routes: [
@@ -23,6 +24,7 @@ it('replaces focused screen with REPLACE', () => {
expect(result).toEqual({
stale: false,
type: 'test',
key: 'root',
index: 1,
routes: [
@@ -42,6 +44,7 @@ it('replaces source screen with REPLACE', () => {
expect(result).toEqual({
stale: false,
type: 'test',
key: 'root',
index: 1,
routes: [
@@ -70,6 +73,7 @@ it('sets params for the focused screen with SET_PARAMS', () => {
expect(result).toEqual({
stale: false,
type: 'test',
key: 'root',
index: 1,
routes: [
@@ -89,6 +93,7 @@ it('sets params for the source screen with SET_PARAMS', () => {
expect(result).toEqual({
stale: false,
type: 'test',
key: 'root',
index: 1,
routes: [

View File

@@ -233,6 +233,7 @@ it('handle dispatching with ref', () => {
expect(onStateChange).toBeCalledTimes(1);
expect(onStateChange).lastCalledWith({
stale: false,
type: 'test',
index: 0,
key: '0',
routeNames: ['foo', 'foo2', 'bar', 'baz'],
@@ -242,6 +243,7 @@ it('handle dispatching with ref', () => {
name: 'baz',
state: {
stale: false,
type: 'test',
index: 0,
key: '1',
routeNames: ['qux', 'lex'],
@@ -367,10 +369,12 @@ it('handle getRootState', () => {
routeNames: ['qux', 'lex'],
routes: [{ key: 'qux', name: 'qux' }, { key: 'lex', name: 'lex' }],
stale: false,
type: 'test',
},
},
{ key: 'bar', name: 'bar' },
],
stale: false,
type: 'test',
});
});

View File

@@ -13,6 +13,8 @@ export const MockRouterKey = { current: 0 };
export default function MockRouter(options: DefaultRouterOptions) {
const router: Router<NavigationState, MockActions> = {
type: 'test',
getInitialState({ routeNames, routeParamList }) {
const index =
options.initialRouteName === undefined
@@ -21,6 +23,7 @@ export default function MockRouter(options: DefaultRouterOptions) {
return {
stale: false,
type: 'test',
key: String(MockRouterKey.current++),
index,
routeNames,
@@ -58,6 +61,7 @@ export default function MockRouter(options: DefaultRouterOptions) {
return {
stale: false,
type: 'test',
key: String(MockRouterKey.current++),
index:
typeof state.index === 'number' && state.index < routes.length

View File

@@ -52,6 +52,7 @@ it('initializes state for a navigator on navigation', () => {
expect(onStateChange).toBeCalledTimes(1);
expect(onStateChange).toBeCalledWith({
stale: false,
type: 'test',
index: 0,
key: '0',
routeNames: ['foo', 'bar', 'baz'],
@@ -106,6 +107,66 @@ it('rehydrates state for a navigator on navigation', () => {
routeNames: ['foo', 'bar'],
routes: [{ key: 'foo', name: 'foo' }, { key: 'bar', name: 'bar' }],
stale: false,
type: 'test',
});
});
it("doesn't rehydrate state if the type of state didn't match router", () => {
const TestNavigator = (props: any) => {
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
return descriptors[state.routes[state.index].key].render();
};
const FooScreen = (props: any) => {
React.useEffect(() => {
props.navigation.dispatch({ type: 'UPDATE' });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return null;
};
const initialState = {
index: 1,
type: 'something-else',
routes: [{ key: 'foo', name: 'foo' }, { key: 'bar', name: 'bar' }],
};
const onStateChange = jest.fn();
const element = (
<NavigationContainer
initialState={initialState}
onStateChange={onStateChange}
>
<TestNavigator initialRouteName="foo">
<Screen
name="foo"
component={FooScreen}
initialParams={{ answer: 42 }}
/>
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
);
render(element).update(element);
expect(onStateChange).lastCalledWith({
index: 0,
key: '0',
routeNames: ['foo', 'bar'],
routes: [
{
key: 'foo',
name: 'foo',
params: { answer: 42 },
},
{ key: 'bar', name: 'bar' },
],
stale: false,
type: 'test',
});
});
@@ -144,6 +205,7 @@ it('initializes state for nested screens in React.Fragment', () => {
expect(onStateChange).toBeCalledTimes(1);
expect(onStateChange).toBeCalledWith({
stale: false,
type: 'test',
index: 0,
key: '0',
routeNames: ['foo', 'bar', 'baz'],
@@ -194,6 +256,7 @@ it('initializes state for nested navigator on navigation', () => {
expect(onStateChange).toBeCalledTimes(1);
expect(onStateChange).toBeCalledWith({
stale: false,
type: 'test',
index: 2,
key: '0',
routeNames: ['foo', 'bar', 'baz'],
@@ -205,6 +268,7 @@ it('initializes state for nested navigator on navigation', () => {
name: 'baz',
state: {
stale: false,
type: 'test',
index: 0,
key: '1',
routeNames: ['qux'],
@@ -309,6 +373,7 @@ it('cleans up state when the navigator unmounts', () => {
expect(onStateChange).toBeCalledTimes(1);
expect(onStateChange).lastCalledWith({
stale: false,
type: 'test',
index: 0,
key: '0',
routeNames: ['foo', 'bar'],
@@ -361,6 +426,7 @@ it('allows state updates by dispatching a function returning an action', () => {
expect(onStateChange).toBeCalledTimes(1);
expect(onStateChange).toBeCalledWith({
stale: false,
type: 'test',
index: 1,
key: '0',
routeNames: ['foo', 'bar'],
@@ -399,6 +465,7 @@ it('updates route params with setParams', () => {
expect(onStateChange).toBeCalledTimes(1);
expect(onStateChange).lastCalledWith({
stale: false,
type: 'test',
index: 0,
key: '0',
routeNames: ['foo', 'bar'],
@@ -413,6 +480,7 @@ it('updates route params with setParams', () => {
expect(onStateChange).toBeCalledTimes(2);
expect(onStateChange).lastCalledWith({
stale: false,
type: 'test',
index: 0,
key: '0',
routeNames: ['foo', 'bar'],
@@ -470,6 +538,7 @@ it('updates route params with setParams applied to parent', () => {
{ key: 'bar', name: 'bar' },
],
stale: false,
type: 'test',
});
act(() => setParams({ age: 25 }));
@@ -484,6 +553,7 @@ it('updates route params with setParams applied to parent', () => {
{ key: 'bar', name: 'bar' },
],
stale: false,
type: 'test',
});
});
@@ -516,6 +586,7 @@ it('handles change in route names', () => {
expect(onStateChange).toBeCalledWith({
stale: false,
type: 'test',
index: 0,
key: '0',
routeNames: ['foo', 'baz', 'qux'],
@@ -628,6 +699,7 @@ it('gives access to internal state', () => {
routeNames: ['bar'],
routes: [{ key: 'bar', name: 'bar' }],
stale: false,
type: 'test',
});
});

View File

@@ -216,6 +216,7 @@ it('fires blur event when a route is removed with a delay', async () => {
return {
stale: false,
type: 'test',
key: 'stack',
index: 0,
routeNames,

View File

@@ -76,6 +76,7 @@ it("lets parent handle the action if child didn't", () => {
expect(onStateChange).toBeCalledTimes(1);
expect(onStateChange).lastCalledWith({
stale: false,
type: 'test',
index: 2,
key: '0',
routeNames: ['foo', 'bar', 'baz'],
@@ -191,6 +192,7 @@ it("lets children handle the action if parent didn't", () => {
expect(onStateChange).toBeCalledTimes(1);
expect(onStateChange).lastCalledWith({
stale: false,
type: 'test',
index: 0,
key: '0',
routeNames: ['foo', 'bar', 'baz'],
@@ -200,6 +202,7 @@ it("lets children handle the action if parent didn't", () => {
name: 'baz',
state: {
stale: false,
type: 'test',
index: 0,
key: '1',
routeNames: ['qux', 'lex'],

View File

@@ -23,6 +23,12 @@ export type NavigationState = {
routes: Array<
Route<string> & { state?: NavigationState | PartialState<NavigationState> }
>;
/**
* Custom type for the state, whether it's for tab, stack, drawer etc.
* During rehydration, the state will be discarded if type doesn't match with router type.
* It can also be used to detect the type of the navigator we're dealing with.
*/
type: string;
/**
* Whether the navigation state has been rehydrated.
*/
@@ -36,9 +42,10 @@ export type InitialState = Partial<
};
export type PartialState<State extends NavigationState> = Partial<
Omit<State, 'stale' | 'key' | 'routes' | 'routeNames'>
Omit<State, 'stale' | 'type' | 'key' | 'routes' | 'routeNames'>
> & {
stale?: true;
type?: string;
routes: Array<
Omit<Route<string>, 'key'> & { key?: string; state?: InitialState }
>;
@@ -115,6 +122,12 @@ export type Router<
State extends NavigationState,
Action extends NavigationAction
> = {
/**
* Type of the router. Should match the `type` property in state.
* If the type doesn't match, the state will be discarded during rehydration.
*/
type: State['type'];
/**
* Initialize the navigation state.
*
@@ -394,13 +407,6 @@ export type NavigationProp<
*/
setOptions(options: Partial<ScreenOptions>): void;
/**
* Check if the screen is the first route in the navigator.
* This method returns `true` if the index of the route is `0`, `false` otherwise.
* It can be useful to decide whether to display a back button in a stack.
*/
isFirstRouteInParent(): boolean;
/**
* Returns the parent navigator, if any. Reason why the function is called
* dangerouslyGetParent is to warn developers against overusing it to eg. get parent
@@ -521,13 +527,19 @@ export type RouteConfig<
/**
* React component to render for this screen.
*/
component: React.ComponentType<any>;
component: React.ComponentType<{
route: RouteProp<ParamList, RouteName>;
navigation: any;
}>;
}
| {
/**
* Render callback to render content of this screen.
*/
children: (props: any) => React.ReactNode;
children: (props: {
route: RouteProp<ParamList, RouteName>;
navigation: any;
}) => React.ReactNode;
});
export type NavigationContainerRef =

View File

@@ -166,6 +166,17 @@ export default function useNavigationBuilder<
);
}
const isStateValid = React.useCallback(
state => state.type === undefined || state.type === router.type,
[router.type]
);
const isStateInitialized = React.useCallback(
state =>
state !== undefined && state.stale === false && isStateValid(state),
[isStateValid]
);
const {
state: currentState,
getState: getCurrentState,
@@ -188,7 +199,7 @@ export default function useNavigationBuilder<
// Otherwise assume that the state was provided as initial state
// So we need to rehydrate it to make it usable
initializedStateRef.current =
currentState === undefined
currentState === undefined || !isStateValid(currentState)
? router.getInitialState({
routeNames,
routeParamList,
@@ -207,9 +218,9 @@ export default function useNavigationBuilder<
// If the state isn't initialized, or stale, use the state we initialized instead
// The state won't update until there's a change needed in the state we have initalized locally
// So it'll be `undefined` or stale untill the first navigation event happens
currentState === undefined || currentState.stale !== false
? (initializedStateRef.current as State)
: (currentState as State);
isStateInitialized(currentState)
? (currentState as State)
: (initializedStateRef.current as State);
let nextState: State = state;
@@ -271,10 +282,10 @@ export default function useNavigationBuilder<
const getState = React.useCallback((): State => {
const currentState = getCurrentState();
return currentState === undefined || currentState.stale !== false
? (initializedStateRef.current as State)
: (currentState as State);
}, [getCurrentState]);
return isStateInitialized(currentState)
? (currentState as State)
: (initializedStateRef.current as State);
}, [getCurrentState, isStateInitialized]);
const emitter = useEventEmitter();

View File

@@ -66,11 +66,9 @@ export default function useNavigationCache<
cache.current = state.routes.reduce<NavigationCache<State, ScreenOptions>>(
(acc, route, index) => {
const previous = cache.current[route.key];
const isFirst = route.key === state.routes[0].key;
if (previous && previous.isFirstRouteInParent() === isFirst) {
// If a cached navigation object already exists and has same `isFirstRouteInParent`, reuse it
// This method could return different result if the index of the route changes somehow
if (previous) {
// If a cached navigation object already exists, reuse it
acc[route.key] = previous;
} else {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -121,7 +119,6 @@ export default function useNavigationCache<
// This makes sure that we return the focus state in the whole tree, not just this navigator
return navigation ? navigation.isFocused() : true;
},
isFirstRouteInParent: () => isFirst,
};
}

View File

@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.18](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.17...@react-navigation/drawer@5.0.0-alpha.18) (2019-10-30)
### Bug Fixes
* hide screen from screen reader when drawer is open ([#147](https://github.com/react-navigation/navigation-ex/issues/147)) ([fb749ac](https://github.com/react-navigation/navigation-ex/commit/fb749ac))
### Features
* add an 'unmountInactiveScreens' option ([12d597f](https://github.com/react-navigation/navigation-ex/commit/12d597f))
# [5.0.0-alpha.17](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.16...@react-navigation/drawer@5.0.0-alpha.17) (2019-10-29)
**Note:** Version bump only for package @react-navigation/drawer
# [5.0.0-alpha.16](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.15...@react-navigation/drawer@5.0.0-alpha.16) (2019-10-22)

View File

@@ -11,7 +11,7 @@
"material",
"drawer"
],
"version": "5.0.0-alpha.16",
"version": "5.0.0-alpha.18",
"license": "MIT",
"repository": {
"type": "git",
@@ -34,7 +34,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.9"
"@react-navigation/routers": "^5.0.0-alpha.11"
},
"devDependencies": {
"@react-native-community/bob": "^0.7.0",
@@ -46,7 +46,7 @@
"react-native-gesture-handler": "^1.3.0",
"react-native-reanimated": "^1.3.0",
"react-native-safe-area-context": "^0.3.6",
"react-native-screens": "^2.0.0-alpha.5",
"react-native-screens": "^2.0.0-alpha.6",
"typescript": "^3.6.3"
},
"peerDependencies": {

View File

@@ -67,7 +67,7 @@ export type DrawerNavigationConfig<T = DrawerContentOptions> = {
* Whether a screen should be unmounted when navigating away from it.
* Defaults to `false`.
*/
unmountInactiveRoutes?: boolean;
unmountInactiveScreens?: boolean;
/**
* Custom component used to render as the content of the drawer, for example, navigation items.
* Defaults to `DrawerItems`.

View File

@@ -8,6 +8,7 @@ import {
Keyboard,
StatusBar,
StyleProp,
View,
} from 'react-native';
import {
PanGestureHandler,
@@ -544,7 +545,13 @@ export default class DrawerView extends React.PureComponent<Props> {
sceneContainerStyle as any,
]}
>
{renderSceneContent({ progress: this.progress })}
<View
accessibilityElementsHidden={open}
importantForAccessibility={open ? 'no-hide-descendants' : 'auto'}
style={styles.content}
>
{renderSceneContent({ progress: this.progress })}
</View>
<TapGestureHandler onHandlerStateChange={this.handleTapStateChange}>
<Animated.View
style={[

View File

@@ -152,43 +152,37 @@ export default class DrawerView extends React.PureComponent<Props, State> {
};
private renderContent = () => {
let { lazy, state, descriptors, unmountInactiveRoutes } = this.props;
let { lazy, state, descriptors, unmountInactiveScreens } = this.props;
const { loaded } = this.state;
if (unmountInactiveRoutes) {
const activeKey = state.routes[state.index].key;
const descriptor = descriptors[activeKey];
return (
<ScreenContainer style={styles.content}>
{state.routes.map((route, index) => {
if (unmountInactiveScreens && index !== state.index) {
return null;
}
return descriptor.render();
} else {
return (
<ScreenContainer style={styles.content}>
{state.routes.map((route, index) => {
if (lazy && !loaded.includes(index)) {
// Don't render a screen if we've never navigated to it
return null;
}
if (lazy && !loaded.includes(index)) {
// Don't render a screen if we've never navigated to it
return null;
}
const isFocused = state.index === index;
const descriptor = descriptors[route.key];
const isFocused = state.index === index;
const descriptor = descriptors[route.key];
return (
<ResourceSavingScene
key={route.key}
style={[
StyleSheet.absoluteFill,
{ opacity: isFocused ? 1 : 0 },
]}
isVisible={isFocused}
>
{descriptor.render()}
</ResourceSavingScene>
);
})}
</ScreenContainer>
);
}
return (
<ResourceSavingScene
key={route.key}
style={[StyleSheet.absoluteFill, { opacity: isFocused ? 1 : 0 }]}
isVisible={isFocused}
>
{descriptor.render()}
</ResourceSavingScene>
);
})}
</ScreenContainer>
);
};
private setDrawerGestureRef = (ref: PanGestureHandler | null) => {

View File

@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.17](https://github.com/satya164/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.16...@react-navigation/example@5.0.0-alpha.17) (2019-10-29)
### Bug Fixes
* improve type annotation for screens ([8f16085](https://github.com/satya164/navigation-ex/commit/8f16085))
# [5.0.0-alpha.16](https://github.com/satya164/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.15...@react-navigation/example@5.0.0-alpha.16) (2019-10-22)
**Note:** Version bump only for package @react-navigation/example
# [5.0.0-alpha.15](https://github.com/satya164/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.14...@react-navigation/example@5.0.0-alpha.15) (2019-10-22)
**Note:** Version bump only for package @react-navigation/example

View File

@@ -93,7 +93,7 @@ PODS:
- React
- RNReanimated (1.2.0):
- React
- RNScreens (2.0.0-alpha.4):
- RNScreens (2.0.0-alpha.6):
- React
- UMBarCodeScannerInterface (4.0.0)
- UMCameraInterface (4.0.0)
@@ -159,7 +159,7 @@ DEPENDENCIES:
- yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
https://github.com/cocoapods/specs.git:
trunk:
- boost-for-react-native
EXTERNAL SOURCES:
@@ -267,7 +267,7 @@ SPEC CHECKSUMS:
react-native-safe-area-context: e380a6f783ccaec848e2f3cc8eb205a62362950d
RNGestureHandler: 5329a942fce3d41c68b84c2c2276ce06a696d8b0
RNReanimated: 1b52415c4302f198cb581282a0166690bad62c43
RNScreens: 84be1a2369a580beb2fea0755cc62ef16b83fffe
RNScreens: 73691421e207a57b85af0fea931e620b05a35e89
UMBarCodeScannerInterface: d5a6fdc98ed6241225b0a8432a7f4e2b397668bc
UMCameraInterface: 68870a3197fee85bd5afca5609ba4a5b7257d19d
UMConstantsInterface: d25b8e8887ca7aaf568c06caf08f4d40734ee4ef
@@ -284,4 +284,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 1276a2dd000c142ccc03272023bb8a6b2d5b9933
COCOAPODS: 1.7.5
COCOAPODS: 1.8.3

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/example",
"description": "Demo app to showcase various functionality of React Navigation",
"version": "5.0.0-alpha.15",
"version": "5.0.0-alpha.17",
"private": true,
"workspaces": {
"nohoist": [
@@ -27,10 +27,10 @@
"react-dom": "~16.8.3",
"react-native": "~0.59.10",
"react-native-gesture-handler": "~1.3.0",
"react-native-paper": "^3.0.0-alpha.7",
"react-native-paper": "^3.1.1",
"react-native-reanimated": "~1.2.0",
"react-native-safe-area-context": "~0.3.6",
"react-native-screens": "^2.0.0-alpha.5",
"react-native-screens": "^2.0.0-alpha.6",
"react-native-tab-view": "2.10.0",
"react-native-unimodules": "^0.7.0-rc.1",
"react-native-web": "^0.11.7",

View File

@@ -41,15 +41,13 @@ export default function BottomTabsScreen() {
tabBarButtonComponent: TouchableBounce,
}}
>
{props => (
<SimpleStackScreen {...props} options={{ headerMode: 'none' }} />
)}
{props => <SimpleStackScreen {...props} headerMode="none" />}
</BottomTabs.Screen>
<BottomTabs.Screen
name="chat"
component={Chat}
options={{
title: 'Chat',
tabBarLabel: 'Chat',
tabBarIcon: getTabBarIcon('message-reply'),
tabBarButtonComponent: TouchableBounce,
}}

View File

@@ -28,9 +28,7 @@ export default function MaterialBottomTabsScreen() {
tabBarColor: '#C9E7F8',
}}
>
{props => (
<SimpleStackScreen {...props} options={{ headerMode: 'none' }} />
)}
{props => <SimpleStackScreen {...props} headerMode="none" />}
</MaterialBottomTabs.Screen>
<MaterialBottomTabs.Screen
name="chat"

View File

@@ -5,7 +5,6 @@ import { RouteProp, ParamListBase } from '@react-navigation/core';
import {
createStackNavigator,
StackNavigationProp,
StackNavigationOptions,
} from '@react-navigation/stack';
import Article from '../Shared/Article';
import Albums from '../Shared/Albums';
@@ -77,18 +76,17 @@ const AlbumsScreen = ({
const SimpleStack = createStackNavigator<SimpleStackParams>();
type Props = {
options?: StackNavigationOptions;
type Props = Partial<React.ComponentProps<typeof SimpleStack.Navigator>> & {
navigation: StackNavigationProp<ParamListBase>;
};
export default function SimpleStackScreen({ navigation, options }: Props) {
export default function SimpleStackScreen({ navigation, ...rest }: Props) {
navigation.setOptions({
headerShown: false,
});
return (
<SimpleStack.Navigator {...options}>
<SimpleStack.Navigator {...rest}>
<SimpleStack.Screen
name="article"
component={ArticleScreen}

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.17](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.16...@react-navigation/material-bottom-tabs@5.0.0-alpha.17) (2019-10-30)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
# [5.0.0-alpha.16](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.15...@react-navigation/material-bottom-tabs@5.0.0-alpha.16) (2019-10-29)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
# [5.0.0-alpha.15](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.14...@react-navigation/material-bottom-tabs@5.0.0-alpha.15) (2019-10-22)

View File

@@ -11,7 +11,7 @@
"material",
"tab"
],
"version": "5.0.0-alpha.15",
"version": "5.0.0-alpha.17",
"license": "MIT",
"repository": {
"type": "git",
@@ -34,7 +34,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.9"
"@react-navigation/routers": "^5.0.0-alpha.11"
},
"devDependencies": {
"@react-native-community/bob": "^0.7.0",
@@ -44,7 +44,7 @@
"del-cli": "^3.0.0",
"react": "~16.8.3",
"react-native": "~0.59.10",
"react-native-paper": "^3.0.0-alpha.7",
"react-native-paper": "^3.1.1",
"react-native-vector-icons": "^6.6.0",
"typescript": "^3.6.3"
},
@@ -52,7 +52,7 @@
"@react-navigation/core": "^5.0.0-alpha.0",
"react": "*",
"react-native": "*",
"react-native-paper": "^3.0.0-alpha.0",
"react-native-paper": "^3.0.0",
"react-native-vector-icons": "^6.0.0"
},
"@react-native-community/bob": {

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.14](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-top-tabs@5.0.0-alpha.13...@react-navigation/material-top-tabs@5.0.0-alpha.14) (2019-10-30)
**Note:** Version bump only for package @react-navigation/material-top-tabs
# [5.0.0-alpha.13](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-top-tabs@5.0.0-alpha.12...@react-navigation/material-top-tabs@5.0.0-alpha.13) (2019-10-29)
**Note:** Version bump only for package @react-navigation/material-top-tabs
# [5.0.0-alpha.12](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-top-tabs@5.0.0-alpha.11...@react-navigation/material-top-tabs@5.0.0-alpha.12) (2019-10-15)

View File

@@ -11,7 +11,7 @@
"material",
"tab"
],
"version": "5.0.0-alpha.12",
"version": "5.0.0-alpha.14",
"license": "MIT",
"repository": {
"type": "git",
@@ -34,7 +34,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.9"
"@react-navigation/routers": "^5.0.0-alpha.11"
},
"devDependencies": {
"@react-native-community/bob": "^0.7.0",

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.6](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.5...@react-navigation/native-stack@5.0.0-alpha.6) (2019-10-30)
**Note:** Version bump only for package @react-navigation/native-stack
# [5.0.0-alpha.5](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.4...@react-navigation/native-stack@5.0.0-alpha.5) (2019-10-29)
**Note:** Version bump only for package @react-navigation/native-stack
# [5.0.0-alpha.4](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.3...@react-navigation/native-stack@5.0.0-alpha.4) (2019-10-22)

View File

@@ -6,7 +6,7 @@
"react-native",
"react-navigation"
],
"version": "5.0.0-alpha.4",
"version": "5.0.0-alpha.6",
"license": "MIT",
"repository": {
"type": "git",
@@ -29,19 +29,19 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.9"
"@react-navigation/routers": "^5.0.0-alpha.11"
},
"devDependencies": {
"@react-native-community/bob": "^0.7.0",
"del-cli": "^2.0.0",
"react-native-screens": "^2.0.0-alpha.5",
"react-native-screens": "^2.0.0-alpha.6",
"typescript": "^3.5.3"
},
"peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0",
"react": "*",
"react-native": "*",
"react-native-screens": "^2.0.0-alpha.5"
"react-native-screens": "^2.0.0-alpha.6"
},
"@react-native-community/bob": {
"source": "src",

View File

@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.14](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native@5.0.0-alpha.13...@react-navigation/native@5.0.0-alpha.14) (2019-10-30)
### Bug Fixes
* support scroll to top in navigators nested in tab ([50dea65](https://github.com/react-navigation/navigation-ex/commit/50dea65))
# [5.0.0-alpha.13](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native@5.0.0-alpha.12...@react-navigation/native@5.0.0-alpha.13) (2019-10-22)
**Note:** Version bump only for package @react-navigation/native

View File

@@ -7,7 +7,7 @@
"ios",
"android"
],
"version": "5.0.0-alpha.13",
"version": "5.0.0-alpha.14",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { useNavigation, EventArg } from '@react-navigation/core';
import { useNavigation, useRoute, EventArg } from '@react-navigation/core';
type ScrollOptions = { y?: number; animated?: boolean };
@@ -36,22 +36,42 @@ export default function useScrollToTop(
ref: React.RefObject<ScrollableWrapper>
) {
const navigation = useNavigation();
const route = useRoute();
React.useEffect(
() =>
// @ts-ignore
React.useEffect(() => {
let current = navigation;
// The screen might be inside another navigator such as stack nested in tabs
// We need to find the closest tab navigator and add the listener there
while (current && current.dangerouslyGetState().type !== 'tab') {
current = current.dangerouslyGetParent();
}
if (!current) {
return;
}
const unsubscribe = current.addListener(
// We don't wanna import tab types here to avoid extra deps
// in addition, there are multiple tab implementations
navigation.addListener('tabPress', (e: EventArg<'tabPress'>) => {
// @ts-ignore
'tabPress',
(e: EventArg<'tabPress'>) => {
// We should scroll to top only when the screen is focused
const isFocused = navigation.isFocused();
// In a nested stack navigator, tab press resets the stack to first screen
// So we should scroll to top only when we are on first screen
const isFirst =
navigation === current ||
navigation.dangerouslyGetState().routes[0].key === route.key;
// Run the operation in the next frame so we're sure all listeners have been run
// This is necessary to know if preventDefault() has been called
requestAnimationFrame(() => {
const scrollable = getScrollableNode(ref);
if (isFocused && !e.defaultPrevented && scrollable) {
// When user taps on already focused tab, scroll to top
if (isFocused && isFirst && scrollable && !e.defaultPrevented) {
if ('scrollToTop' in scrollable) {
scrollable.scrollToTop();
} else if ('scrollTo' in scrollable) {
@@ -63,7 +83,9 @@ export default function useScrollToTop(
}
}
});
}),
[navigation, ref]
);
}
);
return unsubscribe;
}, [navigation, ref, route.key]);
}

View File

@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.11](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.10...@react-navigation/routers@5.0.0-alpha.11) (2019-10-30)
**Note:** Version bump only for package @react-navigation/routers
# [5.0.0-alpha.10](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.9...@react-navigation/routers@5.0.0-alpha.10) (2019-10-29)
### Bug Fixes
* use index of first route when rehydrating tab state ([7635373](https://github.com/react-navigation/navigation-ex/commit/7635373))
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.8...@react-navigation/routers@5.0.0-alpha.9) (2019-10-03)
**Note:** Version bump only for package @react-navigation/routers

View File

@@ -26,6 +26,7 @@ it('gets initial state from route names and params with initialRouteName', () =>
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'drawer',
});
});
@@ -52,6 +53,7 @@ it('gets initial state from route names and params without initialRouteName', ()
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'drawer',
});
});
@@ -85,6 +87,29 @@ it('gets rehydrated state from partial state', () => {
{ key: 'qux-1', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'drawer',
});
expect(
router.getRehydratedState(
{
routes: [{ key: 'baz-0', name: 'baz' }],
},
options
)
).toEqual({
index: 1,
key: 'drawer-test',
isDrawerOpen: false,
routeKeyHistory: [],
routeNames: ['bar', 'baz', 'qux'],
routes: [
{ key: 'bar-test', name: 'bar' },
{ key: 'baz-0', name: 'baz', params: { answer: 42 } },
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'drawer',
});
expect(
@@ -111,6 +136,7 @@ it('gets rehydrated state from partial state', () => {
{ key: 'qux-2', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'drawer',
});
expect(
@@ -122,7 +148,7 @@ it('gets rehydrated state from partial state', () => {
options
)
).toEqual({
index: 0,
index: 2,
key: 'drawer-test',
isDrawerOpen: false,
routeKeyHistory: [],
@@ -133,6 +159,7 @@ it('gets rehydrated state from partial state', () => {
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'drawer',
});
expect(
@@ -157,6 +184,7 @@ it('gets rehydrated state from partial state', () => {
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'drawer',
});
});
@@ -175,6 +203,7 @@ it("doesn't rehydrate state if it's not stale", () => {
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false as const,
type: 'drawer' as const,
};
expect(
@@ -192,6 +221,7 @@ it('handles navigate action', () => {
router.getStateForAction(
{
stale: false,
type: 'drawer',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -203,6 +233,7 @@ it('handles navigate action', () => {
)
).toEqual({
stale: false,
type: 'drawer',
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
@@ -222,6 +253,7 @@ it('handles navigate action with open drawer', () => {
router.getStateForAction(
{
stale: false,
type: 'drawer',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -233,6 +265,7 @@ it('handles navigate action with open drawer', () => {
)
).toEqual({
stale: false,
type: 'drawer',
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
@@ -252,6 +285,7 @@ it('handles open drawer action', () => {
router.getStateForAction(
{
stale: false,
type: 'drawer',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -263,6 +297,7 @@ it('handles open drawer action', () => {
)
).toEqual({
stale: false,
type: 'drawer',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -273,6 +308,7 @@ it('handles open drawer action', () => {
const state = {
stale: false as const,
type: 'drawer' as const,
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -293,6 +329,7 @@ it('handles close drawer action', () => {
router.getStateForAction(
{
stale: false,
type: 'drawer',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -304,6 +341,7 @@ it('handles close drawer action', () => {
)
).toEqual({
stale: false,
type: 'drawer',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -314,6 +352,7 @@ it('handles close drawer action', () => {
const state = {
stale: false as const,
type: 'drawer' as const,
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -334,6 +373,7 @@ it('handles toggle drawer action', () => {
router.getStateForAction(
{
stale: false,
type: 'drawer',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -345,6 +385,7 @@ it('handles toggle drawer action', () => {
)
).toEqual({
stale: false,
type: 'drawer',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -357,6 +398,7 @@ it('handles toggle drawer action', () => {
router.getStateForAction(
{
stale: false,
type: 'drawer',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -368,6 +410,7 @@ it('handles toggle drawer action', () => {
)
).toEqual({
stale: false,
type: 'drawer',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -392,6 +435,7 @@ it('updates route key history on focus change', () => {
{ key: 'qux-0', name: 'qux', params: { name: 'Jane' } },
],
stale: false as const,
type: 'drawer' as const,
};
expect(router.getStateForRouteFocus(state, 'bar-0').routeKeyHistory).toEqual(
@@ -420,6 +464,7 @@ it('closes drawer on focus change', () => {
{ key: 'qux-0', name: 'qux' },
],
stale: false,
type: 'drawer',
},
'baz-0'
)
@@ -435,6 +480,7 @@ it('closes drawer on focus change', () => {
{ key: 'qux-0', name: 'qux' },
],
stale: false,
type: 'drawer',
});
expect(
@@ -451,6 +497,7 @@ it('closes drawer on focus change', () => {
{ key: 'qux-0', name: 'qux' },
],
stale: false,
type: 'drawer',
},
'baz-0'
)
@@ -466,5 +513,6 @@ it('closes drawer on focus change', () => {
{ key: 'qux-0', name: 'qux' },
],
stale: false,
type: 'drawer',
});
});

View File

@@ -20,6 +20,7 @@ it('gets initial state from route names and params with initialRouteName', () =>
routeNames: ['bar', 'baz', 'qux'],
routes: [{ key: 'baz-test', name: 'baz', params: { answer: 42 } }],
stale: false,
type: 'stack',
});
});
@@ -40,6 +41,7 @@ it('gets initial state from route names and params without initialRouteName', ()
routeNames: ['bar', 'baz', 'qux'],
routes: [{ key: 'bar-test', name: 'bar' }],
stale: false,
type: 'stack',
});
});
@@ -70,6 +72,7 @@ it('gets rehydrated state from partial state', () => {
{ key: 'qux-1', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'stack',
});
expect(
@@ -94,6 +97,7 @@ it('gets rehydrated state from partial state', () => {
{ key: 'qux-2', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'stack',
});
expect(
@@ -110,6 +114,7 @@ it('gets rehydrated state from partial state', () => {
routeNames: ['bar', 'baz', 'qux'],
routes: [{ key: 'bar-test', name: 'bar' }],
stale: false,
type: 'stack',
});
});
@@ -122,6 +127,7 @@ it("doesn't rehydrate state if it's not stale", () => {
routeNames: ['bar', 'baz', 'qux'],
routes: [{ key: 'bar-test', name: 'bar' }],
stale: false as const,
type: 'stack' as const,
};
expect(
@@ -147,6 +153,7 @@ it('gets state on route names change', () => {
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'stack',
},
{
routeNames: ['qux', 'baz', 'foo', 'fiz'],
@@ -165,6 +172,7 @@ it('gets state on route names change', () => {
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'stack',
});
expect(
@@ -178,6 +186,7 @@ it('gets state on route names change', () => {
{ key: 'bar-test', name: 'bar' },
],
stale: false,
type: 'stack',
},
{
routeNames: ['baz', 'qux'],
@@ -192,6 +201,7 @@ it('gets state on route names change', () => {
routeNames: ['baz', 'qux'],
routes: [{ key: 'baz-test', name: 'baz', params: { name: 'John' } }],
stale: false,
type: 'stack',
});
});
@@ -209,6 +219,7 @@ it('gets state on route names change with initialRouteName', () => {
{ key: 'bar-test', name: 'bar' },
],
stale: false,
type: 'stack',
},
{
routeNames: ['baz', 'qux'],
@@ -223,6 +234,7 @@ it('gets state on route names change with initialRouteName', () => {
routeNames: ['baz', 'qux'],
routes: [{ key: 'qux-test', name: 'qux' }],
stale: false,
type: 'stack',
});
});
@@ -233,6 +245,7 @@ it('handles navigate action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
@@ -242,6 +255,7 @@ it('handles navigate action', () => {
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 2,
routeNames: ['baz', 'bar', 'qux'],
@@ -260,6 +274,7 @@ it('handles navigate action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
@@ -269,6 +284,7 @@ it('handles navigate action', () => {
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 0,
routeNames: ['baz', 'bar', 'qux'],
@@ -279,6 +295,7 @@ it('handles navigate action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
@@ -291,6 +308,7 @@ it('handles navigate action', () => {
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
@@ -304,6 +322,7 @@ it('handles navigate action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
@@ -317,6 +336,7 @@ it('handles navigate action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
@@ -330,6 +350,7 @@ it('handles navigate action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
@@ -342,6 +363,7 @@ it('handles navigate action', () => {
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 0,
routeNames: ['baz', 'bar', 'qux'],
@@ -352,6 +374,7 @@ it('handles navigate action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
@@ -361,6 +384,7 @@ it('handles navigate action', () => {
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 2,
routeNames: ['baz', 'bar', 'qux'],
@@ -379,6 +403,7 @@ it('handles go back action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
@@ -388,6 +413,7 @@ it('handles go back action', () => {
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 0,
routeNames: ['baz', 'bar', 'qux'],
@@ -398,6 +424,7 @@ it('handles go back action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 0,
routeNames: ['baz', 'bar', 'qux'],
@@ -415,6 +442,7 @@ it('handles pop action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 2,
routeNames: ['baz', 'bar', 'qux'],
@@ -428,6 +456,7 @@ it('handles pop action', () => {
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
@@ -438,6 +467,7 @@ it('handles pop action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 2,
routeNames: ['baz', 'bar', 'qux'],
@@ -451,6 +481,7 @@ it('handles pop action', () => {
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 0,
routeNames: ['baz', 'bar', 'qux'],
@@ -461,6 +492,7 @@ it('handles pop action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 2,
routeNames: ['baz', 'bar', 'qux'],
@@ -478,6 +510,7 @@ it('handles pop action', () => {
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 0,
routeNames: ['baz', 'bar', 'qux'],
@@ -488,6 +521,7 @@ it('handles pop action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 0,
routeNames: ['baz', 'bar', 'qux'],
@@ -505,6 +539,7 @@ it('handles pop to top action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 2,
routeNames: ['baz', 'bar', 'qux'],
@@ -518,6 +553,7 @@ it('handles pop to top action', () => {
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 0,
routeNames: ['baz', 'bar', 'qux'],
@@ -532,6 +568,7 @@ it('handles push action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 2,
routeNames: ['baz', 'bar', 'qux'],
@@ -541,6 +578,7 @@ it('handles push action', () => {
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 3,
routeNames: ['baz', 'bar', 'qux'],
@@ -551,6 +589,7 @@ it('handles push action', () => {
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 2,
routeNames: ['baz', 'bar', 'qux'],
@@ -576,6 +615,7 @@ it('changes index on focus change', () => {
{ key: 'qux-0', name: 'qux' },
],
stale: false,
type: 'stack',
},
'baz-0'
)
@@ -585,6 +625,7 @@ it('changes index on focus change', () => {
routeNames: ['bar', 'baz', 'qux'],
routes: [{ key: 'bar-0', name: 'bar' }, { key: 'baz-0', name: 'baz' }],
stale: false,
type: 'stack',
});
const state = {
@@ -593,6 +634,7 @@ it('changes index on focus change', () => {
routeNames: ['bar', 'baz', 'qux'],
routes: [{ key: 'bar-0', name: 'bar' }, { key: 'baz-0', name: 'baz' }],
stale: false as const,
type: 'stack' as const,
};
expect(router.getStateForRouteFocus(state, 'qux-0')).toEqual(state);

View File

@@ -25,6 +25,7 @@ it('gets initial state from route names and params with initialRouteName', () =>
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'tab',
});
});
@@ -50,6 +51,7 @@ it('gets initial state from route names and params without initialRouteName', ()
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'tab',
});
});
@@ -82,6 +84,28 @@ it('gets rehydrated state from partial state', () => {
{ key: 'qux-1', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'tab',
});
expect(
router.getRehydratedState(
{
routes: [{ key: 'baz-0', name: 'baz' }],
},
options
)
).toEqual({
index: 1,
key: 'tab-test',
routeKeyHistory: [],
routeNames: ['bar', 'baz', 'qux'],
routes: [
{ key: 'bar-test', name: 'bar' },
{ key: 'baz-0', name: 'baz', params: { answer: 42 } },
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'tab',
});
expect(
@@ -107,6 +131,7 @@ it('gets rehydrated state from partial state', () => {
{ key: 'qux-2', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'tab',
});
expect(
@@ -118,7 +143,7 @@ it('gets rehydrated state from partial state', () => {
options
)
).toEqual({
index: 0,
index: 2,
key: 'tab-test',
routeKeyHistory: [],
routeNames: ['bar', 'baz', 'qux'],
@@ -128,6 +153,7 @@ it('gets rehydrated state from partial state', () => {
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'tab',
});
expect(
@@ -150,6 +176,7 @@ it('gets rehydrated state from partial state', () => {
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'tab',
});
});
@@ -167,6 +194,7 @@ it("doesn't rehydrate state if it's not stale", () => {
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false as const,
type: 'tab' as const,
};
expect(
@@ -193,6 +221,7 @@ it('gets state on route names change', () => {
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
],
stale: false,
type: 'tab',
},
{
routeNames: ['qux', 'baz', 'foo', 'fiz'],
@@ -214,6 +243,7 @@ it('gets state on route names change', () => {
{ key: 'fiz-test', name: 'fiz', params: { fruit: 'apple' } },
],
stale: false,
type: 'tab',
});
});
@@ -224,6 +254,7 @@ it('handles navigate action', () => {
router.getStateForAction(
{
stale: false,
type: 'tab',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -234,6 +265,7 @@ it('handles navigate action', () => {
)
).toEqual({
stale: false,
type: 'tab',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -248,6 +280,7 @@ it('handles navigate action', () => {
router.getStateForAction(
{
stale: false,
type: 'tab',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -258,6 +291,7 @@ it('handles navigate action', () => {
)
).toEqual({
stale: false,
type: 'tab',
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
@@ -272,6 +306,7 @@ it('handles navigate action', () => {
router.getStateForAction(
{
stale: false,
type: 'tab',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -290,6 +325,7 @@ it('handles jump to action', () => {
router.getStateForAction(
{
stale: false,
type: 'tab',
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
@@ -300,6 +336,7 @@ it('handles jump to action', () => {
)
).toEqual({
stale: false,
type: 'tab',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -315,6 +352,7 @@ it('handles back action with backBehavior: history', () => {
router.getStateForAction(
{
stale: false,
type: 'tab',
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
@@ -325,6 +363,7 @@ it('handles back action with backBehavior: history', () => {
)
).toEqual({
stale: false,
type: 'tab',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -336,6 +375,7 @@ it('handles back action with backBehavior: history', () => {
router.getStateForAction(
{
stale: false,
type: 'tab',
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
@@ -354,6 +394,7 @@ it('handles back action with backBehavior: order', () => {
router.getStateForAction(
{
stale: false,
type: 'tab',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -364,6 +405,7 @@ it('handles back action with backBehavior: order', () => {
)
).toEqual({
stale: false,
type: 'tab',
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
@@ -375,6 +417,7 @@ it('handles back action with backBehavior: order', () => {
router.getStateForAction(
{
stale: false,
type: 'tab',
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
@@ -396,6 +439,7 @@ it('handles back action with backBehavior: initialRoute', () => {
router.getStateForAction(
{
stale: false,
type: 'tab',
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
@@ -406,6 +450,7 @@ it('handles back action with backBehavior: initialRoute', () => {
)
).toEqual({
stale: false,
type: 'tab',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -417,6 +462,7 @@ it('handles back action with backBehavior: initialRoute', () => {
router.getStateForAction(
{
stale: false,
type: 'tab',
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
@@ -435,6 +481,7 @@ it('handles back action with backBehavior: none', () => {
router.getStateForAction(
{
stale: false,
type: 'tab',
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
@@ -460,6 +507,7 @@ it('updates route key history on navigate and jump to', () => {
{ key: 'qux-0', name: 'qux', params: { name: 'Jane' } },
],
stale: false as const,
type: 'tab',
};
expect(state.routeKeyHistory).toEqual([]);
@@ -514,6 +562,7 @@ it('updates route key history on focus change', () => {
{ key: 'qux-0', name: 'qux', params: { name: 'Jane' } },
],
stale: false as const,
type: 'tab' as const,
};
expect(router.getStateForRouteFocus(state, 'bar-0').routeKeyHistory).toEqual(

View File

@@ -6,7 +6,7 @@
"react-native",
"react-navigation"
],
"version": "5.0.0-alpha.9",
"version": "5.0.0-alpha.11",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -17,7 +17,11 @@ export type DrawerActionType =
export type DrawerRouterOptions = TabRouterOptions;
export type DrawerNavigationState = TabNavigationState & {
export type DrawerNavigationState = Omit<TabNavigationState, 'type'> & {
/**
* Type of the router, in this case, it's drawer.
*/
type: 'drawer';
/**
* Whether the drawer is open or closed.
*/
@@ -40,7 +44,7 @@ export const DrawerActions = {
export default function DrawerRouter(
options: DrawerRouterOptions
): Router<DrawerNavigationState, DrawerActionType | CommonAction> {
const router = TabRouter(options) as Router<
const router = (TabRouter(options) as unknown) as Router<
DrawerNavigationState,
TabActionType | CommonAction
>;
@@ -48,6 +52,8 @@ export default function DrawerRouter(
return {
...router,
type: 'drawer',
getInitialState({ routeNames, routeParamList }) {
const index =
options.initialRouteName === undefined
@@ -56,6 +62,7 @@ export default function DrawerRouter(
return {
stale: false,
type: 'drawer',
key: `drawer-${shortid()}`,
index,
routeNames,
@@ -81,6 +88,7 @@ export default function DrawerRouter(
return {
...state,
type: 'drawer',
key: `drawer-${shortid()}`,
isDrawerOpen:
typeof partialState.isDrawerOpen === 'boolean'

View File

@@ -29,7 +29,12 @@ export type StackActionType =
export type StackRouterOptions = DefaultRouterOptions;
export type StackNavigationState = NavigationState;
export type StackNavigationState = NavigationState & {
/**
* Type of the router, in this case, it's stack.
*/
type: 'stack';
};
export const StackActions = {
push(name: string, params?: object): StackActionType {
@@ -47,6 +52,8 @@ export default function StackRouter(options: StackRouterOptions) {
const router: Router<StackNavigationState, CommonAction | StackActionType> = {
...BaseRouter,
type: 'stack',
getInitialState({ routeNames, routeParamList }) {
const initialRouteName =
options.initialRouteName !== undefined
@@ -55,6 +62,7 @@ export default function StackRouter(options: StackRouterOptions) {
return {
stale: false,
type: 'stack',
key: `stack-${shortid()}`,
index: 0,
routeNames,
@@ -107,6 +115,7 @@ export default function StackRouter(options: StackRouterOptions) {
return {
stale: false,
type: 'stack',
key: `stack-${shortid()}`,
index: routes.length - 1,
routeNames,

View File

@@ -21,6 +21,10 @@ export type TabRouterOptions = DefaultRouterOptions & {
};
export type TabNavigationState = NavigationState & {
/**
* Type of the router, in this case, it's tab.
*/
type: 'tab';
/**
* List of previously visited route keys.
*/
@@ -54,6 +58,8 @@ export default function TabRouter({
const router: Router<TabNavigationState, TabActionType | CommonAction> = {
...BaseRouter,
type: 'tab',
getInitialState({ routeNames, routeParamList }) {
const index =
initialRouteName === undefined
@@ -62,6 +68,7 @@ export default function TabRouter({
return {
stale: false,
type: 'tab',
key: `tab-${shortid()}`,
index,
routeNames,
@@ -105,17 +112,25 @@ export default function TabRouter({
} as Route<string>;
});
const index = Math.min(
Math.max(
typeof state.index === 'number'
? state.index
: routeNames.indexOf(state.routes[0].name),
0
),
routes.length - 1
);
const routeKeyHistory = state.routeKeyHistory
? state.routeKeyHistory.filter(key => routes.find(r => r.key === key))
: [];
return {
stale: false,
type: 'tab',
key: `tab-${shortid()}`,
index:
typeof state.index === 'number' && state.index < routes.length
? state.index
: 0,
index,
routeNames,
routeKeyHistory,
routes,

View File

@@ -3,6 +3,37 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.31](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.30...@react-navigation/stack@5.0.0-alpha.31) (2019-10-30)
**Note:** Version bump only for package @react-navigation/stack
# [5.0.0-alpha.30](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.29...@react-navigation/stack@5.0.0-alpha.30) (2019-10-29)
### Bug Fixes
* keyboard manager in stack for fast swipe ([07bfc86](https://github.com/react-navigation/navigation-ex/commit/07bfc86))
* make clearKeyboardTimeout private ([876c318](https://github.com/react-navigation/navigation-ex/commit/876c318))
# [5.0.0-alpha.29](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.28...@react-navigation/stack@5.0.0-alpha.29) (2019-10-22)
### Bug Fixes
* conditions in gesture direction ([225e760](https://github.com/react-navigation/navigation-ex/commit/225e760))
# [5.0.0-alpha.28](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.27...@react-navigation/stack@5.0.0-alpha.28) (2019-10-22)

View File

@@ -10,7 +10,7 @@
"android",
"stack"
],
"version": "5.0.0-alpha.28",
"version": "5.0.0-alpha.31",
"license": "MIT",
"repository": {
"type": "git",
@@ -33,7 +33,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.9"
"@react-navigation/routers": "^5.0.0-alpha.11"
},
"devDependencies": {
"@react-native-community/bob": "^0.7.0",
@@ -46,7 +46,7 @@
"react-native-gesture-handler": "^1.3.0",
"react-native-reanimated": "^1.3.0",
"react-native-safe-area-context": "^0.3.6",
"react-native-screens": "^2.0.0-alpha.5",
"react-native-screens": "^2.0.0-alpha.6",
"typescript": "^3.6.3"
},
"peerDependencies": {

View File

@@ -11,14 +11,27 @@ type Props = {
};
export default class KeyboardManager extends React.Component<Props> {
componentWillUnmount = () => {
this.clearKeyboardTimeout();
};
// Numeric id of the previously focused text input
// When a gesture didn't change the tab, we can restore the focused input with this
private previouslyFocusedTextInput: number | null = null;
private startTimestamp: number = 0;
private keyboardTimeout: NodeJS.Timeout | undefined;
private clearKeyboardTimeout = () => {
if (this.keyboardTimeout !== undefined) {
clearTimeout(this.keyboardTimeout);
this.keyboardTimeout = undefined;
}
};
private handlePageChangeStart = () => {
if (!this.props.enabled) {
return;
}
this.clearKeyboardTimeout();
const input = TextInput.State.currentlyFocusedField();
@@ -27,12 +40,16 @@ export default class KeyboardManager extends React.Component<Props> {
// Store the id of this input so we can refocus it if change was cancelled
this.previouslyFocusedTextInput = input;
// Store timestamp for touch start
this.startTimestamp = Date.now();
};
private handlePageChangeConfirm = () => {
if (!this.props.enabled) {
return;
}
this.clearKeyboardTimeout();
Keyboard.dismiss();
@@ -44,15 +61,29 @@ export default class KeyboardManager extends React.Component<Props> {
if (!this.props.enabled) {
return;
}
this.clearKeyboardTimeout();
// The page didn't change, we should restore the focus of text input
const input = this.previouslyFocusedTextInput;
if (input) {
TextInput.State.focusTextInput(input);
}
// If the interaction was super short we should make sure keyboard won't hide again.
this.previouslyFocusedTextInput = null;
// Too fast input refocus will result only in keyboard flashing on screen and hiding right away.
// During first ~100ms keyboard will be dismissed no matter what,
// so we have to make sure it won't interrupt input refocus logic.
// That's why when the interaction is shorter than 100ms we add delay so it won't hide once again.
// Subtracting timestamps makes us sure the delay is executed only when needed.
if (Date.now() - this.startTimestamp < 100) {
this.keyboardTimeout = setTimeout(() => {
TextInput.State.focusTextInput(input);
this.previouslyFocusedTextInput = null;
}, 100);
} else {
TextInput.State.focusTextInput(input);
this.previouslyFocusedTextInput = null;
}
}
};
render() {

View File

@@ -713,13 +713,16 @@ export default class Card extends React.Component<Props> {
private gestureActivationCriteria() {
const { layout, gestureDirection, gestureResponseDistance } = this.props;
// Doesn't make sense for a response distance of 0, so this works fine
const distance =
gestureDirection === 'vertical'
? (gestureResponseDistance && gestureResponseDistance.vertical) ||
GESTURE_RESPONSE_DISTANCE_VERTICAL
: (gestureResponseDistance && gestureResponseDistance.horizontal) ||
GESTURE_RESPONSE_DISTANCE_HORIZONTAL;
? gestureResponseDistance &&
gestureResponseDistance.vertical !== undefined
? gestureResponseDistance.vertical
: GESTURE_RESPONSE_DISTANCE_VERTICAL
: gestureResponseDistance &&
gestureResponseDistance.horizontal !== undefined
? gestureResponseDistance.horizontal
: GESTURE_RESPONSE_DISTANCE_HORIZONTAL;
if (gestureDirection === 'vertical') {
return {

View File

@@ -13102,10 +13102,10 @@ react-native-gesture-handler@~1.3.0:
invariant "^2.2.2"
prop-types "^15.5.10"
react-native-paper@^3.0.0-alpha.7:
version "3.0.0-alpha.7"
resolved "https://registry.yarnpkg.com/react-native-paper/-/react-native-paper-3.0.0-alpha.7.tgz#fbbfe5dc9ef8dbd18932786aa3d7f0479501538b"
integrity sha512-tjqewrUMnucLM4yqMiVtCOnrqilnvDDNr2guIImwsUpJ6HWaJKBEFKqB25SEdMvuo88MWSdA0gyRNtS3WRpS3w==
react-native-paper@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/react-native-paper/-/react-native-paper-3.1.1.tgz#971f3097eecb4c061bf10768182b8985442a45ab"
integrity sha512-GHJ/2z/1Nzm4Y1g22Znu09BV7SV4tsR7h/9HrXuj3kFrsJo7zt5e+t/ELLLvycGEo4z1vhV6MtjtIk/PSaKoDA==
dependencies:
"@callstack/react-theme-provider" "^3.0.5"
color "^3.1.2"
@@ -13133,10 +13133,10 @@ react-native-safe-area-view@^0.12.0:
dependencies:
hoist-non-react-statics "^2.3.1"
react-native-screens@^2.0.0-alpha.5:
version "2.0.0-alpha.5"
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.0.0-alpha.5.tgz#5b6a72df959d31ffaf7045cd5eb753477e80689b"
integrity sha512-uKVc+JYEC59Dz2RPBI4tnaIB8W6T0dHGY6PjUtvkvaBmZBjfxhpezd3m2t8o913Xarx6EvT2maSH8816+MNJnw==
react-native-screens@^2.0.0-alpha.6:
version "2.0.0-alpha.6"
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.0.0-alpha.6.tgz#238cf7e97ff6008cca75dd1dd4a5a854bce81d57"
integrity sha512-5m59glvDDzQvzdBymIn6GfCnzk/9kaxkREEKLVMdANtZlqIuH3Jbgoc+56pcX5LVSZCMaSozPAQBcLaMWO2JUA==
dependencies:
debounce "^1.2.0"