Compare commits

..

10 Commits

Author SHA1 Message Date
Satyajit Sahoo
264537bdb4 chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.45
 - @react-navigation/compat@5.0.0-alpha.34
 - @react-navigation/core@5.0.0-alpha.43
 - @react-navigation/drawer@5.0.0-alpha.47
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.42
 - @react-navigation/material-top-tabs@5.0.0-alpha.41
 - @react-navigation/native-stack@5.0.0-alpha.35
 - @react-navigation/native@5.0.0-alpha.35
 - @react-navigation/routers@5.0.0-alpha.33
 - @react-navigation/stack@5.0.0-alpha.70
2020-02-04 17:34:55 +01:00
Satyajit Sahoo
ca4a36070a fix: improve error message for unhandled action 2020-02-04 17:33:03 +01:00
Wojciech Lewicki
4ca5cc6329 feat: add initialRouteName property to config (#322) 2020-02-04 14:44:57 +01:00
osdnk
25c3fc440f chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.44
 - @react-navigation/compat@5.0.0-alpha.33
 - @react-navigation/core@5.0.0-alpha.42
 - @react-navigation/drawer@5.0.0-alpha.46
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.41
 - @react-navigation/material-top-tabs@5.0.0-alpha.40
 - @react-navigation/native-stack@5.0.0-alpha.34
 - @react-navigation/native@5.0.0-alpha.34
 - @react-navigation/routers@5.0.0-alpha.32
 - @react-navigation/stack@5.0.0-alpha.69
2020-02-04 11:04:43 +01:00
Satyajit Sahoo
89fa363883 chore: don't run expo preview for contributors 2020-02-04 10:54:12 +01:00
Michał Osadnik
bec2f754d4 refactor: rename NavigationNativeContainer to NavigationContainer (#344) 2020-02-04 10:21:16 +01:00
Evan Bacon
b277927925 feat: disable pan gesture by default in the browser for Apple devices
fixes #287
2020-02-04 09:12:40 +01:00
osdnk
72993c6463 chore: delete .gitattributes 2020-02-03 14:53:11 +01:00
Satyajit Sahoo
3fbfb70699 chore: publish
- @react-navigation/stack@5.0.0-alpha.68
2020-02-03 05:48:24 +01:00
Satyajit Sahoo
abdf9d12b5 fix: use .native for masked view instead of .web 2020-02-03 05:47:25 +01:00
51 changed files with 1121 additions and 608 deletions

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
* text eol=lf

View File

@@ -5,6 +5,7 @@ jobs:
publish:
name: Install and publish
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.owner.login == 'react-navigation'
steps:
- name: Checkout
uses: actions/checkout@v1

View File

@@ -22,7 +22,7 @@ import {
InitialState,
useLinking,
NavigationContainerRef,
NavigationNativeContainer,
NavigationContainer,
DefaultTheme,
DarkTheme,
} from '@react-navigation/native';
@@ -202,7 +202,7 @@ export default function App() {
{Platform.OS === 'ios' && (
<StatusBar barStyle={theme.dark ? 'light-content' : 'dark-content'} />
)}
<NavigationNativeContainer
<NavigationContainer
ref={containerRef}
initialState={initialState}
onStateChange={state =>
@@ -307,7 +307,7 @@ export default function App() {
)}
</Drawer.Screen>
</Drawer.Navigator>
</NavigationNativeContainer>
</NavigationContainer>
</PaperProvider>
);
}

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.45](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.44...@react-navigation/bottom-tabs@5.0.0-alpha.45) (2020-02-04)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [5.0.0-alpha.44](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.43...@react-navigation/bottom-tabs@5.0.0-alpha.44) (2020-02-04)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [5.0.0-alpha.43](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.42...@react-navigation/bottom-tabs@5.0.0-alpha.43) (2020-02-03)
**Note:** Version bump only for package @react-navigation/bottom-tabs

View File

@@ -10,7 +10,7 @@
"android",
"tab"
],
"version": "5.0.0-alpha.43",
"version": "5.0.0-alpha.45",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs",
"main": "lib/commonjs/index.js",
@@ -30,7 +30,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.31",
"@react-navigation/routers": "^5.0.0-alpha.33",
"color": "^3.1.2",
"react-native-iphone-x-helper": "^1.2.1"
},

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.34](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.33...@react-navigation/compat@5.0.0-alpha.34) (2020-02-04)
**Note:** Version bump only for package @react-navigation/compat
# [5.0.0-alpha.33](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.32...@react-navigation/compat@5.0.0-alpha.33) (2020-02-04)
**Note:** Version bump only for package @react-navigation/compat
# [5.0.0-alpha.32](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.31...@react-navigation/compat@5.0.0-alpha.32) (2020-02-03)
**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.32",
"version": "5.0.0-alpha.34",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/compat",
"main": "lib/commonjs/index.js",
@@ -21,7 +21,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.31"
"@react-navigation/routers": "^5.0.0-alpha.33"
},
"devDependencies": {
"@types/react": "^16.9.17",

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.43](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.42...@react-navigation/core@5.0.0-alpha.43) (2020-02-04)
### Bug Fixes
* improve error message for unhandled action ([ca4a360](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/ca4a36070a21c4fe86cb1cc55a4452dca293f215))
### Features
* add initialRouteName property to config ([#322](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/issues/322)) ([4ca5cc6](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/4ca5cc632992187f12870281e4cf4c7d1f799967))
# [5.0.0-alpha.42](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.41...@react-navigation/core@5.0.0-alpha.42) (2020-02-04)
**Note:** Version bump only for package @react-navigation/core
# [5.0.0-alpha.41](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.40...@react-navigation/core@5.0.0-alpha.41) (2020-02-03)

View File

@@ -6,7 +6,7 @@
"react-native",
"react-navigation"
],
"version": "5.0.0-alpha.41",
"version": "5.0.0-alpha.43",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/core",
"main": "lib/commonjs/index.js",

View File

@@ -0,0 +1,300 @@
import * as React from 'react';
import * as CommonActions from './CommonActions';
import EnsureSingleNavigator from './EnsureSingleNavigator';
import NavigationBuilderContext from './NavigationBuilderContext';
import useFocusedListeners from './useFocusedListeners';
import useDevTools from './useDevTools';
import useStateGetters from './useStateGetters';
import isSerializable from './isSerializable';
import {
Route,
NavigationState,
InitialState,
PartialState,
NavigationAction,
NavigationContainerRef,
NavigationContainerProps,
} from './types';
import useEventEmitter from './useEventEmitter';
type State = NavigationState | PartialState<NavigationState> | undefined;
const MISSING_CONTEXT_ERROR =
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?";
export const NavigationStateContext = React.createContext<{
isDefault?: true;
state?: NavigationState | PartialState<NavigationState>;
getState: () => NavigationState | PartialState<NavigationState> | undefined;
setState: (
state: NavigationState | PartialState<NavigationState> | undefined
) => void;
key?: string;
performTransaction: (action: () => void) => void;
}>({
isDefault: true,
get getState(): any {
throw new Error(MISSING_CONTEXT_ERROR);
},
get setState(): any {
throw new Error(MISSING_CONTEXT_ERROR);
},
get performTransaction(): any {
throw new Error(MISSING_CONTEXT_ERROR);
},
});
let hasWarnedForSerialization = false;
/**
* Remove `key` and `routeNames` from the state objects recursively to get partial state.
*
* @param state Initial state object.
*/
const getPartialState = (
state: InitialState | undefined
): PartialState<NavigationState> | undefined => {
if (state === undefined) {
return;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { key, routeNames, ...partialState } = state;
// @ts-ignore
return {
...partialState,
stale: true,
routes: state.routes.map(route => {
if (route.state === undefined) {
return route as Route<string> & {
state?: PartialState<NavigationState>;
};
}
return { ...route, state: getPartialState(route.state) };
}),
};
};
/**
* Container component which holds the navigation state.
* This should be rendered at the root wrapping the whole app.
*
* @param props.initialState Initial state object for the navigation tree.
* @param props.onStateChange Callback which is called with the latest navigation state when it changes.
* @param props.children Child elements to render the content.
* @param props.ref Ref object which refers to the navigation object containing helper methods.
*/
const BaseNavigationContainer = React.forwardRef(
function BaseNavigationContainer(
{
initialState,
onStateChange,
independent,
children,
}: NavigationContainerProps,
ref: React.Ref<NavigationContainerRef>
) {
const parent = React.useContext(NavigationStateContext);
if (!parent.isDefault && !independent) {
throw new Error(
"Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitely."
);
}
const [state, setNavigationState] = React.useState<State>(() =>
getPartialState(initialState == null ? undefined : initialState)
);
const navigationStateRef = React.useRef<State>();
const transactionStateRef = React.useRef<State | null>(null);
const isTransactionActiveRef = React.useRef<boolean>(false);
const isFirstMountRef = React.useRef<boolean>(true);
const skipTrackingRef = React.useRef<boolean>(false);
const performTransaction = React.useCallback((callback: () => void) => {
if (isTransactionActiveRef.current) {
throw new Error(
"Only one transaction can be active at a time. Did you accidentally nest 'performTransaction'?"
);
}
setNavigationState((navigationState: State) => {
isTransactionActiveRef.current = true;
transactionStateRef.current = navigationState;
try {
callback();
} finally {
isTransactionActiveRef.current = false;
}
return transactionStateRef.current;
});
}, []);
const getState = React.useCallback(
() =>
transactionStateRef.current !== null
? transactionStateRef.current
: navigationStateRef.current,
[]
);
const setState = React.useCallback((navigationState: State) => {
if (transactionStateRef.current === null) {
throw new Error(
"Any 'setState' calls need to be done inside 'performTransaction'"
);
}
transactionStateRef.current = navigationState;
}, []);
const reset = React.useCallback(
(state: NavigationState) => {
performTransaction(() => {
skipTrackingRef.current = true;
setState(state);
});
},
[performTransaction, setState]
);
const { trackState, trackAction } = useDevTools({
name: '@react-navigation',
reset,
state,
});
const {
listeners,
addListener: addFocusedListener,
} = useFocusedListeners();
const { getStateForRoute, addStateGetter } = useStateGetters();
const dispatch = (
action: NavigationAction | ((state: NavigationState) => NavigationAction)
) => {
listeners[0](navigation => navigation.dispatch(action));
};
const canGoBack = () => {
const { result, handled } = listeners[0](navigation =>
navigation.canGoBack()
);
if (handled) {
return result;
} else {
return false;
}
};
const resetRoot = React.useCallback(
(state?: PartialState<NavigationState> | NavigationState) => {
performTransaction(() => {
trackAction('@@RESET_ROOT');
setState(state);
});
},
[performTransaction, setState, trackAction]
);
const getRootState = React.useCallback(() => {
return getStateForRoute('root');
}, [getStateForRoute]);
const emitter = useEventEmitter();
React.useImperativeHandle(ref, () => ({
...(Object.keys(CommonActions) as (keyof typeof CommonActions)[]).reduce<
any
>((acc, name) => {
acc[name] = (...args: any[]) =>
dispatch(
CommonActions[name](
// @ts-ignore
...args
)
);
return acc;
}, {}),
...emitter.create('root'),
resetRoot,
dispatch,
canGoBack,
getRootState,
}));
const builderContext = React.useMemo(
() => ({
addFocusedListener,
addStateGetter,
trackAction,
}),
[addFocusedListener, trackAction, addStateGetter]
);
const context = React.useMemo(
() => ({
state,
performTransaction,
getState,
setState,
}),
[getState, performTransaction, setState, state]
);
React.useEffect(() => {
if (process.env.NODE_ENV !== 'production') {
if (
state !== undefined &&
!isSerializable(state) &&
!hasWarnedForSerialization
) {
hasWarnedForSerialization = true;
console.warn(
"We found non-serializable values in the navigation state, which can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use functions in your options, you can use 'navigation.setOptions' instead."
);
}
}
emitter.emit({
type: 'state',
data: { state },
});
if (skipTrackingRef.current) {
skipTrackingRef.current = false;
} else {
trackState(getRootState);
}
navigationStateRef.current = state;
transactionStateRef.current = null;
if (!isFirstMountRef.current && onStateChange) {
onStateChange(getRootState());
}
isFirstMountRef.current = false;
}, [state, onStateChange, trackState, getRootState, emitter]);
return (
<NavigationBuilderContext.Provider value={builderContext}>
<NavigationStateContext.Provider value={context}>
<EnsureSingleNavigator>{children}</EnsureSingleNavigator>
</NavigationStateContext.Provider>
</NavigationBuilderContext.Provider>
);
}
);
export default BaseNavigationContainer;

View File

@@ -1,295 +0,0 @@
import * as React from 'react';
import * as CommonActions from './CommonActions';
import EnsureSingleNavigator from './EnsureSingleNavigator';
import NavigationBuilderContext from './NavigationBuilderContext';
import useFocusedListeners from './useFocusedListeners';
import useDevTools from './useDevTools';
import useStateGetters from './useStateGetters';
import isSerializable from './isSerializable';
import {
Route,
NavigationState,
InitialState,
PartialState,
NavigationAction,
NavigationContainerRef,
NavigationContainerProps,
} from './types';
import useEventEmitter from './useEventEmitter';
type State = NavigationState | PartialState<NavigationState> | undefined;
const MISSING_CONTEXT_ERROR =
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?";
export const NavigationStateContext = React.createContext<{
isDefault?: true;
state?: NavigationState | PartialState<NavigationState>;
getState: () => NavigationState | PartialState<NavigationState> | undefined;
setState: (
state: NavigationState | PartialState<NavigationState> | undefined
) => void;
key?: string;
performTransaction: (action: () => void) => void;
}>({
isDefault: true,
get getState(): any {
throw new Error(MISSING_CONTEXT_ERROR);
},
get setState(): any {
throw new Error(MISSING_CONTEXT_ERROR);
},
get performTransaction(): any {
throw new Error(MISSING_CONTEXT_ERROR);
},
});
let hasWarnedForSerialization = false;
/**
* Remove `key` and `routeNames` from the state objects recursively to get partial state.
*
* @param state Initial state object.
*/
const getPartialState = (
state: InitialState | undefined
): PartialState<NavigationState> | undefined => {
if (state === undefined) {
return;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { key, routeNames, ...partialState } = state;
// @ts-ignore
return {
...partialState,
stale: true,
routes: state.routes.map(route => {
if (route.state === undefined) {
return route as Route<string> & {
state?: PartialState<NavigationState>;
};
}
return { ...route, state: getPartialState(route.state) };
}),
};
};
/**
* Container component which holds the navigation state.
* This should be rendered at the root wrapping the whole app.
*
* @param props.initialState Initial state object for the navigation tree.
* @param props.onStateChange Callback which is called with the latest navigation state when it changes.
* @param props.children Child elements to render the content.
* @param props.ref Ref object which refers to the navigation object containing helper methods.
*/
const Container = React.forwardRef(function NavigationContainer(
{
initialState,
onStateChange,
independent,
children,
}: NavigationContainerProps,
ref: React.Ref<NavigationContainerRef>
) {
const parent = React.useContext(NavigationStateContext);
if (!parent.isDefault && !independent) {
throw new Error(
"Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitely."
);
}
const [state, setNavigationState] = React.useState<State>(() =>
getPartialState(initialState == null ? undefined : initialState)
);
const navigationStateRef = React.useRef<State>();
const transactionStateRef = React.useRef<State | null>(null);
const isTransactionActiveRef = React.useRef<boolean>(false);
const isFirstMountRef = React.useRef<boolean>(true);
const skipTrackingRef = React.useRef<boolean>(false);
const performTransaction = React.useCallback((callback: () => void) => {
if (isTransactionActiveRef.current) {
throw new Error(
"Only one transaction can be active at a time. Did you accidentally nest 'performTransaction'?"
);
}
setNavigationState((navigationState: State) => {
isTransactionActiveRef.current = true;
transactionStateRef.current = navigationState;
try {
callback();
} finally {
isTransactionActiveRef.current = false;
}
return transactionStateRef.current;
});
}, []);
const getState = React.useCallback(
() =>
transactionStateRef.current !== null
? transactionStateRef.current
: navigationStateRef.current,
[]
);
const setState = React.useCallback((navigationState: State) => {
if (transactionStateRef.current === null) {
throw new Error(
"Any 'setState' calls need to be done inside 'performTransaction'"
);
}
transactionStateRef.current = navigationState;
}, []);
const reset = React.useCallback(
(state: NavigationState) => {
performTransaction(() => {
skipTrackingRef.current = true;
setState(state);
});
},
[performTransaction, setState]
);
const { trackState, trackAction } = useDevTools({
name: '@react-navigation',
reset,
state,
});
const { listeners, addListener: addFocusedListener } = useFocusedListeners();
const { getStateForRoute, addStateGetter } = useStateGetters();
const dispatch = (
action: NavigationAction | ((state: NavigationState) => NavigationAction)
) => {
listeners[0](navigation => navigation.dispatch(action));
};
const canGoBack = () => {
const { result, handled } = listeners[0](navigation =>
navigation.canGoBack()
);
if (handled) {
return result;
} else {
return false;
}
};
const resetRoot = React.useCallback(
(state?: PartialState<NavigationState> | NavigationState) => {
performTransaction(() => {
trackAction('@@RESET_ROOT');
setState(state);
});
},
[performTransaction, setState, trackAction]
);
const getRootState = React.useCallback(() => {
return getStateForRoute('root');
}, [getStateForRoute]);
const emitter = useEventEmitter();
React.useImperativeHandle(ref, () => ({
...(Object.keys(CommonActions) as (keyof typeof CommonActions)[]).reduce<
any
>((acc, name) => {
acc[name] = (...args: any[]) =>
dispatch(
CommonActions[name](
// @ts-ignore
...args
)
);
return acc;
}, {}),
...emitter.create('root'),
resetRoot,
dispatch,
canGoBack,
getRootState,
}));
const builderContext = React.useMemo(
() => ({
addFocusedListener,
addStateGetter,
trackAction,
}),
[addFocusedListener, trackAction, addStateGetter]
);
const context = React.useMemo(
() => ({
state,
performTransaction,
getState,
setState,
}),
[getState, performTransaction, setState, state]
);
React.useEffect(() => {
if (process.env.NODE_ENV !== 'production') {
if (
state !== undefined &&
!isSerializable(state) &&
!hasWarnedForSerialization
) {
hasWarnedForSerialization = true;
console.warn(
"We found non-serializable values in the navigation state, which can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use functions in your options, you can use 'navigation.setOptions' instead."
);
}
}
emitter.emit({
type: 'state',
data: { state },
});
if (skipTrackingRef.current) {
skipTrackingRef.current = false;
} else {
trackState(getRootState);
}
navigationStateRef.current = state;
transactionStateRef.current = null;
if (!isFirstMountRef.current && onStateChange) {
onStateChange(getRootState());
}
isFirstMountRef.current = false;
}, [state, onStateChange, trackState, getRootState, emitter]);
return (
<NavigationBuilderContext.Provider value={builderContext}>
<NavigationStateContext.Provider value={context}>
<EnsureSingleNavigator>{children}</EnsureSingleNavigator>
</NavigationStateContext.Provider>
</NavigationBuilderContext.Provider>
);
});
export default Container;

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { NavigationStateContext } from './NavigationContainer';
import { NavigationStateContext } from './BaseNavigationContainer';
import NavigationContext from './NavigationContext';
import NavigationRouteContext from './NavigationRouteContext';
import StaticContainer from './StaticContainer';

View File

@@ -1,8 +1,8 @@
import * as React from 'react';
import { act, render } from 'react-native-testing-library';
import NavigationContainer, {
import BaseNavigationContainer, {
NavigationStateContext,
} from '../NavigationContainer';
} from '../BaseNavigationContainer';
import MockRouter, { MockActions } from './__fixtures__/MockRouter';
import useNavigationBuilder from '../useNavigationBuilder';
import Screen from '../Screen';
@@ -85,9 +85,9 @@ it('throws when setState is called outside performTransaction', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<Test />
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -112,9 +112,9 @@ it('throws when nesting performTransaction', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<Test />
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -125,11 +125,11 @@ it('throws when nesting performTransaction', () => {
it('throws when nesting containers', () => {
expect(() =>
render(
<NavigationContainer>
<NavigationContainer>
<BaseNavigationContainer>
<BaseNavigationContainer>
<React.Fragment />
</NavigationContainer>
</NavigationContainer>
</BaseNavigationContainer>
</BaseNavigationContainer>
)
).toThrowError(
"Looks like you have nested a 'NavigationContainer' inside another."
@@ -137,11 +137,11 @@ it('throws when nesting containers', () => {
expect(() =>
render(
<NavigationContainer>
<NavigationContainer independent>
<BaseNavigationContainer>
<BaseNavigationContainer independent>
<React.Fragment />
</NavigationContainer>
</NavigationContainer>
</BaseNavigationContainer>
</BaseNavigationContainer>
)
).not.toThrowError(
"Looks like you have nested a 'NavigationContainer' inside another."
@@ -223,7 +223,7 @@ it('handle dispatching with ref', () => {
};
const element = (
<NavigationContainer
<BaseNavigationContainer
ref={ref}
initialState={initialState}
onStateChange={onStateChange}
@@ -248,7 +248,7 @@ it('handle dispatching with ref', () => {
)}
</Screen>
</ParentNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element).update(element);
@@ -301,7 +301,7 @@ it('handle resetting state with ref', () => {
const onStateChange = jest.fn();
const element = (
<NavigationContainer ref={ref} onStateChange={onStateChange}>
<BaseNavigationContainer ref={ref} onStateChange={onStateChange}>
<TestNavigator>
<Screen name="foo">{() => null}</Screen>
<Screen name="foo2">
@@ -322,7 +322,7 @@ it('handle resetting state with ref', () => {
)}
</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element).update(element);
@@ -389,7 +389,7 @@ it('handles getRootState', () => {
const ref = React.createRef<NavigationContainerRef>();
const element = (
<NavigationContainer ref={ref}>
<BaseNavigationContainer ref={ref}>
<TestNavigator initialRouteName="foo">
<Screen name="foo">
{() => (
@@ -401,7 +401,7 @@ it('handles getRootState', () => {
</Screen>
<Screen name="bar">{() => null}</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element);
@@ -450,13 +450,13 @@ it('emits state events when the state changes', () => {
const ref = React.createRef<NavigationContainerRef>();
const element = (
<NavigationContainer ref={ref}>
<BaseNavigationContainer ref={ref}>
<TestNavigator>
<Screen name="foo">{() => null}</Screen>
<Screen name="bar">{() => null}</Screen>
<Screen name="baz">{() => null}</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element).update(element);

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import { render } from 'react-native-testing-library';
import Screen from '../Screen';
import NavigationContainer from '../NavigationContainer';
import BaseNavigationContainer from '../BaseNavigationContainer';
import useNavigationBuilder from '../useNavigationBuilder';
import MockRouter, { MockRouterKey } from './__fixtures__/MockRouter';
@@ -26,7 +26,7 @@ it('throws if NAVIGATE dispatched neither key nor name', () => {
const onStateChange = jest.fn();
const element = (
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator initialRouteName="foo">
<Screen
name="foo"
@@ -34,7 +34,7 @@ it('throws if NAVIGATE dispatched neither key nor name', () => {
initialParams={{ count: 10 }}
/>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(

View File

@@ -394,13 +394,6 @@ it('handles parse in nested object for second route depth and and path and parse
screens: {
Foe: 'foe',
Bar: {
path: 'bar/:id',
parse: {
id: Number,
},
stringify: {
id: (id: number) => `id=${id}`,
},
screens: {
Baz: 'baz',
},
@@ -433,24 +426,260 @@ it('handles parse in nested object for second route depth and and path and parse
);
});
it('returns undefined if path is empty', () => {
it('handles initialRouteName', () => {
const path = '/baz';
const config = {
Foo: {
path: 'foo/:id',
starting: true,
stringify: {
id: (id: number) => `id=${id}`,
},
initialRouteName: 'Foe',
screens: {
Foe: 'foe',
Bar: {
path: 'bar/:id',
parse: {
id: Number,
screens: {
Baz: 'baz',
},
},
},
},
};
const state = {
routes: [
{
name: 'Foo',
state: {
index: 1,
routes: [
{
name: 'Foe',
},
{
name: 'Bar',
state: {
routes: [{ name: 'Baz' }],
},
},
],
},
},
],
};
expect(getStateFromPath(path, config)).toEqual(state);
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
state
);
});
it('handles initialRouteName included in path', () => {
const path = '/baz';
const config = {
Foo: {
initialRouteName: 'Foe',
screens: {
Foe: {
screens: {
Baz: 'baz',
},
},
Bar: 'bar',
},
},
};
const state = {
routes: [
{
name: 'Foo',
state: {
routes: [
{
name: 'Foe',
state: {
routes: [{ name: 'Baz' }],
},
},
],
},
},
],
};
expect(getStateFromPath(path, config)).toEqual(state);
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
state
);
});
it('handles two initialRouteNames', () => {
const path = '/bar/sweet/apple/foe/bis/jane?count=10&answer=42&valid=true';
const config = {
Foo: {
path: 'foo',
screens: {
Foe: 'foe',
},
},
Bar: 'bar/:type/:fruit',
Baz: {
initialRouteName: 'Bos',
screens: {
Bos: 'bos',
Bis: {
path: 'bis/:author',
stringify: {
id: (id: number) => `id=${id}`,
author: (author: string) =>
author.replace(/^\w/, c => c.toLowerCase()),
},
parse: {
author: (author: string) =>
author.replace(/^\w/, c => c.toUpperCase()),
count: Number,
valid: Boolean,
},
},
},
},
};
const state = {
routes: [
{
name: 'Bar',
params: { fruit: 'apple', type: 'sweet' },
state: {
routes: [
{
name: 'Foo',
state: {
routes: [
{
name: 'Foe',
state: {
routes: [
{
name: 'Baz',
state: {
index: 1,
routes: [
{ name: 'Bos' },
{
name: 'Bis',
params: {
author: 'Jane',
count: 10,
answer: '42',
valid: true,
},
},
],
},
},
],
},
},
],
},
},
],
},
},
],
};
expect(getStateFromPath(path, config)).toEqual(state);
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
state
);
});
it('accepts initialRouteName without config for it', () => {
const path = '/bar/sweet/apple/foe/bis/jane?count=10&answer=42&valid=true';
const config = {
Foo: {
path: 'foo',
screens: {
Foe: 'foe',
},
},
Bar: 'bar/:type/:fruit',
Baz: {
initialRouteName: 'Bas',
screens: {
Bos: 'bos',
Bis: {
path: 'bis/:author',
stringify: {
author: (author: string) =>
author.replace(/^\w/, c => c.toLowerCase()),
},
parse: {
author: (author: string) =>
author.replace(/^\w/, c => c.toUpperCase()),
count: Number,
valid: Boolean,
},
},
},
},
};
const state = {
routes: [
{
name: 'Bar',
params: { fruit: 'apple', type: 'sweet' },
state: {
routes: [
{
name: 'Foo',
state: {
routes: [
{
name: 'Foe',
state: {
routes: [
{
name: 'Baz',
state: {
index: 1,
routes: [
{ name: 'Bas' },
{
name: 'Bis',
params: {
author: 'Jane',
count: 10,
answer: '42',
valid: true,
},
},
],
},
},
],
},
},
],
},
},
],
},
},
],
};
expect(getStateFromPath(path, config)).toEqual(state);
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
state
);
});
it('returns undefined if path is empty', () => {
const config = {
Foo: {
screens: {
Foe: 'foe',
Bar: {
screens: {
Baz: 'baz',
},

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import { render, act } from 'react-native-testing-library';
import Screen from '../Screen';
import NavigationContainer from '../NavigationContainer';
import BaseNavigationContainer from '../BaseNavigationContainer';
import useNavigationBuilder from '../useNavigationBuilder';
import useNavigation from '../useNavigation';
import MockRouter, { MockRouterKey } from './__fixtures__/MockRouter';
@@ -28,7 +28,7 @@ it('initializes state for a navigator on navigation', () => {
const onStateChange = jest.fn();
const element = (
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator initialRouteName="foo">
<Screen
name="foo"
@@ -44,7 +44,7 @@ it('initializes state for a navigator on navigation', () => {
)}
</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element).update(element);
@@ -75,11 +75,11 @@ it("doesn't crash when initialState is null", () => {
const element = (
// @ts-ignore
<NavigationContainer initialState={null}>
<BaseNavigationContainer initialState={null}>
<TestNavigator>
<Screen name="foo" component={TestScreen} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element)).not.toThrowError();
@@ -112,7 +112,7 @@ it('rehydrates state for a navigator on navigation', () => {
const onStateChange = jest.fn();
const element = (
<NavigationContainer
<BaseNavigationContainer
initialState={initialState}
onStateChange={onStateChange}
>
@@ -120,7 +120,7 @@ it('rehydrates state for a navigator on navigation', () => {
<Screen name="foo" component={jest.fn()} />
<Screen name="bar" component={BarScreen} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element).update(element);
@@ -166,7 +166,7 @@ it("doesn't rehydrate state if the type of state didn't match router", () => {
const onStateChange = jest.fn();
const element = (
<NavigationContainer
<BaseNavigationContainer
initialState={initialState}
onStateChange={onStateChange}
>
@@ -178,7 +178,7 @@ it("doesn't rehydrate state if the type of state didn't match router", () => {
/>
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element).update(element);
@@ -219,7 +219,7 @@ it('initializes state for nested screens in React.Fragment', () => {
const onStateChange = jest.fn();
const element = (
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator>
<Screen name="foo" component={TestScreen} />
<React.Fragment>
@@ -227,7 +227,7 @@ it('initializes state for nested screens in React.Fragment', () => {
<Screen name="baz" component={jest.fn()} />
</React.Fragment>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element).update(element);
@@ -266,7 +266,7 @@ it('initializes state for nested navigator on navigation', () => {
const onStateChange = jest.fn();
const element = (
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator initialRouteName="baz">
<Screen name="foo" component={jest.fn()} />
<Screen name="bar" component={jest.fn()} />
@@ -278,7 +278,7 @@ it('initializes state for nested navigator on navigation', () => {
)}
</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element).update(element);
@@ -328,12 +328,12 @@ it("doesn't update state if nothing changed", () => {
const onStateChange = jest.fn();
render(
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator initialRouteName="foo">
<Screen name="foo" component={FooScreen} />
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(onStateChange).toBeCalledTimes(0);
@@ -360,12 +360,12 @@ it("doesn't update state if action wasn't handled", () => {
const spy = jest.spyOn(console, 'error').mockImplementation();
render(
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator initialRouteName="foo">
<Screen name="foo" component={FooScreen} />
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(onStateChange).toBeCalledTimes(0);
@@ -396,12 +396,12 @@ it('cleans up state when the navigator unmounts', () => {
const onStateChange = jest.fn();
const element = (
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator>
<Screen name="foo" component={FooScreen} />
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
const root = render(element);
@@ -422,7 +422,7 @@ it('cleans up state when the navigator unmounts', () => {
});
root.update(
<NavigationContainer onStateChange={onStateChange} children={null} />
<BaseNavigationContainer onStateChange={onStateChange} children={null} />
);
expect(onStateChange).toBeCalledTimes(2);
@@ -454,12 +454,12 @@ it('allows state updates by dispatching a function returning an action', () => {
const onStateChange = jest.fn();
const element = (
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator initialRouteName="foo">
<Screen name="foo" component={FooScreen} />
<Screen name="bar" component={BarScreen} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element).update(element);
@@ -496,12 +496,12 @@ it('updates route params with setParams', () => {
const onStateChange = jest.fn();
render(
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator initialRouteName="foo">
<Screen name="foo" component={FooScreen} />
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
act(() => setParams({ username: 'alice' }));
@@ -556,7 +556,7 @@ it('updates route params with setParams applied to parent', () => {
const onStateChange = jest.fn();
render(
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator initialRouteName="foo">
<Screen name="foo">
{() => (
@@ -567,7 +567,7 @@ it('updates route params with setParams applied to parent', () => {
</Screen>
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
act(() => setParams({ username: 'alice' }));
@@ -634,22 +634,22 @@ it('handles change in route names', () => {
const onStateChange = jest.fn();
const root = render(
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator initialRouteName="bar">
<Screen name="foo" component={jest.fn()} />
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
root.update(
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<TestNavigator>
<Screen name="foo" component={jest.fn()} />
<Screen name="baz" component={jest.fn()} />
<Screen name="qux" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(onStateChange).toBeCalledWith({
@@ -677,7 +677,7 @@ it('navigates to nested child in a navigator', () => {
const navigation = React.createRef<NavigationContainerRef>();
const element = render(
<NavigationContainer ref={navigation} onStateChange={onStateChange}>
<BaseNavigationContainer ref={navigation} onStateChange={onStateChange}>
<TestNavigator>
<Screen name="foo">
{() => (
@@ -704,7 +704,7 @@ it('navigates to nested child in a navigator', () => {
)}
</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(element).toMatchInlineSnapshot(`"[foo-a, undefined]"`);
@@ -752,11 +752,11 @@ it('gives access to internal state', () => {
};
const root = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator initialRouteName="bar">
<Screen name="bar" component={Test} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(root).update(root);
@@ -778,9 +778,9 @@ it("throws if navigator doesn't have any screens", () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator />
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -812,14 +812,14 @@ it('throws if multiple navigators rendered under one container', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" component={jest.fn()} />
</TestNavigator>
<TestNavigator>
<Screen name="foo" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -836,12 +836,12 @@ it('throws when Screen is not the direct children', () => {
const Bar = () => null;
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" component={jest.fn()} />
<Bar />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -856,12 +856,12 @@ it('throws when a React Element is not the direct children', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" component={jest.fn()} />
Hello world
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -877,7 +877,7 @@ it("doesn't throw when direct children is Screen or empty element", () => {
};
render(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" component={jest.fn()} />
{null}
@@ -885,7 +885,7 @@ it("doesn't throw when direct children is Screen or empty element", () => {
{false}
{true}
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
});
@@ -896,13 +896,13 @@ it('throws when multiple screens with same name are defined', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" component={jest.fn()} />
<Screen name="bar" component={jest.fn()} />
<Screen name="foo" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -917,20 +917,20 @@ it('switches rendered navigators', () => {
};
const root = render(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator key="a">
<Screen name="foo" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() =>
root.update(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator key="b">
<Screen name="foo" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
)
).not.toThrowError(
'Another navigator is already registered for this container.'
@@ -944,11 +944,11 @@ it('throws if no name is passed to Screen', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name={undefined as any} component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -963,11 +963,11 @@ it('throws if invalid name is passed to Screen', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name={[] as any} component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -982,13 +982,13 @@ it('throws if both children and component are passed', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" component={jest.fn()}>
{jest.fn()}
</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -1003,11 +1003,11 @@ it('throws descriptive error for undefined screen component', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" component={undefined as any} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -1022,11 +1022,11 @@ it('throws descriptive error for invalid screen component', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" component={{} as any} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -1041,11 +1041,11 @@ it('throws descriptive error for invalid children', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo">{[] as any}</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
@@ -1060,13 +1060,13 @@ it("doesn't throw if children is null", () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" component={jest.fn()}>
{null as any}
</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(() => render(element).update(element)).not.toThrowError();

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import { render, act } from 'react-native-testing-library';
import useNavigationBuilder from '../useNavigationBuilder';
import NavigationContainer from '../NavigationContainer';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import MockRouter, {
MockActions,
@@ -34,7 +34,7 @@ it('sets options with options prop as an object', () => {
const TestScreen = (): any => 'Test screen';
const root = render(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen
name="foo"
@@ -43,7 +43,7 @@ it('sets options with options prop as an object', () => {
/>
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(root).toMatchInlineSnapshot(`
@@ -79,7 +79,7 @@ it('sets options with options prop as a fuction', () => {
const TestScreen = (): any => 'Test screen';
const root = render(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen
name="foo"
@@ -89,7 +89,7 @@ it('sets options with options prop as a fuction', () => {
/>
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(root).toMatchInlineSnapshot(`
@@ -134,12 +134,12 @@ it('sets options with screenOptions prop as an object', () => {
const TestScreenB = (): any => 'Test screen B';
const root = render(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator screenOptions={{ title: 'Hello world' }}>
<Screen name="foo" component={TestScreenA} />
<Screen name="bar" component={TestScreenB} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(root).toMatchInlineSnapshot(`
@@ -194,7 +194,7 @@ it('sets options with screenOptions prop as a fuction', () => {
const TestScreenB = (): any => 'Test screen B';
const root = render(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator
screenOptions={({ route }: any) => ({
title: `${route.name}: ${route.params.author || route.params.fruit}`,
@@ -211,7 +211,7 @@ it('sets options with screenOptions prop as a fuction', () => {
initialParams={{ fruit: 'Apple' }}
/>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(root).toMatchInlineSnapshot(`
@@ -266,14 +266,14 @@ it('sets initial options with setOptions', () => {
};
const root = render(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" options={{ color: 'blue' }}>
{props => <TestScreen {...props} />}
</Screen>
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(root).toMatchInlineSnapshot(`
@@ -331,14 +331,14 @@ it('updates options with setOptions', () => {
};
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" options={{ color: 'blue' }}>
{props => <TestScreen {...props} />}
</Screen>
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
const root = render(element);
@@ -396,7 +396,7 @@ it("returns correct value for canGoBack when it's not overridden", () => {
};
const root = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen
name="foo"
@@ -405,7 +405,7 @@ it("returns correct value for canGoBack when it's not overridden", () => {
/>
<Screen name="bar" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(root).update(root);
@@ -452,11 +452,11 @@ it(`returns false for canGoBack when current router doesn't handle GO_BACK`, ()
};
const root = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="baz" component={TestScreen} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(root).update(root);
@@ -513,7 +513,7 @@ it('returns true for canGoBack when current router handles GO_BACK', () => {
};
const root = (
<NavigationContainer>
<BaseNavigationContainer>
<ParentNavigator>
<Screen name="baz">
{() => (
@@ -523,7 +523,7 @@ it('returns true for canGoBack when current router handles GO_BACK', () => {
)}
</Screen>
</ParentNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(root).update(root);
@@ -580,7 +580,7 @@ it('returns true for canGoBack when parent router handles GO_BACK', () => {
};
const root = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="baz">
{() => (
@@ -597,7 +597,7 @@ it('returns true for canGoBack when parent router handles GO_BACK', () => {
)}
</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(root).update(root);

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import { render, act } from 'react-native-testing-library';
import useNavigationBuilder from '../useNavigationBuilder';
import NavigationContainer from '../NavigationContainer';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import MockRouter from './__fixtures__/MockRouter';
import { Router, NavigationState } from '../types';
@@ -47,7 +47,7 @@ it('fires focus and blur events in root navigator', () => {
const navigation = React.createRef<any>();
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator ref={navigation}>
<Screen
name="first"
@@ -66,7 +66,7 @@ it('fires focus and blur events in root navigator', () => {
component={createComponent(fourthFocusCallback, fourthBlurCallback)}
/>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element);
@@ -139,7 +139,7 @@ it('fires focus and blur events in nested navigator', () => {
const child = React.createRef<any>();
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator ref={parent}>
<Screen
name="first"
@@ -170,7 +170,7 @@ it('fires focus and blur events in nested navigator', () => {
)}
</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element);
@@ -307,12 +307,12 @@ it('fires blur event when a route is removed with a delay', async () => {
const navigation = React.createRef<any>();
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator ref={navigation}>
<Screen name="first" component={First} />
<Screen name="second" component={Second} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element);
@@ -363,13 +363,13 @@ it('fires custom events', () => {
const ref = React.createRef<any>();
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator ref={ref}>
<Screen name="first" component={createComponent(firstCallback)} />
<Screen name="second" component={createComponent(secondCallback)} />
<Screen name="third" component={createComponent(thirdCallback)} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element);
@@ -444,11 +444,11 @@ it('has option to prevent default', () => {
const ref = React.createRef<any>();
const element = (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator ref={ref}>
<Screen name="first" component={Test} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element);

View File

@@ -2,7 +2,7 @@ import * as React from 'react';
import { render, act } from 'react-native-testing-library';
import useNavigationBuilder from '../useNavigationBuilder';
import useFocusEffect from '../useFocusEffect';
import NavigationContainer from '../NavigationContainer';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import MockRouter from './__fixtures__/MockRouter';
@@ -31,13 +31,13 @@ it('runs focus effect on focus change', () => {
const navigation = React.createRef<any>();
const element = (
<NavigationContainer ref={navigation}>
<BaseNavigationContainer ref={navigation}>
<TestNavigator>
<Screen name="first">{() => null}</Screen>
<Screen name="second" component={Test} />
<Screen name="third">{() => null}</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element);
@@ -84,12 +84,12 @@ it('runs focus effect on deps change', () => {
};
const App = ({ count }: { count: number }) => (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="first">{() => <Test count={count} />}</Screen>
<Screen name="second">{() => null}</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
const root = render(<App count={1} />);
@@ -135,13 +135,13 @@ it('runs focus effect when initial state is given', () => {
const navigation = React.createRef<any>();
const element = (
<NavigationContainer ref={navigation} initialState={initialState}>
<BaseNavigationContainer ref={navigation} initialState={initialState}>
<TestNavigator>
<Screen name="first">{() => null}</Screen>
<Screen name="second">{() => null}</Screen>
<Screen name="third" component={Test} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element);
@@ -178,13 +178,13 @@ it('runs focus effect when only focused route is rendered', () => {
const navigation = React.createRef<any>();
const element = (
<NavigationContainer ref={navigation}>
<BaseNavigationContainer ref={navigation}>
<TestNavigator>
<Screen name="first" component={Test} />
<Screen name="second">{() => null}</Screen>
<Screen name="third">{() => null}</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element);
@@ -221,12 +221,12 @@ it('runs cleanup when component is unmounted', () => {
const TestB = () => null;
const App = ({ mounted }: { mounted: boolean }) => (
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="first" component={mounted ? TestA : TestB} />
<Screen name="second">{() => null}</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
const root = render(<App mounted />);

View File

@@ -2,7 +2,7 @@ import * as React from 'react';
import { render, act } from 'react-native-testing-library';
import useNavigationBuilder from '../useNavigationBuilder';
import useIsFocused from '../useIsFocused';
import NavigationContainer from '../NavigationContainer';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import MockRouter from './__fixtures__/MockRouter';
@@ -24,13 +24,13 @@ it('renders correct focus state', () => {
const navigation = React.createRef<any>();
const root = render(
<NavigationContainer ref={navigation}>
<BaseNavigationContainer ref={navigation}>
<TestNavigator>
<Screen name="first">{() => null}</Screen>
<Screen name="second" component={Test} />
<Screen name="third">{() => null}</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(root).toMatchInlineSnapshot(`"unfocused"`);

View File

@@ -2,7 +2,7 @@ import * as React from 'react';
import { render } from 'react-native-testing-library';
import useNavigationBuilder from '../useNavigationBuilder';
import useNavigation from '../useNavigation';
import NavigationContainer from '../NavigationContainer';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import MockRouter from './__fixtures__/MockRouter';
@@ -24,11 +24,11 @@ it('gets navigation prop from context', () => {
};
render(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" component={Test} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
});
@@ -50,7 +50,7 @@ it("gets navigation's parent from context", () => {
};
render(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo">
{() => (
@@ -60,7 +60,7 @@ it("gets navigation's parent from context", () => {
)}
</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
});
@@ -86,7 +86,7 @@ it("gets navigation's parent's parent from context", () => {
};
render(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo">
{() => (
@@ -102,7 +102,7 @@ it("gets navigation's parent's parent from context", () => {
)}
</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
});

View File

@@ -2,7 +2,7 @@ import * as React from 'react';
import { render, act } from 'react-native-testing-library';
import useNavigationBuilder from '../useNavigationBuilder';
import useNavigationState from '../useNavigationState';
import NavigationContainer from '../NavigationContainer';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import MockRouter from './__fixtures__/MockRouter';
import { NavigationState } from '../types';
@@ -27,13 +27,13 @@ it('gets the current navigation state', () => {
const navigation = React.createRef<any>();
const element = (
<NavigationContainer ref={navigation}>
<BaseNavigationContainer ref={navigation}>
<TestNavigator>
<Screen name="first" component={Test} />
<Screen name="second">{() => null}</Screen>
<Screen name="third">{() => null}</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element);
@@ -78,13 +78,13 @@ it('gets the current navigation state with selector', () => {
const navigation = React.createRef<any>();
const element = (
<NavigationContainer ref={navigation}>
<BaseNavigationContainer ref={navigation}>
<TestNavigator>
<Screen name="first" component={Test} />
<Screen name="second">{() => null}</Screen>
<Screen name="third">{() => null}</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element);
@@ -133,13 +133,13 @@ it('gets the correct value if selector changes', () => {
const App = ({ selector }: { selector: (state: NavigationState) => any }) => {
return (
<SelectorContext.Provider value={selector}>
<NavigationContainer ref={navigation}>
<BaseNavigationContainer ref={navigation}>
<TestNavigator>
<Screen name="first" component={Test} />
<Screen name="second">{() => null}</Screen>
<Screen name="third">{() => null}</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
</SelectorContext.Provider>
);
};

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import { render } from 'react-native-testing-library';
import useNavigationBuilder from '../useNavigationBuilder';
import NavigationContainer from '../NavigationContainer';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import MockRouter, {
MockActions,
@@ -58,7 +58,7 @@ it("lets parent handle the action if child didn't", () => {
const onStateChange = jest.fn();
render(
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<ParentNavigator initialRouteName="baz">
<Screen name="foo">{() => null}</Screen>
<Screen name="bar">{() => null}</Screen>
@@ -70,7 +70,7 @@ it("lets parent handle the action if child didn't", () => {
)}
</Screen>
</ParentNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
expect(onStateChange).toBeCalledTimes(1);
@@ -171,7 +171,7 @@ it("lets children handle the action if parent didn't", () => {
};
const element = (
<NavigationContainer
<BaseNavigationContainer
initialState={initialState}
onStateChange={onStateChange}
>
@@ -187,7 +187,7 @@ it("lets children handle the action if parent didn't", () => {
)}
</Screen>
</ParentNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element).update(element);
@@ -284,7 +284,7 @@ it("action doesn't bubble if target is specified", () => {
const onStateChange = jest.fn();
const element = (
<NavigationContainer onStateChange={onStateChange}>
<BaseNavigationContainer onStateChange={onStateChange}>
<ParentNavigator>
<Screen name="foo">{() => null}</Screen>
<Screen name="bar" component={TestScreen} />
@@ -297,7 +297,7 @@ it("action doesn't bubble if target is specified", () => {
)}
</Screen>
</ParentNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
render(element).update(element);
@@ -349,7 +349,7 @@ it('logs error if no navigator handled the action', () => {
};
const element = (
<NavigationContainer initialState={initialState}>
<BaseNavigationContainer initialState={initialState}>
<TestNavigator>
<Screen name="foo">{() => null}</Screen>
<Screen name="bar" component={TestScreen} />
@@ -362,7 +362,7 @@ it('logs error if no navigator handled the action', () => {
)}
</Screen>
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
const spy = jest.spyOn(console, 'error').mockImplementation();

View File

@@ -2,7 +2,7 @@ import * as React from 'react';
import { render } from 'react-native-testing-library';
import useNavigationBuilder from '../useNavigationBuilder';
import useRoute from '../useRoute';
import NavigationContainer from '../NavigationContainer';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import MockRouter from './__fixtures__/MockRouter';
import { RouteProp } from '../types';
@@ -25,10 +25,10 @@ it('gets route prop from context', () => {
};
render(
<NavigationContainer>
<BaseNavigationContainer>
<TestNavigator>
<Screen name="foo" component={Test} initialParams={{ x: 1 }} />
</TestNavigator>
</NavigationContainer>
</BaseNavigationContainer>
);
});

View File

@@ -9,7 +9,7 @@ type Options = {
[routeName: string]:
| string
| {
path: string;
path?: string;
stringify?: StringifyConfig;
screens?: Options;
};

View File

@@ -8,9 +8,10 @@ type Options = {
[routeName: string]:
| string
| {
path: string;
path?: string;
parse?: ParseConfig;
screens?: Options;
initialRouteName?: string;
};
};
@@ -21,6 +22,11 @@ type RouteConfig = {
parse: ParseConfig | undefined;
};
type InitialRouteConfig = {
initialRouteName: string;
connectedRoutes: string[];
};
type ResultState = PartialState<NavigationState> & {
state?: ResultState;
};
@@ -51,9 +57,12 @@ export default function getStateFromPath(
if (path === '') {
return undefined;
}
let initialRoutes: InitialRouteConfig[] = [];
// Create a normalized configs array which will be easier to use
const configs = ([] as RouteConfig[]).concat(
...Object.keys(options).map(key => createNormalizedConfigs(key, options))
...Object.keys(options).map(key =>
createNormalizedConfigs(key, options, [], initialRoutes)
)
);
let result: PartialState<NavigationState> | undefined;
@@ -65,8 +74,8 @@ export default function getStateFromPath(
.replace(/\?.*/, ''); // Remove query params which we will handle later
while (remaining) {
let routeNames;
let params;
let routeNames: string[] | undefined;
let params: Record<string, any> | undefined;
// Go through all configs, and see if the next path segment matches our regex
for (const config of configs) {
@@ -111,46 +120,43 @@ export default function getStateFromPath(
}
let state: InitialState;
let routeName = routeNames.shift() as string;
let initialRoute = findInitialRoute(routeName, initialRoutes);
if (routeNames.length === 1) {
state = {
routes: [
{ name: routeNames.shift() as string, ...(params && { params }) },
],
};
} else {
state = {
routes: [{ name: routeNames.shift() as string, state: { routes: [] } }],
};
state = createNestedState(
initialRoute,
routeName,
routeNames.length === 0,
params
);
let helper = state.routes[0].state as InitialState;
let routeName;
if (routeNames.length > 0) {
let nestedState = state;
while ((routeName = routeNames.shift())) {
if (routeNames.length === 0) {
helper.routes.push({
name: routeName,
...(params && { params }),
});
} else {
helper.routes[0] = {
name: routeName,
state: {
routes: [],
},
};
helper = helper.routes[0].state as InitialState;
while ((routeName = routeNames.shift() as string)) {
initialRoute = findInitialRoute(routeName, initialRoutes);
nestedState.routes[nestedState.index || 0].state = createNestedState(
initialRoute,
routeName,
routeNames.length === 0,
params
);
if (routeNames.length > 0) {
nestedState = nestedState.routes[nestedState.index || 0]
.state as InitialState;
}
}
}
if (current) {
// The state should be nested inside the deepest route we parsed before
while (current.routes[0].state) {
current = current.routes[0].state;
while (current?.routes[current.index || 0].state) {
current = current.routes[current.index || 0].state;
}
current.routes[0].state = state;
(current as PartialState<NavigationState>).routes[
current?.index || 0
].state = state;
} else {
result = state;
}
@@ -165,12 +171,14 @@ export default function getStateFromPath(
const query = path.split('?')[1];
if (query) {
while (current.routes[0].state) {
while (current?.routes[current.index || 0].state) {
// The query params apply to the deepest route
current = current.routes[0].state;
current = current.routes[current.index || 0].state;
}
const route = current.routes[0];
const route = (current as PartialState<NavigationState>).routes[
current?.index || 0
];
const params = queryString.parse(query);
const parseFunction = findParseConfigForRoute(route.name, configs);
@@ -192,7 +200,8 @@ export default function getStateFromPath(
function createNormalizedConfigs(
key: string,
routeConfig: Options,
routeNames: string[] = []
routeNames: string[] = [],
initials: InitialRouteConfig[]
): RouteConfig[] {
const configs: RouteConfig[] = [];
@@ -205,15 +214,25 @@ function createNormalizedConfigs(
configs.push(createConfigItem(routeNames, value));
} else if (typeof value === 'object') {
// if an object is specified as the value (e.g. Foo: { ... }),
// it has `path` property and
// it can have `path` property and
// it could have `screens` prop which has nested configs
configs.push(createConfigItem(routeNames, value.path, value.parse));
if (value.path) {
configs.push(createConfigItem(routeNames, value.path, value.parse));
}
if (value.screens) {
// property `initialRouteName` without `screens` has no purpose
if (value.initialRouteName) {
initials.push({
initialRouteName: value.initialRouteName,
connectedRoutes: Object.keys(value.screens),
});
}
Object.keys(value.screens).forEach(nestedConfig => {
const result = createNormalizedConfigs(
nestedConfig,
value.screens as Options,
routeNames
routeNames,
initials
);
configs.push(...result);
});
@@ -254,3 +273,55 @@ function findParseConfigForRoute(
}
return undefined;
}
// tries to find an initial route connected with the one passed
function findInitialRoute(
routeName: string,
initialRoutes: InitialRouteConfig[]
): string | undefined {
for (const config of initialRoutes) {
if (config.connectedRoutes.includes(routeName)) {
return config.initialRouteName === routeName
? undefined
: config.initialRouteName;
}
}
return undefined;
}
// returns nested state object with values depending on whether
// it is the end of state and if there is initialRoute for this level
function createNestedState(
initialRoute: string | undefined,
routeName: string,
isEmpty: boolean,
params?: Record<string, any> | undefined
): InitialState {
if (isEmpty) {
if (initialRoute) {
return {
index: 1,
routes: [
{ name: initialRoute },
{ name: routeName as string, ...(params && { params }) },
],
};
} else {
return {
routes: [{ name: routeName as string, ...(params && { params }) }],
};
}
} else {
if (initialRoute) {
return {
index: 1,
routes: [
{ name: initialRoute },
{ name: routeName as string, state: { routes: [] } },
],
};
} else {
return { routes: [{ name: routeName as string, state: { routes: [] } }] };
}
}
}

View File

@@ -3,7 +3,7 @@ import * as CommonActions from './CommonActions';
export { CommonActions };
export { default as BaseRouter } from './BaseRouter';
export { default as NavigationContainer } from './NavigationContainer';
export { default as BaseNavigationContainer } from './BaseNavigationContainer';
export { default as createNavigatorFactory } from './createNavigatorFactory';
export { default as NavigationContext } from './NavigationContext';

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import { isValidElementType } from 'react-is';
import { NavigationStateContext } from './NavigationContainer';
import { NavigationStateContext } from './BaseNavigationContainer';
import NavigationRouteContext from './NavigationRouteContext';
import Screen from './Screen';
import { navigate } from './CommonActions';

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import * as CommonActions from './CommonActions';
import NavigationContext from './NavigationContext';
import { NavigationStateContext } from './NavigationContainer';
import { NavigationStateContext } from './BaseNavigationContainer';
import { NavigationEventEmitter } from './useEventEmitter';
import {
NavigationHelpers,
@@ -51,7 +51,7 @@ export default function useNavigationHelpers<
console.error(
`The action '${payload.type}' with payload '${JSON.stringify(
payload.payload
)}' was not handled by any navigator.`
)}' was not handled by any navigator. If you are trying to navigate to a screen, check if the screen exists in your navigator.`
);
}
});

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.47](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.46...@react-navigation/drawer@5.0.0-alpha.47) (2020-02-04)
**Note:** Version bump only for package @react-navigation/drawer
# [5.0.0-alpha.46](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.45...@react-navigation/drawer@5.0.0-alpha.46) (2020-02-04)
### Features
* disable pan gesture by default in the browser for Apple devices ([b277927](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/b2779279251b1f157ba825cc34e39046b44f00d8)), closes [#287](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/issues/287)
# [5.0.0-alpha.45](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.44...@react-navigation/drawer@5.0.0-alpha.45) (2020-02-03)
**Note:** Version bump only for package @react-navigation/drawer

View File

@@ -11,7 +11,7 @@
"material",
"drawer"
],
"version": "5.0.0-alpha.45",
"version": "5.0.0-alpha.47",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer",
"main": "lib/commonjs/index.js",
@@ -31,7 +31,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.31",
"@react-navigation/routers": "^5.0.0-alpha.33",
"color": "^3.1.2",
"react-native-iphone-x-helper": "^1.2.1"
},

View File

@@ -94,11 +94,30 @@ type Props = {
gestureHandlerProps?: React.ComponentProps<typeof PanGestureHandler>;
};
/**
* Disables the pan gesture by default on Apple devices in the browser.
* https://stackoverflow.com/a/9039885
*/
function shouldEnableGesture(): boolean {
if (
Platform.OS === 'web' &&
typeof navigator !== 'undefined' &&
typeof window !== 'undefined'
) {
const isWebAppleDevice =
/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
return !isWebAppleDevice;
}
return true;
}
export default class DrawerView extends React.PureComponent<Props> {
static defaultProps = {
drawerPostion: I18nManager.isRTL ? 'left' : 'right',
drawerType: 'front',
gestureEnabled: true,
gestureEnabled: shouldEnableGesture(),
swipeEdgeWidth: 32,
swipeVelocityThreshold: 500,
keyboardDismissMode: 'on-drag',

View File

@@ -205,7 +205,7 @@ export default function DrawerView({
<DrawerGestureContext.Provider value={drawerGestureRef}>
<Drawer
open={isDrawerOpen}
gestureEnabled={gestureEnabled !== false}
gestureEnabled={gestureEnabled}
onOpen={handleDrawerOpen}
onClose={handleDrawerClose}
onGestureRef={ref => {

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.42](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.41...@react-navigation/material-bottom-tabs@5.0.0-alpha.42) (2020-02-04)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
# [5.0.0-alpha.41](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.40...@react-navigation/material-bottom-tabs@5.0.0-alpha.41) (2020-02-04)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
# [5.0.0-alpha.40](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.39...@react-navigation/material-bottom-tabs@5.0.0-alpha.40) (2020-02-03)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs

View File

@@ -11,7 +11,7 @@
"material",
"tab"
],
"version": "5.0.0-alpha.40",
"version": "5.0.0-alpha.42",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs",
"main": "lib/commonjs/index.js",
@@ -31,7 +31,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.31"
"@react-navigation/routers": "^5.0.0-alpha.33"
},
"devDependencies": {
"@react-native-community/bob": "^0.8.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.41](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.0-alpha.40...@react-navigation/material-top-tabs@5.0.0-alpha.41) (2020-02-04)
**Note:** Version bump only for package @react-navigation/material-top-tabs
# [5.0.0-alpha.40](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.0-alpha.39...@react-navigation/material-top-tabs@5.0.0-alpha.40) (2020-02-04)
**Note:** Version bump only for package @react-navigation/material-top-tabs
# [5.0.0-alpha.39](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.0-alpha.38...@react-navigation/material-top-tabs@5.0.0-alpha.39) (2020-02-03)
**Note:** Version bump only for package @react-navigation/material-top-tabs

View File

@@ -11,7 +11,7 @@
"material",
"tab"
],
"version": "5.0.0-alpha.39",
"version": "5.0.0-alpha.41",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/material-top-tabs",
"main": "lib/commonjs/index.js",
@@ -31,7 +31,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.31",
"@react-navigation/routers": "^5.0.0-alpha.33",
"color": "^3.1.2"
},
"devDependencies": {

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.35](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.34...@react-navigation/native-stack@5.0.0-alpha.35) (2020-02-04)
**Note:** Version bump only for package @react-navigation/native-stack
# [5.0.0-alpha.34](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.33...@react-navigation/native-stack@5.0.0-alpha.34) (2020-02-04)
**Note:** Version bump only for package @react-navigation/native-stack
# [5.0.0-alpha.33](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.32...@react-navigation/native-stack@5.0.0-alpha.33) (2020-02-03)
**Note:** Version bump only for package @react-navigation/native-stack

View File

@@ -6,7 +6,7 @@
"react-native",
"react-navigation"
],
"version": "5.0.0-alpha.33",
"version": "5.0.0-alpha.35",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack",
"main": "lib/commonjs/index.js",
@@ -26,7 +26,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.31"
"@react-navigation/routers": "^5.0.0-alpha.33"
},
"devDependencies": {
"@react-native-community/bob": "^0.8.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.35](https://github.com/react-navigation/navigation-ex/tree/master/packages/native/compare/@react-navigation/native@5.0.0-alpha.34...@react-navigation/native@5.0.0-alpha.35) (2020-02-04)
**Note:** Version bump only for package @react-navigation/native
# [5.0.0-alpha.34](https://github.com/react-navigation/navigation-ex/tree/master/packages/native/compare/@react-navigation/native@5.0.0-alpha.33...@react-navigation/native@5.0.0-alpha.34) (2020-02-04)
**Note:** Version bump only for package @react-navigation/native
# [5.0.0-alpha.33](https://github.com/react-navigation/navigation-ex/tree/master/packages/native/compare/@react-navigation/native@5.0.0-alpha.32...@react-navigation/native@5.0.0-alpha.33) (2020-02-03)
**Note:** Version bump only for package @react-navigation/native

View File

@@ -7,7 +7,7 @@
"ios",
"android"
],
"version": "5.0.0-alpha.33",
"version": "5.0.0-alpha.35",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/native",
"main": "lib/commonjs/index.js",
@@ -27,7 +27,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/core": "^5.0.0-alpha.41"
"@react-navigation/core": "^5.0.0-alpha.43"
},
"devDependencies": {
"@react-native-community/bob": "^0.8.0",

View File

@@ -0,0 +1,44 @@
import * as React from 'react';
import {
BaseNavigationContainer,
NavigationContainerProps,
NavigationContainerRef,
} from '@react-navigation/core';
import ThemeProvider from './theming/ThemeProvider';
import DefaultTheme from './theming/DefaultTheme';
import useBackButton from './useBackButton';
import { Theme } from './types';
type Props = NavigationContainerProps & {
theme?: Theme;
};
/**
* Container component which holds the navigation state
* designed for mobile apps.
* This should be rendered at the root wrapping the whole app.
*
* @param props.initialState Initial state object for the navigation tree.
* @param props.onStateChange Callback which is called with the latest navigation state when it changes.
* @param props.theme Theme object for the navigators.
* @param props.children Child elements to render the content.
* @param props.ref Ref object which refers to the navigation object containing helper methods.
*/
const NavigationContainer = React.forwardRef(function NavigationContainer(
{ theme = DefaultTheme, ...rest }: Props,
ref: React.Ref<NavigationContainerRef>
) {
const refContainer = React.useRef<NavigationContainerRef>(null);
useBackButton(refContainer);
React.useImperativeHandle(ref, () => refContainer.current);
return (
<ThemeProvider value={theme}>
<BaseNavigationContainer {...rest} ref={refContainer} />
</ThemeProvider>
);
});
export default NavigationContainer;

View File

@@ -1,44 +1,5 @@
import * as React from 'react';
import {
NavigationContainer,
NavigationContainerProps,
NavigationContainerRef,
} from '@react-navigation/core';
import ThemeProvider from './theming/ThemeProvider';
import DefaultTheme from './theming/DefaultTheme';
import useBackButton from './useBackButton';
import { Theme } from './types';
type Props = NavigationContainerProps & {
theme?: Theme;
};
/**
* Container component which holds the navigation state
* designed for mobile apps.
* This should be rendered at the root wrapping the whole app.
*
* @param props.initialState Initial state object for the navigation tree.
* @param props.onStateChange Callback which is called with the latest navigation state when it changes.
* @param props.theme Theme object for the navigators.
* @param props.children Child elements to render the content.
* @param props.ref Ref object which refers to the navigation object containing helper methods.
*/
const NavigationNativeContainer = React.forwardRef(function NativeContainer(
{ theme = DefaultTheme, ...rest }: Props,
ref: React.Ref<NavigationContainerRef>
) {
const refContainer = React.useRef<NavigationContainerRef>(null);
useBackButton(refContainer);
React.useImperativeHandle(ref, () => refContainer.current);
return (
<ThemeProvider value={theme}>
<NavigationContainer {...rest} ref={refContainer} />
</ThemeProvider>
export default function() {
throw new Error(
"'NavigationNativeContainer' has been renamed to 'NavigationContainer"
);
});
export default NavigationNativeContainer;
}

View File

@@ -1,5 +1,6 @@
export * from '@react-navigation/core';
export { default as NavigationContainer } from './NavigationContainer';
export { default as NavigationNativeContainer } from './NavigationNativeContainer';
export { default as useBackButton } from './useBackButton';

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.33](https://github.com/react-navigation/navigation-ex/tree/master/packages/routers/compare/@react-navigation/routers@5.0.0-alpha.32...@react-navigation/routers@5.0.0-alpha.33) (2020-02-04)
**Note:** Version bump only for package @react-navigation/routers
# [5.0.0-alpha.32](https://github.com/react-navigation/navigation-ex/tree/master/packages/routers/compare/@react-navigation/routers@5.0.0-alpha.31...@react-navigation/routers@5.0.0-alpha.32) (2020-02-04)
**Note:** Version bump only for package @react-navigation/routers
# [5.0.0-alpha.31](https://github.com/react-navigation/navigation-ex/tree/master/packages/routers/compare/@react-navigation/routers@5.0.0-alpha.30...@react-navigation/routers@5.0.0-alpha.31) (2020-02-03)
**Note:** Version bump only for package @react-navigation/routers

View File

@@ -6,7 +6,7 @@
"react-native",
"react-navigation"
],
"version": "5.0.0-alpha.31",
"version": "5.0.0-alpha.33",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/routers",
"main": "lib/commonjs/index.js",
@@ -26,7 +26,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/core": "^5.0.0-alpha.41",
"@react-navigation/core": "^5.0.0-alpha.43",
"shortid": "^2.2.15"
},
"devDependencies": {

View File

@@ -3,6 +3,33 @@
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.70](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack/compare/@react-navigation/stack@5.0.0-alpha.69...@react-navigation/stack@5.0.0-alpha.70) (2020-02-04)
**Note:** Version bump only for package @react-navigation/stack
# [5.0.0-alpha.69](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack/compare/@react-navigation/stack@5.0.0-alpha.68...@react-navigation/stack@5.0.0-alpha.69) (2020-02-04)
**Note:** Version bump only for package @react-navigation/stack
# [5.0.0-alpha.68](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack/compare/@react-navigation/stack@5.0.0-alpha.67...@react-navigation/stack@5.0.0-alpha.68) (2020-02-03)
### Bug Fixes
* use .native for masked view instead of .web ([abdf9d1](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack/commit/abdf9d12b5c3fbde6414b50e3b6e082b67899772))
# [5.0.0-alpha.67](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack/compare/@react-navigation/stack@5.0.0-alpha.66...@react-navigation/stack@5.0.0-alpha.67) (2020-02-03)
**Note:** Version bump only for package @react-navigation/stack

View File

@@ -10,7 +10,7 @@
"android",
"stack"
],
"version": "5.0.0-alpha.67",
"version": "5.0.0-alpha.70",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/stack",
"main": "lib/commonjs/index.js",
@@ -30,7 +30,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.31",
"@react-navigation/routers": "^5.0.0-alpha.33",
"color": "^3.1.2",
"react-native-iphone-x-helper": "^1.2.1"
},

View File

@@ -0,0 +1,19 @@
import * as React from 'react';
import { UIManager } from 'react-native';
import RNCMaskedView from '@react-native-community/masked-view';
type Props = React.ComponentProps<typeof RNCMaskedView> & {
children: React.ReactElement;
};
const isMaskedViewAvailable =
// @ts-ignore
UIManager.getViewManagerConfig('RNCMaskedView') != null;
export default function MaskedView({ children, ...rest }: Props) {
if (isMaskedViewAvailable) {
return <RNCMaskedView {...rest}>{children}</RNCMaskedView>;
}
return children;
}

View File

@@ -1,19 +1,10 @@
import * as React from 'react';
import { UIManager } from 'react-native';
import RNCMaskedView from '@react-native-community/masked-view';
type Props = React.ComponentProps<typeof RNCMaskedView> & {
type Props = {
maskElement: React.ReactElement;
children: React.ReactElement;
};
const isMaskedViewAvailable =
// @ts-ignore
UIManager.getViewManagerConfig('RNCMaskedView') != null;
export default function MaskedView({ children, ...rest }: Props) {
if (isMaskedViewAvailable) {
return <RNCMaskedView {...rest}>{children}</RNCMaskedView>;
}
export default function MaskedView({ children }: Props) {
return children;
}

View File

@@ -1,9 +0,0 @@
import * as React from 'react';
type Props = {
children: React.ReactElement;
};
export default function MaskedView({ children }: Props) {
return children;
}