Compare commits

..

1 Commits

Author SHA1 Message Date
Satyajit Sahoo
f483970625 chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.41
 - @react-navigation/compat@5.0.0-alpha.30
 - @react-navigation/core@5.0.0-alpha.39
 - @react-navigation/drawer@5.0.0-alpha.43
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.38
 - @react-navigation/material-top-tabs@5.0.0-alpha.37
 - @react-navigation/native-stack@5.0.0-alpha.31
 - @react-navigation/native@5.0.0-alpha.31
 - @react-navigation/routers@5.0.0-alpha.29
 - @react-navigation/stack@5.0.0-alpha.65
2020-02-03 00:29:10 +01:00
54 changed files with 624 additions and 1305 deletions

1
.gitattributes vendored Normal file
View File

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

View File

@@ -5,7 +5,6 @@ jobs:
publish: publish:
name: Install and publish name: Install and publish
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.owner.login == 'react-navigation'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v1 uses: actions/checkout@v1
@@ -51,4 +50,4 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
msg: The Expo app for the example from this branch is ready!<br><br>[expo.io/${{ steps.expo.outputs.path }}](https://expo.io/${{ steps.expo.outputs.path }})<br><br><a href="https://exp.host/${{ steps.expo.outputs.path }}"><img src="https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=exp://exp.host/${{ steps.expo.outputs.path }}" height="200px" width="200px"></a>. msg: The Expo app for the example from this branch is ready!<br><br>[expo.io/${{ steps.expo.outputs.path }}](https://expo.io/${{ steps.expo.outputs.path }})<br><br><a href="https://exp.host/${{ steps.expo.outputs.path }}"><img src="https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=exp://exp.host/${{ steps.expo.outputs.path }}" height="200px" width="200px"></a>.

View File

@@ -5,5 +5,3 @@ If you want to run the example from the repo,
- Clone the repository and run `yarn` in the project root - Clone the repository and run `yarn` in the project root
- Run `yarn example start` to start the packager - Run `yarn example start` to start the packager
- Follow the instructions to open it with the [Expo app](https://expo.io/) - Follow the instructions to open it with the [Expo app](https://expo.io/)
You can also run the currently published [app on Expo](https://expo.io/@react-navigation/react-navigation-example) on your Android device or iOS simulator or the [web app](https://react-navigation-example.netlify.com/) in your browser.

View File

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

View File

@@ -3,31 +3,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.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) # [5.0.0-alpha.41](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.39...@react-navigation/bottom-tabs@5.0.0-alpha.41) (2020-02-02)
**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
# [5.0.0-alpha.42](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.39...@react-navigation/bottom-tabs@5.0.0-alpha.42) (2020-02-02)
### Bug Fixes ### Bug Fixes

View File

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

View File

@@ -3,31 +3,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.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) # [5.0.0-alpha.30](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.28...@react-navigation/compat@5.0.0-alpha.30) (2020-02-02)
**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
# [5.0.0-alpha.31](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.28...@react-navigation/compat@5.0.0-alpha.31) (2020-02-02)
### Bug Fixes ### Bug Fixes

View File

@@ -1,7 +1,7 @@
{ {
"name": "@react-navigation/compat", "name": "@react-navigation/compat",
"description": "Compatibility layer to write navigator definitions in static configuration format", "description": "Compatibility layer to write navigator definitions in static configuration format",
"version": "5.0.0-alpha.34", "version": "5.0.0-alpha.30",
"license": "MIT", "license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/compat", "repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/compat",
"main": "lib/commonjs/index.js", "main": "lib/commonjs/index.js",
@@ -21,7 +21,7 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.33" "@react-navigation/routers": "^5.0.0-alpha.29"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^16.9.17", "@types/react": "^16.9.17",

View File

@@ -3,42 +3,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.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) # [5.0.0-alpha.39](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.37...@react-navigation/core@5.0.0-alpha.39) (2020-02-02)
### 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)
### Bug Fixes
* ignore circular references when checking serializable ([e5063b9](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/e5063b93398350511f3fd2ef48425559f871781f))
# [5.0.0-alpha.40](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.37...@react-navigation/core@5.0.0-alpha.40) (2020-02-02)
### Bug Fixes ### Bug Fixes

View File

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

View File

@@ -1,300 +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 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

@@ -0,0 +1,295 @@
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 * as React from 'react';
import { NavigationStateContext } from './BaseNavigationContainer'; import { NavigationStateContext } from './NavigationContainer';
import NavigationContext from './NavigationContext'; import NavigationContext from './NavigationContext';
import NavigationRouteContext from './NavigationRouteContext'; import NavigationRouteContext from './NavigationRouteContext';
import StaticContainer from './StaticContainer'; import StaticContainer from './StaticContainer';

View File

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

View File

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

View File

@@ -394,6 +394,13 @@ it('handles parse in nested object for second route depth and and path and parse
screens: { screens: {
Foe: 'foe', Foe: 'foe',
Bar: { Bar: {
path: 'bar/:id',
parse: {
id: Number,
},
stringify: {
id: (id: number) => `id=${id}`,
},
screens: { screens: {
Baz: 'baz', Baz: 'baz',
}, },
@@ -426,260 +433,24 @@ it('handles parse in nested object for second route depth and and path and parse
); );
}); });
it('handles initialRouteName', () => {
const path = '/baz';
const config = {
Foo: {
initialRouteName: 'Foe',
screens: {
Foe: 'foe',
Bar: {
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: {
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', () => { it('returns undefined if path is empty', () => {
const config = { const config = {
Foo: { Foo: {
path: 'foo/:id',
starting: true,
stringify: {
id: (id: number) => `id=${id}`,
},
screens: { screens: {
Foe: 'foe', Foe: 'foe',
Bar: { Bar: {
path: 'bar/:id',
parse: {
id: Number,
},
stringify: {
id: (id: number) => `id=${id}`,
},
screens: { screens: {
Baz: 'baz', Baz: 'baz',
}, },

View File

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

View File

@@ -1,70 +0,0 @@
import isSerializable from '../isSerializable';
it('returns true for serializable object', () => {
expect(
isSerializable({
index: 0,
key: '7',
routeNames: ['foo', 'bar'],
routes: [
{
key: 'foo',
name: 'foo',
state: {
index: 0,
key: '8',
routeNames: ['qux', 'lex'],
routes: [
{ key: 'qux', name: 'qux' },
{ key: 'lex', name: 'lex' },
],
},
},
],
})
).toBe(true);
});
it('returns false for non-serializable object', () => {
expect(
isSerializable({
index: 0,
key: '7',
routeNames: ['foo', 'bar'],
routes: [
{
key: 'foo',
name: 'foo',
state: {
index: 0,
key: '8',
routeNames: ['qux', 'lex'],
routes: [
{ key: 'qux', name: 'qux', params: () => 42 },
{ key: 'lex', name: 'lex' },
],
},
},
],
})
).toBe(false);
});
it('returns false for circular references', () => {
const o = {
index: 0,
key: '7',
routeNames: ['foo', 'bar'],
routes: [
{
key: 'foo',
name: 'foo',
},
],
};
// @ts-ignore
o.routes[0].state = o;
expect(isSerializable(o)).toBe(false);
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,4 @@
const isSerializableWithoutCircularReference = ( export default function isSerializable(o: { [key: string]: any }): boolean {
o: { [key: string]: any },
seen = new Set<any>()
): boolean => {
if ( if (
o === undefined || o === undefined ||
o === null || o === null ||
@@ -19,29 +16,19 @@ const isSerializableWithoutCircularReference = (
return false; return false;
} }
if (seen.has(o)) {
return false;
}
seen.add(o);
if (Array.isArray(o)) { if (Array.isArray(o)) {
for (const it of o) { for (const it of o) {
if (!isSerializableWithoutCircularReference(it, seen)) { if (!isSerializable(it)) {
return false; return false;
} }
} }
} else { } else {
for (const key in o) { for (const key in o) {
if (!isSerializableWithoutCircularReference(o[key], seen)) { if (!isSerializable(o[key])) {
return false; return false;
} }
} }
} }
return true; return true;
};
export default function isSerializable(o: { [key: string]: any }) {
return isSerializableWithoutCircularReference(o);
} }

View File

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

View File

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

View File

@@ -3,34 +3,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.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) # [5.0.0-alpha.43](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.41...@react-navigation/drawer@5.0.0-alpha.43) (2020-02-02)
**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
# [5.0.0-alpha.44](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.41...@react-navigation/drawer@5.0.0-alpha.44) (2020-02-02)
### Bug Fixes ### Bug Fixes

View File

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

View File

@@ -94,30 +94,11 @@ type Props = {
gestureHandlerProps?: React.ComponentProps<typeof PanGestureHandler>; 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> { export default class DrawerView extends React.PureComponent<Props> {
static defaultProps = { static defaultProps = {
drawerPostion: I18nManager.isRTL ? 'left' : 'right', drawerPostion: I18nManager.isRTL ? 'left' : 'right',
drawerType: 'front', drawerType: 'front',
gestureEnabled: shouldEnableGesture(), gestureEnabled: true,
swipeEdgeWidth: 32, swipeEdgeWidth: 32,
swipeVelocityThreshold: 500, swipeVelocityThreshold: 500,
keyboardDismissMode: 'on-drag', keyboardDismissMode: 'on-drag',

View File

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

View File

@@ -3,31 +3,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.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) # [5.0.0-alpha.38](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.36...@react-navigation/material-bottom-tabs@5.0.0-alpha.38) (2020-02-02)
**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
# [5.0.0-alpha.39](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.36...@react-navigation/material-bottom-tabs@5.0.0-alpha.39) (2020-02-02)
### Bug Fixes ### Bug Fixes

View File

@@ -11,7 +11,7 @@
"material", "material",
"tab" "tab"
], ],
"version": "5.0.0-alpha.42", "version": "5.0.0-alpha.38",
"license": "MIT", "license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs", "repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs",
"main": "lib/commonjs/index.js", "main": "lib/commonjs/index.js",
@@ -31,7 +31,7 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.33" "@react-navigation/routers": "^5.0.0-alpha.29"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.8.0", "@react-native-community/bob": "^0.8.0",

View File

@@ -3,31 +3,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.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) # [5.0.0-alpha.37](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.0-alpha.35...@react-navigation/material-top-tabs@5.0.0-alpha.37) (2020-02-02)
**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
# [5.0.0-alpha.38](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.0-alpha.35...@react-navigation/material-top-tabs@5.0.0-alpha.38) (2020-02-02)
### Bug Fixes ### Bug Fixes

View File

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

View File

@@ -3,31 +3,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.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) # [5.0.0-alpha.31](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.29...@react-navigation/native-stack@5.0.0-alpha.31) (2020-02-02)
**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
# [5.0.0-alpha.32](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.29...@react-navigation/native-stack@5.0.0-alpha.32) (2020-02-02)
### Bug Fixes ### Bug Fixes

View File

@@ -6,7 +6,7 @@
"react-native", "react-native",
"react-navigation" "react-navigation"
], ],
"version": "5.0.0-alpha.35", "version": "5.0.0-alpha.31",
"license": "MIT", "license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack", "repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack",
"main": "lib/commonjs/index.js", "main": "lib/commonjs/index.js",
@@ -26,7 +26,7 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.33" "@react-navigation/routers": "^5.0.0-alpha.29"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.8.0", "@react-native-community/bob": "^0.8.0",

View File

@@ -3,31 +3,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.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) # [5.0.0-alpha.31](https://github.com/react-navigation/navigation-ex/tree/master/packages/native/compare/@react-navigation/native@5.0.0-alpha.29...@react-navigation/native@5.0.0-alpha.31) (2020-02-02)
**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
# [5.0.0-alpha.32](https://github.com/react-navigation/navigation-ex/tree/master/packages/native/compare/@react-navigation/native@5.0.0-alpha.29...@react-navigation/native@5.0.0-alpha.32) (2020-02-02)
### Bug Fixes ### Bug Fixes

View File

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

View File

@@ -1,44 +0,0 @@
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,5 +1,44 @@
export default function() { import * as React from 'react';
throw new Error( import {
"'NavigationNativeContainer' has been renamed to 'NavigationContainer" 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 NavigationNativeContainer;

View File

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

View File

@@ -3,31 +3,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.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) # [5.0.0-alpha.29](https://github.com/react-navigation/navigation-ex/tree/master/packages/routers/compare/@react-navigation/routers@5.0.0-alpha.27...@react-navigation/routers@5.0.0-alpha.29) (2020-02-02)
**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
# [5.0.0-alpha.30](https://github.com/react-navigation/navigation-ex/tree/master/packages/routers/compare/@react-navigation/routers@5.0.0-alpha.27...@react-navigation/routers@5.0.0-alpha.30) (2020-02-02)
### Bug Fixes ### Bug Fixes

View File

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

View File

@@ -3,42 +3,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.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) # [5.0.0-alpha.65](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack/compare/@react-navigation/stack@5.0.0-alpha.63...@react-navigation/stack@5.0.0-alpha.65) (2020-02-02)
**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
# [5.0.0-alpha.66](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack/compare/@react-navigation/stack@5.0.0-alpha.63...@react-navigation/stack@5.0.0-alpha.66) (2020-02-02)
### Bug Fixes ### Bug Fixes

View File

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

View File

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

View File

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