Compare commits

...

29 Commits

Author SHA1 Message Date
satyajit.happy
8318c49331 chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.11
 - @react-navigation/compat@5.0.0-alpha.5
 - @react-navigation/core@5.0.0-alpha.12
 - @react-navigation/drawer@5.0.0-alpha.11
 - @react-navigation/example@5.0.0-alpha.9
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.10
 - @react-navigation/material-top-tabs@5.0.0-alpha.9
 - @react-navigation/native@5.0.0-alpha.9
 - @react-navigation/routers@5.0.0-alpha.9
 - @react-navigation/stack@5.0.0-alpha.21
2019-10-03 19:47:41 +02:00
satyajit.happy
ece6e3899e fix: add missing React import 2019-10-03 19:07:56 +02:00
satyajit.happy
da944ccef9 fix: fix header buttons not clickable on Android. fixes #108 2019-10-03 19:07:21 +02:00
satyajit.happy
bc3586ae3e fix: keep the routes we are closing or replacing 2019-10-03 18:44:18 +02:00
satyajit.happy
19be2b4bbc fix: don't throw when switching navigator. fixes #91 2019-10-03 17:51:13 +02:00
satyajit.happy
a8851b730d chore: upgrade deps 2019-10-03 17:35:24 +02:00
Michał Osadnik
7a5bcb446b feat: add a getRootState method (#119) 2019-10-01 23:17:28 +02:00
satyajit.happy
1345a8fec6 chore: upgrade eslint config 2019-09-28 11:58:21 +02:00
satyajit.happy
7393464515 fix: don't merge state with existing state during reset. fixes #111 2019-09-28 11:49:45 +02:00
osdnk
9810a06061 chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.10
 - @react-navigation/compat@5.0.0-alpha.4
 - @react-navigation/core@5.0.0-alpha.11
 - @react-navigation/drawer@5.0.0-alpha.10
 - @react-navigation/example@5.0.0-alpha.8
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.9
 - @react-navigation/material-top-tabs@5.0.0-alpha.8
 - @react-navigation/routers@5.0.0-alpha.8
 - @react-navigation/stack@5.0.0-alpha.20
2019-09-27 17:30:35 +02:00
osdnk
655a220137 fix: close drawer on navigate 2019-09-27 17:29:59 +02:00
satyajit.happy
e61f5941d7 feat: add a method to reset root navigator state 2019-09-26 16:34:34 +02:00
satyajit.happy
8b78d617c0 feat: export some more type aliases 2019-09-25 23:09:58 +02:00
Dulmandakh
1fd5a868a3 feat: export BottomTabBar props type (#109) 2019-09-25 16:41:40 +02:00
satyajit.happy
1153d5575b fix: fire blur event when a route is removed with a delay
closes #110
2019-09-24 20:27:54 +02:00
osdnk
76de32f441 chore: publish
- @react-navigation/stack@5.0.0-alpha.19
2019-09-23 18:26:26 +02:00
osdnk
4ee19bcdb9 fix: vertical gesture in stack 2019-09-23 18:25:06 +02:00
satyajit.happy
06cc8b9142 chore: publish
- @react-navigation/compat@5.0.0-alpha.3
 - @react-navigation/stack@5.0.0-alpha.18
2019-09-23 17:26:27 +02:00
satyajit.happy
2f66556b10 fix: fix header rendered behind card. closes #108 2019-09-23 17:24:43 +02:00
Dulmandakh
f39813626a feat(stack): use Animated.Text for header title (#105) 2019-09-21 17:55:11 +02:00
Dulmandakh
089390ce87 feat(stack): use Animated.View for header background (#106) 2019-09-21 17:54:21 +02:00
Dulmandakh
d09c9ae643 refactor(stack): convert Header component to function (#104) 2019-09-21 17:53:44 +02:00
satyajit.happy
8920da68a7 fix: throw when wrapping a compat navigatofor compat 2019-09-19 14:57:31 +02:00
satyajit.happy
98a9487cda chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.9
 - @react-navigation/compat@5.0.0-alpha.2
 - @react-navigation/core@5.0.0-alpha.10
 - @react-navigation/stack@5.0.0-alpha.17
2019-09-17 18:44:55 +02:00
satyajit.happy
ff502820c7 feat: add createSwitchNavigator 2019-09-17 18:32:07 +02:00
satyajit.happy
30e510d123 fix: provide navigation prop in header 2019-09-17 18:13:42 +02:00
satyajit.happy
114a5dc888 feat: add withNavigation and withNavigationFocus 2019-09-17 17:57:01 +02:00
Ryan Stelly
b4bbf9b0c3 fix: add fallbacks for non-web modules
closes #95, #96
2019-09-17 16:58:17 +02:00
satyajit.happy
98f0de088f refactor: make dispatch accept thunks 2019-09-17 13:05:45 +02:00
91 changed files with 3030 additions and 1569 deletions

View File

@@ -1,14 +0,0 @@
{
"git": {
"commitMessage": "chore: release %s",
"tagName": "v%s"
},
"github": {
"release": true
},
"plugins": {
"@release-it/conventional-changelog": {
"preset": "angular"
}
}
}

View File

@@ -1,5 +1,3 @@
/* eslint-disable import/no-commonjs */
module.exports = { module.exports = {
presets: [ presets: [
[ [

View File

@@ -1,5 +1,3 @@
/* eslint-disable import/no-commonjs */
module.exports = { module.exports = {
extends: ['@commitlint/config-conventional'], extends: ['@commitlint/config-conventional'],
}; };

View File

@@ -23,22 +23,22 @@
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.5.5", "@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/preset-env": "^7.5.5", "@babel/preset-env": "^7.6.2",
"@babel/preset-react": "^7.0.0", "@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.3.3", "@babel/preset-typescript": "^7.6.0",
"@babel/runtime": "^7.5.5", "@babel/runtime": "^7.6.2",
"@commitlint/config-conventional": "^8.0.0", "@commitlint/config-conventional": "^8.2.0",
"@types/jest": "^24.0.13", "@types/jest": "^24.0.13",
"codecov": "^3.5.0", "codecov": "^3.6.1",
"commitlint": "^8.0.0", "commitlint": "^8.2.0",
"core-js": "^3.2.1", "core-js": "^3.2.1",
"eslint": "^5.16.0", "eslint": "^6.5.1",
"eslint-config-satya164": "^2.4.1", "eslint-config-satya164": "^3.1.2",
"husky": "^2.4.0", "husky": "^3.0.8",
"jest": "^24.8.0", "jest": "^24.8.0",
"lerna": "^3.16.4", "lerna": "^3.16.4",
"prettier": "^1.18.2", "prettier": "^1.18.2",
"typescript": "^3.5.3" "typescript": "^3.6.3"
}, },
"resolutions": { "resolutions": {
"react": "16.8.3", "react": "16.8.3",

View File

@@ -3,6 +3,37 @@
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.11](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.10...@react-navigation/bottom-tabs@5.0.0-alpha.11) (2019-10-03)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [5.0.0-alpha.10](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.9...@react-navigation/bottom-tabs@5.0.0-alpha.10) (2019-09-27)
### Features
* export BottomTabBar props type ([#109](https://github.com/react-navigation/navigation-ex/issues/109)) ([1fd5a86](https://github.com/react-navigation/navigation-ex/commit/1fd5a86))
* export some more type aliases ([8b78d61](https://github.com/react-navigation/navigation-ex/commit/8b78d61))
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.8...@react-navigation/bottom-tabs@5.0.0-alpha.9) (2019-09-17)
### Bug Fixes
* provide navigation prop in header ([30e510d](https://github.com/react-navigation/navigation-ex/commit/30e510d))
# [5.0.0-alpha.8](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.7...@react-navigation/bottom-tabs@5.0.0-alpha.8) (2019-09-16) # [5.0.0-alpha.8](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.7...@react-navigation/bottom-tabs@5.0.0-alpha.8) (2019-09-16)

View File

@@ -10,7 +10,7 @@
"android", "android",
"tab" "tab"
], ],
"version": "5.0.0-alpha.8", "version": "5.0.0-alpha.11",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -33,17 +33,17 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.7", "@react-navigation/routers": "^5.0.0-alpha.9",
"react-native-safe-area-view": "^0.14.6" "react-native-safe-area-view": "^0.14.7"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.7.0", "@react-native-community/bob": "^0.7.0",
"@types/react": "^16.8.24", "@types/react": "^16.9.4",
"@types/react-native": "^0.60.2", "@types/react-native": "^0.60.17",
"del-cli": "^2.0.0", "del-cli": "^3.0.0",
"react": "16.8.3", "react": "16.8.3",
"react-native": "0.59.10", "react-native": "0.59.10",
"typescript": "^3.5.3" "typescript": "^3.6.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0", "@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -13,4 +13,9 @@ export { default as BottomTabBar } from './views/BottomTabBar';
/** /**
* Types * Types
*/ */
export { BottomTabNavigationOptions, BottomTabNavigationProp } from './types'; export {
BottomTabNavigationOptions,
BottomTabNavigationProp,
BottomTabBarProps,
BottomTabBarOptions,
} from './types';

View File

@@ -199,6 +199,7 @@ export type BottomTabBarOptions = {
export type BottomTabBarProps = BottomTabBarOptions & { export type BottomTabBarProps = BottomTabBarOptions & {
state: TabNavigationState; state: TabNavigationState;
descriptors: BottomTabDescriptorMap;
navigation: NavigationHelpers<ParamListBase>; navigation: NavigationHelpers<ParamListBase>;
onTabPress: (props: { route: Route<string> }) => void; onTabPress: (props: { route: Route<string> }) => void;
onTabLongPress: (props: { route: Route<string> }) => void; onTabLongPress: (props: { route: Route<string> }) => void;
@@ -231,5 +232,7 @@ export type BottomTabBarProps = BottomTabBarOptions & {
tintColor: string; tintColor: string;
horizontal: boolean; horizontal: boolean;
}) => React.ReactNode; }) => React.ReactNode;
activeTintColor: string;
inactiveTintColor: string;
safeAreaInset?: React.ComponentProps<typeof SafeAreaView>['forceInset']; safeAreaInset?: React.ComponentProps<typeof SafeAreaView>['forceInset'];
}; };

View File

@@ -9,7 +9,7 @@ import {
Dimensions, Dimensions,
} from 'react-native'; } from 'react-native';
import SafeAreaView from 'react-native-safe-area-view'; import SafeAreaView from 'react-native-safe-area-view';
import { Route } from '@react-navigation/core'; import { Route, NavigationContext } from '@react-navigation/core';
import TabBarIcon from './TabBarIcon'; import TabBarIcon from './TabBarIcon';
import TouchableWithoutFeedbackWrapper from './TouchableWithoutFeedbackWrapper'; import TouchableWithoutFeedbackWrapper from './TouchableWithoutFeedbackWrapper';
@@ -23,8 +23,6 @@ type State = {
}; };
type Props = BottomTabBarProps & { type Props = BottomTabBarProps & {
activeTintColor: string;
inactiveTintColor: string;
safeAreaInset: React.ComponentProps<typeof SafeAreaView>['forceInset']; safeAreaInset: React.ComponentProps<typeof SafeAreaView>['forceInset'];
}; };
@@ -261,6 +259,7 @@ export default class TabBarBottom extends React.Component<Props, State> {
render() { render() {
const { const {
state, state,
descriptors,
keyboardHidesTabBar, keyboardHidesTabBar,
activeBackgroundColor, activeBackgroundColor,
inactiveBackgroundColor, inactiveBackgroundColor,
@@ -291,8 +290,7 @@ export default class TabBarBottom extends React.Component<Props, State> {
style={[ style={[
styles.container, styles.container,
keyboardHidesTabBar keyboardHidesTabBar
? // eslint-disable-next-line react-native/no-inline-styles ? {
{
// When the keyboard is shown, slide down the tab bar // When the keyboard is shown, slide down the tab bar
transform: [ transform: [
{ {
@@ -337,26 +335,30 @@ export default class TabBarBottom extends React.Component<Props, State> {
getButtonComponent({ route }) || TouchableWithoutFeedbackWrapper; getButtonComponent({ route }) || TouchableWithoutFeedbackWrapper;
return ( return (
<ButtonComponent <NavigationContext.Provider
key={route.key} key={route.key}
onPress={() => onTabPress({ route })} value={descriptors[route.key].navigation}
onLongPress={() => onTabLongPress({ route })}
testID={testID}
accessibilityLabel={accessibilityLabel}
accessibilityRole={accessibilityRole}
accessibilityStates={accessibilityStates}
style={[
styles.tab,
{ backgroundColor },
this.shouldUseHorizontalLabels()
? styles.tabLandscape
: styles.tabPortrait,
tabStyle,
]}
> >
{this.renderIcon(scene)} <ButtonComponent
{this.renderLabel(scene)} onPress={() => onTabPress({ route })}
</ButtonComponent> onLongPress={() => onTabLongPress({ route })}
testID={testID}
accessibilityLabel={accessibilityLabel}
accessibilityRole={accessibilityRole}
accessibilityStates={accessibilityStates}
style={[
styles.tab,
{ backgroundColor },
this.shouldUseHorizontalLabels()
? styles.tabLandscape
: styles.tabPortrait,
tabStyle,
]}
>
{this.renderIcon(scene)}
{this.renderLabel(scene)}
</ButtonComponent>
</NavigationContext.Provider>
); );
})} })}
</SafeAreaView> </SafeAreaView>

View File

@@ -177,6 +177,7 @@ export default class BottomTabView extends React.Component<Props, State> {
<TabBarComponent <TabBarComponent
{...tabBarOptions} {...tabBarOptions}
state={state} state={state}
descriptors={descriptors}
navigation={navigation} navigation={navigation}
onTabPress={this.handleTabPress} onTabPress={this.handleTabPress}
onTabLongPress={this.handleTabLongPress} onTabLongPress={this.handleTabLongPress}

View File

@@ -24,12 +24,7 @@ export default class ResourceSavingScene extends React.Component<Props> {
return ( return (
<View <View
style={[ style={[styles.container, style, { opacity: isVisible ? 1 : 0 }]}
styles.container,
style,
// eslint-disable-next-line react-native/no-inline-styles
{ opacity: isVisible ? 1 : 0 },
]}
collapsable={false} collapsable={false}
removeClippedSubviews={ removeClippedSubviews={
// On iOS, set removeClippedSubviews to true only when not focused // On iOS, set removeClippedSubviews to true only when not focused

View File

@@ -3,6 +3,50 @@
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.5](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/compat@5.0.0-alpha.4...@react-navigation/compat@5.0.0-alpha.5) (2019-10-03)
**Note:** Version bump only for package @react-navigation/compat
# [5.0.0-alpha.4](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/compat@5.0.0-alpha.3...@react-navigation/compat@5.0.0-alpha.4) (2019-09-27)
**Note:** Version bump only for package @react-navigation/compat
# [5.0.0-alpha.3](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/compat@5.0.0-alpha.2...@react-navigation/compat@5.0.0-alpha.3) (2019-09-23)
### Bug Fixes
* throw when wrapping a compat navigatofor compat ([8920da6](https://github.com/react-navigation/navigation-ex/commit/8920da6))
# [5.0.0-alpha.2](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/compat@5.0.0-alpha.1...@react-navigation/compat@5.0.0-alpha.2) (2019-09-17)
### Bug Fixes
* provide navigation prop in header ([30e510d](https://github.com/react-navigation/navigation-ex/commit/30e510d))
### Features
* add createSwitchNavigator ([ff50282](https://github.com/react-navigation/navigation-ex/commit/ff50282))
* add withNavigation and withNavigationFocus ([114a5dc](https://github.com/react-navigation/navigation-ex/commit/114a5dc))
# 5.0.0-alpha.1 (2019-09-16) # 5.0.0-alpha.1 (2019-09-16)

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.1", "version": "5.0.0-alpha.5",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -24,12 +24,12 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.7" "@react-navigation/routers": "^5.0.0-alpha.9"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^16.8.19", "@types/react": "^16.9.4",
"react": "^16.8.3", "react": "^16.8.3",
"typescript": "^3.5.3" "typescript": "^3.6.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0", "@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -7,15 +7,18 @@ import {
import ScreenPropsContext from './ScreenPropsContext'; import ScreenPropsContext from './ScreenPropsContext';
import createCompatNavigationProp from './createCompatNavigationProp'; import createCompatNavigationProp from './createCompatNavigationProp';
type Props = { type Props<ParamList extends ParamListBase> = {
navigation: NavigationProp<ParamListBase>; navigation: NavigationProp<ParamList>;
route: RouteProp<ParamListBase, string>; route: RouteProp<ParamList, string>;
component: React.ComponentType<any>; component: React.ComponentType<any>;
}; };
function ScreenComponent(props: Props) { function ScreenComponent<ParamList extends ParamListBase>(
props: Props<ParamList>
) {
const navigation = React.useMemo( const navigation = React.useMemo(
() => createCompatNavigationProp(props.navigation, props.route), () =>
createCompatNavigationProp(props.navigation as any, props.route as any),
[props.navigation, props.route] [props.navigation, props.route]
); );

View File

@@ -6,6 +6,7 @@ import {
RouteProp, RouteProp,
} from '@react-navigation/core'; } from '@react-navigation/core';
import * as helpers from './helpers'; import * as helpers from './helpers';
import { CompatNavigationProp } from './types';
type EventName = 'willFocus' | 'willBlur' | 'didFocus' | 'didBlur' | 'refocus'; type EventName = 'willFocus' | 'willBlur' | 'didFocus' | 'didBlur' | 'refocus';
@@ -14,32 +15,28 @@ const blurSubscriptions = new WeakMap<() => void, () => void>();
const refocusSubscriptions = new WeakMap<() => void, () => void>(); const refocusSubscriptions = new WeakMap<() => void, () => void>();
export default function createCompatNavigationProp< export default function createCompatNavigationProp<
ParamList extends ParamListBase NavigationPropType extends NavigationProp<ParamListBase>,
ParamList extends ParamListBase = NavigationPropType extends NavigationProp<
infer P
>
? P
: ParamListBase
>( >(
navigation: NavigationProp<ParamList>, navigation: NavigationPropType,
state: state:
| (RouteProp<ParamList, keyof ParamList> & { | (RouteProp<ParamList, keyof ParamList> & {
state?: NavigationState | PartialState<NavigationState>; state?: NavigationState | PartialState<NavigationState>;
}) })
| NavigationState | NavigationState
| PartialState<NavigationState> | PartialState<NavigationState>
) { ): CompatNavigationProp<NavigationPropType> {
return { return {
...navigation, ...navigation,
...Object.entries(helpers).reduce<{ ...Object.entries(helpers).reduce<{
[key: string]: (...args: any[]) => void; [key: string]: (...args: any[]) => void;
}>((acc, [name, method]) => { }>((acc, [name, method]: [string, Function]) => {
if (name in navigation) { if (name in navigation) {
acc[name] = (...args: any[]) => { acc[name] = (...args: any[]) => navigation.dispatch(method(...args));
// @ts-ignore
const payload = method(...args);
navigation.dispatch(
typeof payload === 'function'
? payload(navigation.dangerouslyGetState())
: payload
);
};
} }
return acc; return acc;
@@ -188,5 +185,5 @@ export default function createCompatNavigationProp<
return undefined; return undefined;
}, },
}; } as any;
} }

View File

@@ -19,7 +19,14 @@ export default function createCompatNavigatorFactory<
React.ComponentType<any> React.ComponentType<any>
> >
>(createNavigator: CreateNavigator) { >(createNavigator: CreateNavigator) {
return < // @ts-ignore
if (createNavigator.isCompat) {
throw new Error(
`The navigator is already in compat mode. You don't need to wrap it in 'createCompatNavigatorFactory'.`
);
}
const createCompatNavigator = <
NavigationPropType extends NavigationProp<any, any, any, any, any>, NavigationPropType extends NavigationProp<any, any, any, any, any>,
ParamList extends ParamListBase = NavigationPropType extends NavigationProp< ParamList extends ParamListBase = NavigationPropType extends NavigationProp<
infer P infer P
@@ -80,7 +87,7 @@ export default function createCompatNavigatorFactory<
navigation, navigation,
route, route,
}: { }: {
navigation: NavigationProp<ParamList>; navigation: NavigationPropType;
route: RouteProp<ParamList, keyof ParamList> & { route: RouteProp<ParamList, keyof ParamList> & {
state?: NavigationState | PartialState<NavigationState>; state?: NavigationState | PartialState<NavigationState>;
}; };
@@ -101,10 +108,9 @@ export default function createCompatNavigatorFactory<
typeof routeNavigationOptions === 'function' || typeof routeNavigationOptions === 'function' ||
typeof screenNavigationOptions === 'function' typeof screenNavigationOptions === 'function'
? { ? {
navigation: createCompatNavigationProp<ParamList>( navigation: createCompatNavigationProp<
navigation, NavigationPropType
route >(navigation, route),
),
navigationOptions: defaultNavigationOptions || {}, navigationOptions: defaultNavigationOptions || {},
screenProps, screenProps,
} }
@@ -158,4 +164,8 @@ export default function createCompatNavigatorFactory<
return Navigator; return Navigator;
}; };
createCompatNavigator.isCompat = true;
return createCompatNavigator;
} }

View File

@@ -0,0 +1,28 @@
import {
useNavigationBuilder,
createNavigator,
DefaultNavigatorOptions,
} from '@react-navigation/core';
import {
TabRouter,
TabRouterOptions,
TabNavigationState,
} from '@react-navigation/routers';
import createCompatNavigatorFactory from './createCompatNavigatorFactory';
type Props = DefaultNavigatorOptions<{}> & TabRouterOptions;
function SwitchNavigator(props: Props) {
const { state, descriptors } = useNavigationBuilder<
TabNavigationState,
TabRouterOptions,
{},
{}
>(TabRouter, props);
return descriptors[state.routes[state.index].key].render();
}
export default createCompatNavigatorFactory(
createNavigator<{}, typeof SwitchNavigator>(SwitchNavigator)
);

View File

@@ -9,4 +9,13 @@ export {
default as createCompatNavigatorFactory, default as createCompatNavigatorFactory,
} from './createCompatNavigatorFactory'; } from './createCompatNavigatorFactory';
export {
default as createCompatNavigationProp,
} from './createCompatNavigationProp';
export { default as createSwitchNavigator } from './createSwitchNavigator';
export { default as withNavigation } from './withNavigation';
export { default as withNavigationFocus } from './withNavigationFocus';
export * from './types'; export * from './types';

View File

@@ -0,0 +1,25 @@
import * as React from 'react';
import {
useNavigation,
useRoute,
NavigationProp,
ParamListBase,
} from '@react-navigation/core';
import createCompatNavigationProp from './createCompatNavigationProp';
import { CompatNavigationProp } from './types';
export default function useCompatNavigation<
T extends NavigationProp<ParamListBase>
>() {
const navigation = useNavigation();
const route = useRoute();
return React.useMemo(
() =>
createCompatNavigationProp(
navigation,
route as any
) as CompatNavigationProp<T>,
[navigation, route]
);
}

View File

@@ -0,0 +1,33 @@
import * as React from 'react';
import { NavigationProp, ParamListBase } from '@react-navigation/core';
import useCompatNavigation from './useCompatNavigation';
import { CompatNavigationProp } from './types';
type InjectedProps<T extends NavigationProp<ParamListBase>> = {
navigation: CompatNavigationProp<T>;
};
export default function withNavigation<
T extends NavigationProp<ParamListBase>,
P extends InjectedProps<T>,
C extends React.ComponentType<P>
>(Comp: C) {
const WrappedComponent = ({
onRef,
...rest
}: Exclude<P, InjectedProps<T>> & {
onRef?: C extends React.ComponentClass<any>
? React.Ref<InstanceType<C>>
: never;
}): React.ReactElement => {
const navigation = useCompatNavigation<T>();
// @ts-ignore
return <Comp ref={onRef} navigation={navigation} {...rest} />;
};
WrappedComponent.displayName = `withNavigation(${Comp.displayName ||
Comp.name})`;
return WrappedComponent;
}

View File

@@ -0,0 +1,30 @@
import * as React from 'react';
import { useIsFocused } from '@react-navigation/core';
type InjectedProps = {
isFocused: boolean;
};
export default function withNavigationFocus<
P extends InjectedProps,
C extends React.ComponentType<P>
>(Comp: C) {
const WrappedComponent = ({
onRef,
...rest
}: Exclude<P, InjectedProps> & {
onRef?: C extends React.ComponentClass<any>
? React.Ref<InstanceType<C>>
: never;
}): React.ReactElement => {
const isFocused = useIsFocused();
// @ts-ignore
return <Comp ref={onRef} isFocused={isFocused} {...rest} />;
};
WrappedComponent.displayName = `withNavigationFocus(${Comp.displayName ||
Comp.name})`;
return WrappedComponent;
}

View File

@@ -3,6 +3,47 @@
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.12](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.11...@react-navigation/core@5.0.0-alpha.12) (2019-10-03)
### Bug Fixes
* don't merge state with existing state during reset. fixes [#111](https://github.com/react-navigation/navigation-ex/issues/111) ([7393464](https://github.com/react-navigation/navigation-ex/commit/7393464))
* don't throw when switching navigator. fixes [#91](https://github.com/react-navigation/navigation-ex/issues/91) ([19be2b4](https://github.com/react-navigation/navigation-ex/commit/19be2b4))
### Features
* add a getRootState method ([#119](https://github.com/react-navigation/navigation-ex/issues/119)) ([7a5bcb4](https://github.com/react-navigation/navigation-ex/commit/7a5bcb4))
# [5.0.0-alpha.11](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.10...@react-navigation/core@5.0.0-alpha.11) (2019-09-27)
### Bug Fixes
* fire blur event when a route is removed with a delay ([1153d55](https://github.com/react-navigation/navigation-ex/commit/1153d55)), closes [#110](https://github.com/react-navigation/navigation-ex/issues/110)
### Features
* add a method to reset root navigator state ([e61f594](https://github.com/react-navigation/navigation-ex/commit/e61f594))
# [5.0.0-alpha.10](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.9...@react-navigation/core@5.0.0-alpha.10) (2019-09-17)
**Note:** Version bump only for package @react-navigation/core
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.8...@react-navigation/core@5.0.0-alpha.9) (2019-09-16) # [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.8...@react-navigation/core@5.0.0-alpha.9) (2019-09-16)

View File

@@ -6,7 +6,7 @@
"react-native", "react-native",
"react-navigation" "react-navigation"
], ],
"version": "5.0.0-alpha.9", "version": "5.0.0-alpha.12",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -31,19 +31,19 @@
"dependencies": { "dependencies": {
"escape-string-regexp": "^2.0.0", "escape-string-regexp": "^2.0.0",
"query-string": "^6.8.3", "query-string": "^6.8.3",
"shortid": "^2.2.14", "shortid": "^2.2.15",
"use-subscription": "^1.0.0" "use-subscription": "^1.1.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.4.5", "@babel/core": "^7.6.2",
"@react-native-community/bob": "^0.7.0", "@react-native-community/bob": "^0.7.0",
"@types/react": "^16.8.19", "@types/react": "^16.9.4",
"@types/shortid": "^0.0.29", "@types/shortid": "^0.0.29",
"del-cli": "^2.0.0", "del-cli": "^3.0.0",
"react": "^16.8.3", "react": "^16.8.3",
"react-native-testing-library": "^1.9.1", "react-native-testing-library": "^1.9.1",
"react-test-renderer": "16.8.3", "react-test-renderer": "16.8.3",
"typescript": "^3.5.3" "typescript": "^3.6.3"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^16.8.3" "react": "^16.8.3"

View File

@@ -1,5 +1,5 @@
import shortid from 'shortid'; import shortid from 'shortid';
import { CommonAction, NavigationState } from './types'; import { CommonAction, NavigationState, PartialState } from './types';
/** /**
* Base router object that can be used when writing custom routers. * Base router object that can be used when writing custom routers.
@@ -9,7 +9,7 @@ const BaseRouter = {
getStateForAction<State extends NavigationState>( getStateForAction<State extends NavigationState>(
state: State, state: State,
action: CommonAction action: CommonAction
): State | null { ): State | PartialState<State> | null {
switch (action.type) { switch (action.type) {
case 'REPLACE': { case 'REPLACE': {
const index = action.source const index = action.source
@@ -56,12 +56,7 @@ const BaseRouter = {
} }
case 'RESET': case 'RESET':
return { return action.payload as PartialState<State>;
...state,
...action.payload,
key: state.key,
routeNames: state.routeNames,
};
default: default:
return null; return null;

View File

@@ -1,3 +1,4 @@
// eslint-disable-next-line import/no-cycle
import { NavigationState, PartialState } from './types'; import { NavigationState, PartialState } from './types';
export type Action = export type Action =

View File

@@ -18,25 +18,30 @@ export const SingleNavigatorContext = React.createContext<
* Component which ensures that there's only one navigator nested under it. * Component which ensures that there's only one navigator nested under it.
*/ */
export default function EnsureSingleNavigator({ children }: Props) { export default function EnsureSingleNavigator({ children }: Props) {
const [currentKey, setCurrentKey] = React.useState<string | undefined>(); const navigatorKeyRef = React.useRef<string | undefined>();
const value = React.useMemo( const value = React.useMemo(
() => ({ () => ({
register(key: string) { register(key: string) {
const currentKey = navigatorKeyRef.current;
if (currentKey !== undefined && key !== currentKey) { if (currentKey !== undefined && key !== currentKey) {
throw new Error(MULTIPLE_NAVIGATOR_ERROR); throw new Error(MULTIPLE_NAVIGATOR_ERROR);
} }
setCurrentKey(key); navigatorKeyRef.current = key;
}, },
unregister(key: string) { unregister(key: string) {
if (currentKey !== undefined && key !== currentKey) { const currentKey = navigatorKeyRef.current;
throw new Error(MULTIPLE_NAVIGATOR_ERROR);
if (key !== currentKey) {
return;
} }
setCurrentKey(undefined); navigatorKeyRef.current = undefined;
}, },
}), }),
[currentKey] []
); );
return ( return (

View File

@@ -1,5 +1,10 @@
import * as React from 'react'; import * as React from 'react';
import { NavigationAction, NavigationHelpers, ParamListBase } from './types'; import {
NavigationAction,
NavigationHelpers,
NavigationState,
ParamListBase,
} from './types';
export type ChildActionListener = ( export type ChildActionListener = (
action: NavigationAction, action: NavigationAction,
@@ -14,6 +19,8 @@ export type FocusedNavigationListener = <T>(
callback: FocusedNavigationCallback<T> callback: FocusedNavigationCallback<T>
) => { handled: boolean; result: T }; ) => { handled: boolean; result: T };
export type NavigatorStateGetter = () => NavigationState;
/** /**
* Context which holds the required helpers needed to build nested navigators. * Context which holds the required helpers needed to build nested navigators.
*/ */
@@ -25,6 +32,7 @@ const NavigationBuilderContext = React.createContext<{
addActionListener?: (listener: ChildActionListener) => void; addActionListener?: (listener: ChildActionListener) => void;
addFocusedListener?: (listener: FocusedNavigationListener) => void; addFocusedListener?: (listener: FocusedNavigationListener) => void;
onRouteFocus?: (key: string) => void; onRouteFocus?: (key: string) => void;
addStateGetter?: (key: string, getter: NavigatorStateGetter) => void;
trackAction: (action: NavigationAction) => void; trackAction: (action: NavigationAction) => void;
}>({ }>({
trackAction: () => undefined, trackAction: () => undefined,

View File

@@ -2,8 +2,10 @@ import * as React from 'react';
import * as CommonActions from './CommonActions'; import * as CommonActions from './CommonActions';
import EnsureSingleNavigator from './EnsureSingleNavigator'; import EnsureSingleNavigator from './EnsureSingleNavigator';
import NavigationBuilderContext from './NavigationBuilderContext'; import NavigationBuilderContext from './NavigationBuilderContext';
import ResetRootContext from './ResetRootContext';
import useFocusedListeners from './useFocusedListeners'; import useFocusedListeners from './useFocusedListeners';
import useDevTools from './useDevTools'; import useDevTools from './useDevTools';
import useStateGetters from './useStateGetters';
import { import {
Route, Route,
@@ -23,7 +25,9 @@ const MISSING_CONTEXT_ERROR =
export const NavigationStateContext = React.createContext<{ export const NavigationStateContext = React.createContext<{
state?: NavigationState | PartialState<NavigationState>; state?: NavigationState | PartialState<NavigationState>;
getState: () => NavigationState | PartialState<NavigationState> | undefined; getState: () => NavigationState | PartialState<NavigationState> | undefined;
setState: (state: NavigationState | undefined) => void; setState: (
state: NavigationState | PartialState<NavigationState> | undefined
) => void;
key?: string; key?: string;
performTransaction: (action: () => void) => void; performTransaction: (action: () => void) => void;
}>({ }>({
@@ -86,46 +90,6 @@ const Container = React.forwardRef(function NavigationContainer(
getPartialState(initialState) getPartialState(initialState)
); );
const { listeners, addListener: addFocusedListener } = useFocusedListeners();
const dispatch = (action: NavigationAction) => {
listeners[0](navigation => navigation.dispatch(action));
};
const canGoBack = () => {
const { result, handled } = listeners[0](navigation =>
navigation.canGoBack()
);
if (handled) {
return result;
} else {
return false;
}
};
React.useImperativeHandle(ref, () => ({
...(Object.keys(CommonActions) as Array<keyof typeof CommonActions>).reduce<
any
>((acc, name) => {
acc[name] = (...args: any[]) =>
dispatch(
// eslint-disable-next-line import/namespace
CommonActions[name](
// @ts-ignore
...args
)
);
return acc;
}, {}),
resetRoot: (state: PartialState<NavigationState> | NavigationState) => {
trackAction('@@RESET_ROOT');
setNavigationState(state);
},
dispatch,
canGoBack,
}));
const navigationStateRef = React.useRef<State>(); const navigationStateRef = React.useRef<State>();
const transactionStateRef = React.useRef<State | null>(null); const transactionStateRef = React.useRef<State | null>(null);
const isTransactionActiveRef = React.useRef<boolean>(false); const isTransactionActiveRef = React.useRef<boolean>(false);
@@ -143,12 +107,66 @@ const Container = React.forwardRef(function NavigationContainer(
state, 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) => {
trackAction('@@RESET_ROOT');
setNavigationState(state);
},
[trackAction]
);
const getRootState = () => {
return getStateForRoute('root');
};
React.useImperativeHandle(ref, () => ({
...(Object.keys(CommonActions) as Array<keyof typeof CommonActions>).reduce<
any
>((acc, name) => {
acc[name] = (...args: any[]) =>
dispatch(
CommonActions[name](
// @ts-ignore
...args
)
);
return acc;
}, {}),
resetRoot,
dispatch,
canGoBack,
getRootState,
}));
const builderContext = React.useMemo( const builderContext = React.useMemo(
() => ({ () => ({
addFocusedListener, addFocusedListener,
addStateGetter,
trackAction, trackAction,
}), }),
[addFocusedListener, trackAction] [addFocusedListener, trackAction, addStateGetter]
); );
const performTransaction = React.useCallback((callback: () => void) => { const performTransaction = React.useCallback((callback: () => void) => {
@@ -218,7 +236,9 @@ const Container = React.forwardRef(function NavigationContainer(
return ( return (
<NavigationBuilderContext.Provider value={builderContext}> <NavigationBuilderContext.Provider value={builderContext}>
<NavigationStateContext.Provider value={context}> <NavigationStateContext.Provider value={context}>
<EnsureSingleNavigator>{children}</EnsureSingleNavigator> <ResetRootContext.Provider value={resetRoot}>
<EnsureSingleNavigator>{children}</EnsureSingleNavigator>
</ResetRootContext.Provider>
</NavigationStateContext.Provider> </NavigationStateContext.Provider>
</NavigationBuilderContext.Provider> </NavigationBuilderContext.Provider>
); );

View File

@@ -0,0 +1,15 @@
import * as React from 'react';
import { NavigationState, PartialState } from './types';
/**
* Context which holds the method to reset root navigator state.
*/
const ResetRootContext = React.createContext<
(state: PartialState<NavigationState> | NavigationState) => void
>(() => {
throw new Error(
"We couldn't find a way to reset root state. Have you wrapped your app with 'NavigationContainer'?"
);
});
export default ResetRootContext;

View File

@@ -19,8 +19,8 @@ type Props<State extends NavigationState, ScreenOptions extends object> = {
route: Route<string> & { route: Route<string> & {
state?: NavigationState | PartialState<NavigationState>; state?: NavigationState | PartialState<NavigationState>;
}; };
getState: () => NavigationState; getState: () => State;
setState: (state: NavigationState) => void; setState: (state: State) => void;
}; };
/** /**
@@ -47,7 +47,7 @@ export default function SceneView<
}, [getState, route.key]); }, [getState, route.key]);
const setCurrentState = React.useCallback( const setCurrentState = React.useCallback(
(child: NavigationState | undefined) => { (child: NavigationState | PartialState<NavigationState> | undefined) => {
const state = getState(); const state = getState();
setState({ setState({

View File

@@ -125,15 +125,5 @@ it('resets state to new state with RESET', () => {
}) })
); );
expect(result).toEqual({ ...STATE, index: 0, routes }); expect(result).toEqual({ index: 0, routes });
});
it('ignores key and routeNames when resetting with RESET', () => {
const result = BaseRouter.getStateForAction(
STATE,
// @ts-ignore
CommonActions.reset({ index: 2, key: 'foo', routeNames: ['test'] })
);
expect(result).toEqual({ ...STATE, index: 2 });
}); });

View File

@@ -321,3 +321,56 @@ it('handle resetting state with ref', () => {
expect(onStateChange).toBeCalledTimes(1); expect(onStateChange).toBeCalledTimes(1);
expect(onStateChange).lastCalledWith(state); expect(onStateChange).lastCalledWith(state);
}); });
it('handle getRootState', () => {
const TestNavigator = (props: any) => {
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
return descriptors[state.routes[state.index].key].render();
};
const ref = React.createRef<NavigationContainerRef>();
const element = (
<NavigationContainer ref={ref}>
<TestNavigator initialRouteName="foo">
<Screen name="foo">
{() => (
<TestNavigator>
<Screen name="qux" component={() => null} />
<Screen name="lex" component={() => null} />
</TestNavigator>
)}
</Screen>
<Screen name="bar" component={() => null} />
</TestNavigator>
</NavigationContainer>
);
render(element);
let state;
if (ref.current) {
state = ref.current.getRootState();
}
expect(state).toEqual({
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' }],
stale: false,
},
},
{ key: 'bar', name: 'bar' },
],
stale: false,
});
});

View File

@@ -323,7 +323,7 @@ it('cleans up state when the navigator unmounts', () => {
expect(onStateChange).lastCalledWith(undefined); expect(onStateChange).lastCalledWith(undefined);
}); });
it('allows arbitrary state updates by dispatching a function', () => { it('allows state updates by dispatching a function returning an action', () => {
const TestNavigator = (props: any) => { const TestNavigator = (props: any) => {
const { state, descriptors } = useNavigationBuilder(MockRouter, props); const { state, descriptors } = useNavigationBuilder(MockRouter, props);
@@ -332,11 +332,11 @@ it('allows arbitrary state updates by dispatching a function', () => {
const FooScreen = (props: any) => { const FooScreen = (props: any) => {
React.useEffect(() => { React.useEffect(() => {
props.navigation.dispatch((state: any) => ({ props.navigation.dispatch((state: NavigationState) =>
...state, state.index === 0
routes: state.routes.slice().reverse(), ? { type: 'NAVIGATE', payload: { name: state.routeNames[1] } }
index: 1, : { type: 'NOOP' }
})); );
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
@@ -364,7 +364,7 @@ it('allows arbitrary state updates by dispatching a function', () => {
index: 1, index: 1,
key: '0', key: '0',
routeNames: ['foo', 'bar'], routeNames: ['foo', 'bar'],
routes: [{ key: 'bar', name: 'bar' }, { key: 'foo', name: 'foo' }], routes: [{ key: 'foo', name: 'foo' }, { key: 'bar', name: 'bar' }],
}); });
}); });
@@ -655,6 +655,7 @@ it('throws when a React Element is not the direct children', () => {
); );
}); });
// eslint-disable-next-line jest/expect-expect
it("doesn't throw when direct children is Screen or empty element", () => { it("doesn't throw when direct children is Screen or empty element", () => {
const TestNavigator = (props: any) => { const TestNavigator = (props: any) => {
useNavigationBuilder(MockRouter, props); useNavigationBuilder(MockRouter, props);
@@ -694,3 +695,30 @@ it('throws when multiple screens with same name are defined', () => {
"A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named 'foo')" "A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named 'foo')"
); );
}); });
it('switches rendered navigators', () => {
const TestNavigator = (props: any) => {
useNavigationBuilder(MockRouter, props);
return null;
};
const root = render(
<NavigationContainer>
<TestNavigator key="a">
<Screen name="foo" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
);
expect(() =>
root.update(
<NavigationContainer>
<TestNavigator key="b">
<Screen name="foo" component={jest.fn()} />
</TestNavigator>
</NavigationContainer>
)
).not.toThrowError(
'Another navigator is already registered for this container.'
);
});

View File

@@ -4,6 +4,7 @@ import useNavigationBuilder from '../useNavigationBuilder';
import NavigationContainer from '../NavigationContainer'; 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';
it('fires focus and blur events in root navigator', () => { it('fires focus and blur events in root navigator', () => {
const TestNavigator = React.forwardRef((props: any, ref: any): any => { const TestNavigator = React.forwardRef((props: any, ref: any): any => {
@@ -200,6 +201,131 @@ it('fires focus and blur events in nested navigator', () => {
expect(thirdFocusCallback).toBeCalledTimes(1); expect(thirdFocusCallback).toBeCalledTimes(1);
}); });
it('fires blur event when a route is removed with a delay', async () => {
const TestRouter = (options: any): Router<NavigationState, any> => {
const router = MockRouter(options);
return {
...router,
getInitialState({ routeNames, routeParamList }) {
const initialRouteName =
options.initialRouteName !== undefined
? options.initialRouteName
: routeNames[0];
return {
stale: false,
key: 'stack',
index: 0,
routeNames,
routes: [
{
key: initialRouteName,
name: initialRouteName,
params: routeParamList[initialRouteName],
},
],
};
},
getStateForAction(state, action) {
switch (action.type) {
case 'PUSH':
return {
...state,
index: state.index + 1,
routes: [...state.routes, action.payload],
};
case 'POP': {
const routes = state.routes.slice(0, -1);
return {
...state,
index: routes.length - 1,
routes,
};
}
default:
return router.getStateForAction(state, action);
}
},
actionCreators: {
push(payload) {
return { type: 'PUSH', payload };
},
pop() {
return { type: 'POP' };
},
},
};
};
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
const { state, navigation, descriptors } = useNavigationBuilder(
TestRouter,
props
);
React.useImperativeHandle(ref, () => navigation, [navigation]);
const [previous, dispatch] = React.useReducer(
(state, action) => {
return { ...state, ...action };
},
{ routes: state.routes, descriptors }
);
React.useEffect(() => {
dispatch({ routes: state.routes, descriptors });
}, [descriptors, state.routes]);
return previous.routes.map((route: any) =>
previous.descriptors[route.key].render()
);
});
const blurCallback = jest.fn();
const First = () => null;
const Second = ({ navigation }: any) => {
React.useEffect(() => navigation.addListener('blur', blurCallback), [
navigation,
]);
return null;
};
const navigation = React.createRef<any>();
const element = (
<NavigationContainer>
<TestNavigator ref={navigation}>
<Screen name="first" component={First} />
<Screen name="second" component={Second} />
</TestNavigator>
</NavigationContainer>
);
render(element);
act(() =>
navigation.current.push({
name: 'second',
key: 'second',
})
);
expect(blurCallback).toBeCalledTimes(0);
act(() => navigation.current.pop());
expect(blurCallback).toBeCalledTimes(1);
});
it('fires custom events', () => { it('fires custom events', () => {
const eventName = 'someSuperCoolEvent'; const eventName = 'someSuperCoolEvent';

View File

@@ -296,6 +296,7 @@ it("action doesn't bubble if target is specified", () => {
expect(onStateChange).not.toBeCalled(); expect(onStateChange).not.toBeCalled();
}); });
// eslint-disable-next-line jest/expect-expect
it("doesn't crash if no navigator handled the action", () => { it("doesn't crash if no navigator handled the action", () => {
const TestRouter = MockRouter; const TestRouter = MockRouter;

View File

@@ -1,3 +1,4 @@
// eslint-disable-next-line import/no-cycle
import * as CommonActions from './CommonActions'; import * as CommonActions from './CommonActions';
import * as React from 'react'; import * as React from 'react';
@@ -170,7 +171,10 @@ export type Router<
* @param state State object to apply the action on. * @param state State object to apply the action on.
* @param action Action object to apply. * @param action Action object to apply.
*/ */
getStateForAction(state: State, action: Action): State | null; getStateForAction(
state: State,
action: Action
): State | PartialState<State> | null;
/** /**
* Whether the action should also change focus in parent navigator * Whether the action should also change focus in parent navigator
@@ -270,7 +274,9 @@ type NavigationHelpersCommon<
* *
* @param action Action object or update function. * @param action Action object or update function.
*/ */
dispatch(action: NavigationAction | ((state: State) => State)): void; dispatch(
action: NavigationAction | ((state: State) => NavigationAction)
): void;
/** /**
* Navigate to a route in current navigation tree. * Navigate to a route in current navigation tree.
@@ -314,6 +320,13 @@ type NavigationHelpersCommon<
*/ */
reset(state: PartialState<State> | State): void; reset(state: PartialState<State> | State): void;
/**
* Reset the navigation state of the root navigator to the provided state.
*
* @param state Navigation state object.
*/
resetRoot(state: PartialState<NavigationState> | NavigationState): void;
/** /**
* Go back to the previous route in history. * Go back to the previous route in history.
*/ */
@@ -525,6 +538,7 @@ export type NavigationContainerRef =
* @param state Navigation state object. * @param state Navigation state object.
*/ */
resetRoot(state: PartialState<NavigationState> | NavigationState): void; resetRoot(state: PartialState<NavigationState> | NavigationState): void;
getRootState(): NavigationState;
} }
| undefined | undefined
| null; | null;

View File

@@ -3,6 +3,7 @@ import SceneView from './SceneView';
import NavigationBuilderContext, { import NavigationBuilderContext, {
ChildActionListener, ChildActionListener,
FocusedNavigationListener, FocusedNavigationListener,
NavigatorStateGetter,
} from './NavigationBuilderContext'; } from './NavigationBuilderContext';
import { NavigationEventEmitter } from './useEventEmitter'; import { NavigationEventEmitter } from './useEventEmitter';
import useNavigationCache from './useNavigationCache'; import useNavigationCache from './useNavigationCache';
@@ -17,8 +18,8 @@ import {
Router, Router,
} from './types'; } from './types';
type Options<ScreenOptions extends object> = { type Options<State extends NavigationState, ScreenOptions extends object> = {
state: NavigationState; state: State;
screens: { [key: string]: RouteConfig<ParamListBase, string, ScreenOptions> }; screens: { [key: string]: RouteConfig<ParamListBase, string, ScreenOptions> };
navigation: NavigationHelpers<ParamListBase>; navigation: NavigationHelpers<ParamListBase>;
screenOptions?: screenOptions?:
@@ -31,12 +32,13 @@ type Options<ScreenOptions extends object> = {
action: NavigationAction, action: NavigationAction,
visitedNavigators?: Set<string> visitedNavigators?: Set<string>
) => boolean; ) => boolean;
getState: () => NavigationState; getState: () => State;
setState: (state: NavigationState) => void; setState: (state: State) => void;
addActionListener: (listener: ChildActionListener) => void; addActionListener: (listener: ChildActionListener) => void;
addFocusedListener: (listener: FocusedNavigationListener) => void; addFocusedListener: (listener: FocusedNavigationListener) => void;
addStateGetter: (key: string, getter: NavigatorStateGetter) => void;
onRouteFocus: (key: string) => void; onRouteFocus: (key: string) => void;
router: Router<NavigationState, NavigationAction>; router: Router<State, NavigationAction>;
emitter: NavigationEventEmitter; emitter: NavigationEventEmitter;
}; };
@@ -61,10 +63,11 @@ export default function useDescriptors<
setState, setState,
addActionListener, addActionListener,
addFocusedListener, addFocusedListener,
addStateGetter,
onRouteFocus, onRouteFocus,
router, router,
emitter, emitter,
}: Options<ScreenOptions>) { }: Options<State, ScreenOptions>) {
const [options, setOptions] = React.useState<{ [key: string]: object }>({}); const [options, setOptions] = React.useState<{ [key: string]: object }>({});
const { trackAction } = React.useContext(NavigationBuilderContext); const { trackAction } = React.useContext(NavigationBuilderContext);
@@ -74,6 +77,7 @@ export default function useDescriptors<
onAction, onAction,
addActionListener, addActionListener,
addFocusedListener, addFocusedListener,
addStateGetter,
onRouteFocus, onRouteFocus,
trackAction, trackAction,
}), }),
@@ -83,6 +87,7 @@ export default function useDescriptors<
addActionListener, addActionListener,
addFocusedListener, addFocusedListener,
onRouteFocus, onRouteFocus,
addStateGetter,
trackAction, trackAction,
] ]
); );

View File

@@ -18,6 +18,7 @@ type DevTools = {
}; };
declare global { declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace NodeJS { namespace NodeJS {
interface Global { interface Global {
__REDUX_DEVTOOLS_EXTENSION__: __REDUX_DEVTOOLS_EXTENSION__:

View File

@@ -57,19 +57,19 @@ export default function useFocusEvents({ state, emitter }: Options) {
return; return;
} }
state.routes.forEach((route, i) => { if (lastFocusedKey === undefined) {
if ( // Only fire events after initial mount
lastFocusedKey === undefined || return;
(route.key !== lastFocusedKey && route.key !== currentFocusedKey) }
) {
// Only fire events after mount, or if focus state of this route changed
return;
}
emitter.emit({ emitter.emit({
type: i === state.index ? 'focus' : 'blur', type: 'focus',
target: route.key, target: currentFocusedKey,
});
}); });
}, [currentFocusedKey, emitter, navigation, state.index, state.routes]);
emitter.emit({
type: 'blur',
target: lastFocusedKey,
});
}, [currentFocusedKey, emitter, navigation]);
} }

View File

@@ -23,6 +23,8 @@ import {
PrivateValueStore, PrivateValueStore,
NavigationAction, NavigationAction,
} from './types'; } from './types';
import useStateGetters from './useStateGetters';
import useOnGetState from './useOnGetState';
// This is to make TypeScript compiler happy // This is to make TypeScript compiler happy
// eslint-disable-next-line babel/no-unused-expressions // eslint-disable-next-line babel/no-unused-expressions
@@ -227,6 +229,8 @@ export default function useNavigationBuilder<
addListener: addFocusedListener, addListener: addFocusedListener,
} = useFocusedListeners(); } = useFocusedListeners();
const { getStateForRoute, addStateGetter } = useStateGetters();
const onAction = useOnAction({ const onAction = useOnAction({
router, router,
getState, getState,
@@ -245,7 +249,6 @@ export default function useNavigationBuilder<
const navigation = useNavigationHelpers<State, NavigationAction, EventMap>({ const navigation = useNavigationHelpers<State, NavigationAction, EventMap>({
onAction, onAction,
getState, getState,
setState,
emitter, emitter,
router, router,
}); });
@@ -255,6 +258,11 @@ export default function useNavigationBuilder<
focusedListeners, focusedListeners,
}); });
useOnGetState({
getState,
getStateForRoute,
});
const descriptors = useDescriptors<State, ScreenOptions>({ const descriptors = useDescriptors<State, ScreenOptions>({
state, state,
screens, screens,
@@ -266,6 +274,7 @@ export default function useNavigationBuilder<
onRouteFocus, onRouteFocus,
addActionListener, addActionListener,
addFocusedListener, addFocusedListener,
addStateGetter,
router, router,
emitter, emitter,
}); });

View File

@@ -12,15 +12,15 @@ import {
Router, Router,
} from './types'; } from './types';
type Options = { type Options<State extends NavigationState> = {
state: NavigationState; state: State;
getState: () => NavigationState; getState: () => State;
navigation: NavigationHelpers<ParamListBase> & navigation: NavigationHelpers<ParamListBase> &
Partial<NavigationProp<ParamListBase, string, any, any, any>>; Partial<NavigationProp<ParamListBase, string, any, any, any>>;
setOptions: ( setOptions: (
cb: (options: { [key: string]: object }) => { [key: string]: object } cb: (options: { [key: string]: object }) => { [key: string]: object }
) => void; ) => void;
router: Router<NavigationState, NavigationAction>; router: Router<State, NavigationAction>;
emitter: NavigationEventEmitter; emitter: NavigationEventEmitter;
}; };
@@ -39,7 +39,14 @@ type NavigationCache<
export default function useNavigationCache< export default function useNavigationCache<
State extends NavigationState, State extends NavigationState,
ScreenOptions extends object ScreenOptions extends object
>({ state, getState, navigation, setOptions, router, emitter }: Options) { >({
state,
getState,
navigation,
setOptions,
router,
emitter,
}: Options<State>) {
// Cache object which holds navigation objects for each screen // Cache object which holds navigation objects for each screen
// We use `React.useMemo` instead of `React.useRef` coz we want to invalidate it when deps change // We use `React.useMemo` instead of `React.useRef` coz we want to invalidate it when deps change
// In reality, these deps will rarely change, if ever // In reality, these deps will rarely change, if ever
@@ -70,13 +77,17 @@ export default function useNavigationCache<
const { emit, ...rest } = navigation; const { emit, ...rest } = navigation;
const dispatch = ( const dispatch = (
action: NavigationAction | ((state: State) => State) action: NavigationAction | ((state: State) => NavigationAction)
) => ) => {
const payload =
typeof action === 'function' ? action(getState()) : action;
navigation.dispatch( navigation.dispatch(
typeof action === 'object' && action != null typeof payload === 'object' && payload != null
? { source: route.key, ...action } ? { source: route.key, ...payload }
: action : payload
); );
};
const helpers = Object.keys(actions).reduce( const helpers = Object.keys(actions).reduce(
(acc, name) => { (acc, name) => {
@@ -92,7 +103,7 @@ export default function useNavigationCache<
...helpers, ...helpers,
...emitter.create(route.key), ...emitter.create(route.key),
dangerouslyGetParent: () => parentNavigation as any, dangerouslyGetParent: () => parentNavigation as any,
dangerouslyGetState: getState as () => State, dangerouslyGetState: getState,
dispatch, dispatch,
setOptions: (options: object) => setOptions: (options: object) =>
setOptions(o => ({ setOptions(o => ({

View File

@@ -1,6 +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 ResetRootContext from './ResetRootContext';
import { NavigationStateContext } from './NavigationContainer'; import { NavigationStateContext } from './NavigationContainer';
import { NavigationEventEmitter } from './useEventEmitter'; import { NavigationEventEmitter } from './useEventEmitter';
import { import {
@@ -23,7 +24,6 @@ type Options<State extends NavigationState, Action extends NavigationAction> = {
visitedNavigators?: Set<string> visitedNavigators?: Set<string>
) => boolean; ) => boolean;
getState: () => State; getState: () => State;
setState: (state: State) => void;
emitter: NavigationEventEmitter; emitter: NavigationEventEmitter;
router: Router<State, Action>; router: Router<State, Action>;
}; };
@@ -36,18 +36,18 @@ export default function useNavigationHelpers<
State extends NavigationState, State extends NavigationState,
Action extends NavigationAction, Action extends NavigationAction,
EventMap extends { [key: string]: any } EventMap extends { [key: string]: any }
>({ onAction, getState, setState, emitter, router }: Options<State, Action>) { >({ onAction, getState, emitter, router }: Options<State, Action>) {
const resetRoot = React.useContext(ResetRootContext);
const parentNavigationHelpers = React.useContext(NavigationContext); const parentNavigationHelpers = React.useContext(NavigationContext);
const { performTransaction } = React.useContext(NavigationStateContext); const { performTransaction } = React.useContext(NavigationStateContext);
return React.useMemo(() => { return React.useMemo(() => {
const dispatch = (action: Action | ((state: State) => State)) => const dispatch = (action: Action | ((state: State) => Action)) =>
performTransaction(() => { performTransaction(() => {
if (typeof action === 'function') { const payload =
setState(action(getState())); typeof action === 'function' ? action(getState()) : action;
} else {
onAction(action); onAction(payload);
}
}); });
const actions = { const actions = {
@@ -67,6 +67,7 @@ export default function useNavigationHelpers<
return { return {
...parentNavigationHelpers, ...parentNavigationHelpers,
...helpers, ...helpers,
resetRoot,
dispatch, dispatch,
emit: emitter.emit, emit: emitter.emit,
isFocused: parentNavigationHelpers isFocused: parentNavigationHelpers
@@ -85,9 +86,9 @@ export default function useNavigationHelpers<
router, router,
getState, getState,
parentNavigationHelpers, parentNavigationHelpers,
resetRoot,
emitter.emit, emitter.emit,
performTransaction, performTransaction,
setState,
onAction, onAction,
]); ]);
} }

View File

@@ -2,13 +2,18 @@ import * as React from 'react';
import NavigationBuilderContext, { import NavigationBuilderContext, {
ChildActionListener, ChildActionListener,
} from './NavigationBuilderContext'; } from './NavigationBuilderContext';
import { NavigationAction, NavigationState, Router } from './types'; import {
NavigationAction,
NavigationState,
PartialState,
Router,
} from './types';
type Options = { type Options = {
router: Router<NavigationState, NavigationAction>; router: Router<NavigationState, NavigationAction>;
key?: string; key?: string;
getState: () => NavigationState; getState: () => NavigationState;
setState: (state: NavigationState) => void; setState: (state: NavigationState | PartialState<NavigationState>) => void;
listeners: ChildActionListener[]; listeners: ChildActionListener[];
}; };

View File

@@ -0,0 +1,31 @@
import * as React from 'react';
import NavigationBuilderContext from './NavigationBuilderContext';
import { NavigationState } from './types';
import NavigationRouteContext from './NavigationRouteContext';
export default function useOnGetState({
getStateForRoute,
getState,
}: {
getStateForRoute: (routeName: string) => NavigationState | undefined;
getState: () => NavigationState;
}) {
const { addStateGetter } = React.useContext(NavigationBuilderContext);
const route = React.useContext(NavigationRouteContext);
const key = route ? route.key : 'root';
const getter = React.useCallback(() => {
const state = getState();
return {
...state,
routes: state.routes.map(route => ({
...route,
state: getStateForRoute(route.key),
})),
};
}, [getState, getStateForRoute]);
React.useEffect(() => {
return addStateGetter && addStateGetter(key, getter);
}, [addStateGetter, getter, key]);
}

View File

@@ -0,0 +1,35 @@
import * as React from 'react';
import { NavigatorStateGetter } from './NavigationBuilderContext';
/**
* Hook which lets child navigators add getters to be called for obtaining rehydrated state.
*/
export default function useStateGetters() {
const stateGetters = React.useRef<Record<string, NavigatorStateGetter>>({});
const getStateForRoute = React.useCallback(
routeKey =>
stateGetters.current[routeKey] === undefined
? undefined
: stateGetters.current[routeKey](),
[stateGetters]
);
const addStateGetter = React.useCallback(
(key: string, getter: NavigatorStateGetter) => {
stateGetters.current[key] = getter;
return () => {
// @ts-ignore
stateGetters.current[key] = undefined;
};
},
[]
);
return {
getStateForRoute,
addStateGetter,
};
}

View File

@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.11](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.10...@react-navigation/drawer@5.0.0-alpha.11) (2019-10-03)
**Note:** Version bump only for package @react-navigation/drawer
# [5.0.0-alpha.10](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.9...@react-navigation/drawer@5.0.0-alpha.10) (2019-09-27)
### Features
* export some more type aliases ([8b78d61](https://github.com/react-navigation/navigation-ex/commit/8b78d61))
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.8...@react-navigation/drawer@5.0.0-alpha.9) (2019-09-16) # [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.8...@react-navigation/drawer@5.0.0-alpha.9) (2019-09-16)

View File

@@ -11,7 +11,7 @@
"material", "material",
"drawer" "drawer"
], ],
"version": "5.0.0-alpha.9", "version": "5.0.0-alpha.11",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -34,20 +34,20 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.7", "@react-navigation/routers": "^5.0.0-alpha.9",
"react-native-safe-area-view": "^0.14.6" "react-native-safe-area-view": "^0.14.7"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.7.0", "@react-native-community/bob": "^0.7.0",
"@types/react": "^16.8.24", "@types/react": "^16.9.4",
"@types/react-native": "^0.60.2", "@types/react-native": "^0.60.17",
"del-cli": "^2.0.0", "del-cli": "^3.0.0",
"react": "16.8.3", "react": "16.8.3",
"react-native": "0.59.10", "react-native": "0.59.10",
"react-native-gesture-handler": "^1.3.0", "react-native-gesture-handler": "^1.3.0",
"react-native-reanimated": "^1.1.0", "react-native-reanimated": "^1.3.0",
"react-native-screens": "^1.0.0-alpha.22", "react-native-screens": "^1.0.0-alpha.22",
"typescript": "^3.5.3" "typescript": "^3.6.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0", "@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -20,4 +20,8 @@ export { default as DrawerGestureContext } from './utils/DrawerGestureContext';
/** /**
* Types * Types
*/ */
export { DrawerNavigationOptions, DrawerNavigationProp } from './types'; export {
DrawerNavigationOptions,
DrawerNavigationProp,
DrawerNavigationItemsProps,
} from './types';

View File

@@ -578,7 +578,6 @@ export default class DrawerView extends React.PureComponent<Props> {
style={[ style={[
styles.container, styles.container,
right ? { right: offset } : { left: offset }, right ? { right: offset } : { left: offset },
// eslint-disable-next-line react-native/no-inline-styles
{ {
transform: [{ translateX: drawerTranslateX }], transform: [{ translateX: drawerTranslateX }],
opacity: this.drawerOpacity, opacity: this.drawerOpacity,

View File

@@ -163,7 +163,6 @@ export default class DrawerView extends React.PureComponent<Props, State> {
key={route.key} key={route.key}
style={[ style={[
StyleSheet.absoluteFill, StyleSheet.absoluteFill,
// eslint-disable-next-line react-native/no-inline-styles
{ opacity: isFocused ? 1 : 0 }, { opacity: isFocused ? 1 : 0 },
]} ]}
isVisible={isFocused} isVisible={isFocused}

View File

@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.9](https://github.com/satya164/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.8...@react-navigation/example@5.0.0-alpha.9) (2019-10-03)
**Note:** Version bump only for package @react-navigation/example
# [5.0.0-alpha.8](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.7...@react-navigation/example@5.0.0-alpha.8) (2019-09-27)
### Bug Fixes
* close drawer on navigate ([655a220](https://github.com/react-navigation/navigation-ex/commit/655a220))
# [5.0.0-alpha.7](https://github.com/satya164/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.6...@react-navigation/example@5.0.0-alpha.7) (2019-09-16) # [5.0.0-alpha.7](https://github.com/satya164/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.6...@react-navigation/example@5.0.0-alpha.7) (2019-09-16)

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="ReactNavigationExample" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,179 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.3.0" />
<option name="LAST_KNOWN_AGP_VERSION" value="3.3.0" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/build/generated/res/rs/debug;file://$MODULE_DIR$/build/generated/res/resValues/debug" />
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debug/compileDebugRenderscript/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/react/debug" type="java-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debugAndroidTest/compileDebugAndroidTestAidl/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debugAndroidTest/compileDebugAndroidTestRenderscript/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Gradle: com.android.support:collections:28.0.0@jar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.1@jar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.core:common:1.1.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:28.0.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.infer.annotation:infer-annotation:0.11.2@jar" level="project" />
<orderEntry type="library" name="Gradle: javax.inject:javax.inject:1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.google.code.findbugs:jsr305:3.0.2@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp-urlconnection:3.12.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp:3.12.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okio:okio:1.15.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.device.yearclass:yearclass:2.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: commons-codec:commons-codec:1.10@jar" level="project" />
<orderEntry type="library" name="Gradle: commons-io:commons-io:1.4@jar" level="project" />
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:disklrucache:4.9.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:annotations:4.9.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.parse.bolts:bolts-tasks:1.4.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.react:react-native:0.59.10@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:glide:4.9.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-location:16.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-base:16.0.1@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-places-placereport:16.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-tasks:16.0.1@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-basement:16.0.1@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-v4:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-fragment:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:customtabs:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:loader:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-media-compat:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:viewpager:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:coordinatorlayout:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:drawerlayout:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:slidingpanelayout:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:customview:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:swiperefreshlayout:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:asynclayoutinflater:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-compat:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:versionedparcelable:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:cursoradapter:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime:1.1.1@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:documentfile:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:localbroadcastmanager:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:print:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel:1.1.1@aar" level="project" />
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:gifdecoder:4.9.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:interpolator:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata:1.1.1@aar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core:1.1.1@aar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.core:runtime:1.1.1@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:fresco:1.10.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline-okhttp3:1.10.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:drawee:1.10.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline:1.10.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline-base:1.10.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.soloader:soloader:0.6.0@aar" level="project" />
<orderEntry type="library" name="Gradle: io.nlopez.smartlocation:library:3.2.11@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:fbcore:1.10.0@aar" level="project" />
<orderEntry type="module" module-name="react-native-reanimated" />
<orderEntry type="module" module-name="react-native-gesture-handler" />
<orderEntry type="module" module-name="expo-permissions" />
<orderEntry type="module" module-name="unimodules-core" />
<orderEntry type="module" module-name="unimodules-react-native-adapter" />
<orderEntry type="module" module-name="expo-app-loader-provider" />
<orderEntry type="module" module-name="expo-constants" />
<orderEntry type="module" module-name="expo-file-system" />
<orderEntry type="module" module-name="expo-font" />
<orderEntry type="module" module-name="expo-keep-awake" />
<orderEntry type="module" module-name="expo-linear-gradient" />
<orderEntry type="module" module-name="expo-location" />
<orderEntry type="module" module-name="expo-sqlite" />
<orderEntry type="module" module-name="expo-web-browser" />
<orderEntry type="module" module-name="unimodules-barcode-scanner-interface" />
<orderEntry type="module" module-name="unimodules-camera-interface" />
<orderEntry type="module" module-name="unimodules-constants-interface" />
<orderEntry type="module" module-name="unimodules-face-detector-interface" />
<orderEntry type="module" module-name="unimodules-file-system-interface" />
<orderEntry type="module" module-name="unimodules-font-interface" />
<orderEntry type="module" module-name="unimodules-image-loader-interface" />
<orderEntry type="module" module-name="unimodules-permissions-interface" />
<orderEntry type="module" module-name="unimodules-sensors-interface" />
<orderEntry type="module" module-name="unimodules-task-manager-interface" />
</component>
</module>

View File

@@ -0,0 +1,8 @@
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Wed Sep 18 15:42:44 CEST 2019
sdk.dir=/Users/osdnk/Library/Android/sdk

View File

@@ -1,5 +1,3 @@
/* eslint-disable import/no-commonjs */
module.exports = function(api) { module.exports = function(api) {
api.cache(true); api.cache(true);
return { return {

View File

@@ -1,4 +1,4 @@
/* eslint-disable import/no-commonjs, import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');

View File

@@ -1,7 +1,7 @@
{ {
"name": "@react-navigation/example", "name": "@react-navigation/example",
"description": "Demo app to showcase various functionality of React Navigation", "description": "Demo app to showcase various functionality of React Navigation",
"version": "5.0.0-alpha.7", "version": "5.0.0-alpha.9",
"private": true, "private": true,
"workspaces": { "workspaces": {
"nohoist": [ "nohoist": [
@@ -18,29 +18,29 @@
"dependencies": { "dependencies": {
"@expo/vector-icons": "^10.0.0", "@expo/vector-icons": "^10.0.0",
"@react-native-community/masked-view": "^0.1.1", "@react-native-community/masked-view": "^0.1.1",
"expo": "^34.0.1", "expo": "^35.0.0",
"expo-asset": "~6.0.0", "expo-asset": "~7.0.0",
"query-string": "^6.8.3", "query-string": "^6.8.3",
"react": "16.8.3", "react": "^16.10.1",
"react-dom": "^16.8.3", "react-dom": "^16.8.3",
"react-native": "0.59.10", "react-native": "^0.61.2",
"react-native-gesture-handler": "~1.3.0", "react-native-gesture-handler": "~1.3.0",
"react-native-paper": "^3.0.0-alpha.3", "react-native-paper": "^3.0.0-alpha.3",
"react-native-reanimated": "~1.1.0", "react-native-reanimated": "~1.2.0",
"react-native-screens": "1.0.0-alpha.22", "react-native-screens": "~1.0.0-alpha.23",
"react-native-tab-view": "2.7.1", "react-native-tab-view": "2.10.0",
"react-native-unimodules": "~0.5.2", "react-native-unimodules": "^0.7.0-rc.1",
"scheduler": "^0.14.0", "scheduler": "^0.16.1",
"shortid": "^2.2.14", "shortid": "^2.2.15",
"use-subscription": "^1.0.0" "use-subscription": "^1.1.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.5.5", "@babel/core": "^7.6.2",
"@types/react": "^16.8.23", "@types/react": "^16.9.4",
"@types/react-native": "^0.57.65", "@types/react-native": "^0.60.17",
"babel-preset-expo": "^6.0.0", "babel-preset-expo": "^7.0.0",
"expo-cli": "^3.0.10", "expo-cli": "^3.1.2",
"typescript": "^3.5.3" "typescript": "^3.6.3"
}, },
"resolutions": { "resolutions": {
"react-native-safe-area-view": "0.14.7" "react-native-safe-area-view": "0.14.7"

View File

@@ -1,5 +1,3 @@
/* eslint-disable import/namespace, import/default */
import * as React from 'react'; import * as React from 'react';
import { MaterialIcons } from '@expo/vector-icons'; import { MaterialIcons } from '@expo/vector-icons';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

View File

@@ -25,6 +25,7 @@ export default function Albums() {
contentContainerStyle={styles.content} contentContainerStyle={styles.content}
> >
{COVERS.map((source, i) => ( {COVERS.map((source, i) => (
// eslint-disable-next-line react/no-array-index-key
<Image key={i} source={source} style={styles.cover} /> <Image key={i} source={source} style={styles.cover} />
))} ))}
</ScrollView> </ScrollView>

View File

@@ -32,6 +32,7 @@ export default function Chat() {
return ( return (
<View <View
// eslint-disable-next-line react/no-array-index-key
key={i} key={i}
style={[odd ? styles.odd : styles.even, styles.inverted]} style={[odd ? styles.odd : styles.even, styles.inverted]}
> >

View File

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

View File

@@ -11,7 +11,7 @@
"material", "material",
"tab" "tab"
], ],
"version": "5.0.0-alpha.8", "version": "5.0.0-alpha.10",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -34,19 +34,19 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.7" "@react-navigation/routers": "^5.0.0-alpha.9"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.7.0", "@react-native-community/bob": "^0.7.0",
"@types/react": "^16.8.24", "@types/react": "^16.9.4",
"@types/react-native": "^0.60.2", "@types/react-native": "^0.60.17",
"@types/react-native-vector-icons": "^6.4.1", "@types/react-native-vector-icons": "^6.4.4",
"del-cli": "^2.0.0", "del-cli": "^3.0.0",
"react": "16.8.3", "react": "16.8.3",
"react-native": "0.59.10", "react-native": "0.59.10",
"react-native-paper": "^3.0.0-alpha.3", "react-native-paper": "^3.0.0-alpha.3",
"react-native-vector-icons": "^6.6.0", "react-native-vector-icons": "^6.6.0",
"typescript": "^3.5.3" "typescript": "^3.6.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0", "@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-top-tabs@5.0.0-alpha.8...@react-navigation/material-top-tabs@5.0.0-alpha.9) (2019-10-03)
**Note:** Version bump only for package @react-navigation/material-top-tabs
# [5.0.0-alpha.8](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-top-tabs@5.0.0-alpha.7...@react-navigation/material-top-tabs@5.0.0-alpha.8) (2019-09-27)
### Features
* export some more type aliases ([8b78d61](https://github.com/react-navigation/navigation-ex/commit/8b78d61))
# [5.0.0-alpha.7](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-top-tabs@5.0.0-alpha.6...@react-navigation/material-top-tabs@5.0.0-alpha.7) (2019-08-31) # [5.0.0-alpha.7](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-top-tabs@5.0.0-alpha.6...@react-navigation/material-top-tabs@5.0.0-alpha.7) (2019-08-31)
**Note:** Version bump only for package @react-navigation/material-top-tabs **Note:** Version bump only for package @react-navigation/material-top-tabs

View File

@@ -11,7 +11,7 @@
"material", "material",
"tab" "tab"
], ],
"version": "5.0.0-alpha.7", "version": "5.0.0-alpha.9",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -34,19 +34,19 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.7" "@react-navigation/routers": "^5.0.0-alpha.9"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.7.0", "@react-native-community/bob": "^0.7.0",
"@types/react": "^16.8.24", "@types/react": "^16.9.4",
"@types/react-native": "^0.60.2", "@types/react-native": "^0.60.17",
"del-cli": "^2.0.0", "del-cli": "^3.0.0",
"react": "16.8.3", "react": "16.8.3",
"react-native": "^0.59.8", "react-native": "^0.59.8",
"react-native-gesture-handler": "^1.3.0", "react-native-gesture-handler": "^1.3.0",
"react-native-reanimated": "^1.1.0", "react-native-reanimated": "^1.3.0",
"react-native-tab-view": "^2.10.0", "react-native-tab-view": "^2.10.0",
"typescript": "^3.5.3" "typescript": "^3.6.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0", "@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -16,4 +16,6 @@ export { default as MaterialTopTabBar } from './views/MaterialTopTabBar';
export { export {
MaterialTopTabNavigationOptions, MaterialTopTabNavigationOptions,
MaterialTopTabNavigationProp, MaterialTopTabNavigationProp,
MaterialTopTabBarProps,
MaterialTopTabBarOptions,
} from './types'; } from './types';

View File

@@ -3,6 +3,14 @@
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.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native@5.0.0-alpha.8...@react-navigation/native@5.0.0-alpha.9) (2019-10-03)
**Note:** Version bump only for package @react-navigation/native
# [5.0.0-alpha.8](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native@5.0.0-alpha.7...@react-navigation/native@5.0.0-alpha.8) (2019-09-16) # [5.0.0-alpha.8](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native@5.0.0-alpha.7...@react-navigation/native@5.0.0-alpha.8) (2019-09-16)

View File

@@ -7,7 +7,7 @@
"ios", "ios",
"android" "android"
], ],
"version": "5.0.0-alpha.8", "version": "5.0.0-alpha.9",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -31,12 +31,12 @@
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.7.0", "@react-native-community/bob": "^0.7.0",
"@types/react": "^16.8.24", "@types/react": "^16.9.4",
"@types/react-native": "^0.60.2", "@types/react-native": "^0.60.17",
"del-cli": "^2.0.0", "del-cli": "^3.0.0",
"react": "16.8.3", "react": "16.8.3",
"react-native": "0.59.10", "react-native": "0.59.10",
"typescript": "^3.5.3" "typescript": "^3.6.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0", "@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.8...@react-navigation/routers@5.0.0-alpha.9) (2019-10-03)
**Note:** Version bump only for package @react-navigation/routers
# [5.0.0-alpha.8](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.7...@react-navigation/routers@5.0.0-alpha.8) (2019-09-27)
### Bug Fixes
* close drawer on navigate ([655a220](https://github.com/react-navigation/navigation-ex/commit/655a220))
# [5.0.0-alpha.7](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.6...@react-navigation/routers@5.0.0-alpha.7) (2019-08-31) # [5.0.0-alpha.7](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.6...@react-navigation/routers@5.0.0-alpha.7) (2019-08-31)

View File

@@ -215,6 +215,36 @@ it('handles navigate action', () => {
}); });
}); });
it('handles navigate action with open drawer', () => {
const router = DrawerRouter({});
expect(
router.getStateForAction(
{
stale: false,
key: 'root',
index: 1,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
isDrawerOpen: true,
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
},
CommonActions.navigate('baz', { answer: 42 })
)
).toEqual({
stale: false,
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
isDrawerOpen: false,
routeKeyHistory: ['bar'],
routes: [
{ key: 'baz', name: 'baz', params: { answer: 42 } },
{ key: 'bar', name: 'bar' },
],
});
});
it('handles open drawer action', () => { it('handles open drawer action', () => {
const router = DrawerRouter({}); const router = DrawerRouter({});

View File

@@ -6,7 +6,7 @@
"react-native", "react-native",
"react-navigation" "react-navigation"
], ],
"version": "5.0.0-alpha.7", "version": "5.0.0-alpha.9",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -29,12 +29,12 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"shortid": "^2.2.14" "shortid": "^2.2.15"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.7.0", "@react-native-community/bob": "^0.7.0",
"del-cli": "^2.0.0", "del-cli": "^3.0.0",
"typescript": "^3.5.3" "typescript": "^3.6.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0" "@react-navigation/core": "^5.0.0-alpha.0"

View File

@@ -135,6 +135,15 @@ export default function DrawerRouter(
isDrawerOpen: !state.isDrawerOpen, isDrawerOpen: !state.isDrawerOpen,
}; };
case 'NAVIGATE':
return router.getStateForAction(
{
...state,
isDrawerOpen: false,
},
action
);
default: default:
return router.getStateForAction(state, action); return router.getStateForAction(state, action);
} }

View File

@@ -3,6 +3,70 @@
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.21](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.20...@react-navigation/stack@5.0.0-alpha.21) (2019-10-03)
### Bug Fixes
* add missing React import ([ece6e38](https://github.com/react-navigation/navigation-ex/commit/ece6e38))
* fix header buttons not clickable on Android. fixes [#108](https://github.com/react-navigation/navigation-ex/issues/108) ([da944cc](https://github.com/react-navigation/navigation-ex/commit/da944cc))
* keep the routes we are closing or replacing ([bc3586a](https://github.com/react-navigation/navigation-ex/commit/bc3586a))
# [5.0.0-alpha.20](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.19...@react-navigation/stack@5.0.0-alpha.20) (2019-09-27)
### Features
* export some more type aliases ([8b78d61](https://github.com/react-navigation/navigation-ex/commit/8b78d61))
# [5.0.0-alpha.19](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.18...@react-navigation/stack@5.0.0-alpha.19) (2019-09-23)
### Bug Fixes
* vertical gesture in stack ([4ee19bc](https://github.com/react-navigation/navigation-ex/commit/4ee19bc))
# [5.0.0-alpha.18](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.17...@react-navigation/stack@5.0.0-alpha.18) (2019-09-23)
### Bug Fixes
* fix header rendered behind card. closes [#108](https://github.com/react-navigation/navigation-ex/issues/108) ([2f66556](https://github.com/react-navigation/navigation-ex/commit/2f66556))
### Features
* **stack:** use Animated.Text for header title ([#105](https://github.com/react-navigation/navigation-ex/issues/105)) ([f398136](https://github.com/react-navigation/navigation-ex/commit/f398136))
* **stack:** use Animated.View for header background ([#106](https://github.com/react-navigation/navigation-ex/issues/106)) ([089390c](https://github.com/react-navigation/navigation-ex/commit/089390c))
# [5.0.0-alpha.17](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.16...@react-navigation/stack@5.0.0-alpha.17) (2019-09-17)
### Bug Fixes
* add fallbacks for non-web modules ([b4bbf9b](https://github.com/react-navigation/navigation-ex/commit/b4bbf9b)), closes [#95](https://github.com/react-navigation/navigation-ex/issues/95) [#96](https://github.com/react-navigation/navigation-ex/issues/96)
* provide navigation prop in header ([30e510d](https://github.com/react-navigation/navigation-ex/commit/30e510d))
# [5.0.0-alpha.16](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.15...@react-navigation/stack@5.0.0-alpha.16) (2019-09-16) # [5.0.0-alpha.16](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.15...@react-navigation/stack@5.0.0-alpha.16) (2019-09-16)

View File

@@ -10,7 +10,7 @@
"android", "android",
"stack" "stack"
], ],
"version": "5.0.0-alpha.16", "version": "5.0.0-alpha.21",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -33,21 +33,21 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.7", "@react-navigation/routers": "^5.0.0-alpha.9",
"react-native-safe-area-view": "^0.14.6" "react-native-safe-area-view": "^0.14.7"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.7.0", "@react-native-community/bob": "^0.7.0",
"@react-native-community/masked-view": "^0.1.1", "@react-native-community/masked-view": "^0.1.1",
"@types/react": "^16.8.24", "@types/react": "^16.9.4",
"@types/react-native": "^0.60.2", "@types/react-native": "^0.60.17",
"del-cli": "^2.0.0", "del-cli": "^3.0.0",
"react": "16.8.3", "react": "16.8.3",
"react-native": "0.59.10", "react-native": "0.59.10",
"react-native-gesture-handler": "^1.3.0", "react-native-gesture-handler": "^1.3.0",
"react-native-reanimated": "^1.1.0", "react-native-reanimated": "^1.3.0",
"react-native-screens": "^1.0.0-alpha.22", "react-native-screens": "^1.0.0-alpha.22",
"typescript": "^3.5.3" "typescript": "^3.6.3"
}, },
"peerDependencies": { "peerDependencies": {
"@react-native-community/masked-view": "^0.1.1", "@react-native-community/masked-view": "^0.1.1",

View File

@@ -1,7 +1,10 @@
import { I18nManager } from 'react-native'; import { I18nManager } from 'react-native';
import Animated from 'react-native-reanimated'; import Animated from 'react-native-reanimated';
import { CardInterpolationProps, CardInterpolatedStyle } from '../types'; import getStatusBarHeight from '../utils/getStatusBarHeight';
import { getStatusBarHeight } from 'react-native-safe-area-view'; import {
StackCardInterpolationProps,
StackCardInterpolatedStyle,
} from '../types';
const { cond, add, multiply, interpolate } = Animated; const { cond, add, multiply, interpolate } = Animated;
@@ -12,7 +15,7 @@ export function forHorizontalIOS({
current, current,
next, next,
layouts: { screen }, layouts: { screen },
}: CardInterpolationProps): CardInterpolatedStyle { }: StackCardInterpolationProps): StackCardInterpolatedStyle {
const translateFocused = interpolate(current.progress, { const translateFocused = interpolate(current.progress, {
inputRange: [0, 1], inputRange: [0, 1],
outputRange: [I18nManager.isRTL ? -screen.width : screen.width, 0], outputRange: [I18nManager.isRTL ? -screen.width : screen.width, 0],
@@ -57,7 +60,7 @@ export function forHorizontalIOS({
export function forVerticalIOS({ export function forVerticalIOS({
current, current,
layouts: { screen }, layouts: { screen },
}: CardInterpolationProps): CardInterpolatedStyle { }: StackCardInterpolationProps): StackCardInterpolatedStyle {
const translateY = interpolate(current.progress, { const translateY = interpolate(current.progress, {
inputRange: [0, 1], inputRange: [0, 1],
outputRange: [screen.height, 0], outputRange: [screen.height, 0],
@@ -81,7 +84,7 @@ export function forModalPresentationIOS({
current, current,
next, next,
layouts: { screen }, layouts: { screen },
}: CardInterpolationProps): CardInterpolatedStyle { }: StackCardInterpolationProps): StackCardInterpolatedStyle {
const topOffset = 10; const topOffset = 10;
const statusBarHeight = getStatusBarHeight(screen.width > screen.height); const statusBarHeight = getStatusBarHeight(screen.width > screen.height);
const aspectRatio = screen.height / screen.width; const aspectRatio = screen.height / screen.width;
@@ -134,7 +137,7 @@ export function forFadeFromBottomAndroid({
current, current,
layouts: { screen }, layouts: { screen },
closing, closing,
}: CardInterpolationProps): CardInterpolatedStyle { }: StackCardInterpolationProps): StackCardInterpolatedStyle {
const translateY = interpolate(current.progress, { const translateY = interpolate(current.progress, {
inputRange: [0, 1], inputRange: [0, 1],
outputRange: [multiply(screen.height, 0.08), 0], outputRange: [multiply(screen.height, 0.08), 0],
@@ -164,7 +167,7 @@ export function forRevealFromBottomAndroid({
current, current,
next, next,
layouts: { screen }, layouts: { screen },
}: CardInterpolationProps): CardInterpolatedStyle { }: StackCardInterpolationProps): StackCardInterpolatedStyle {
const containerTranslateY = interpolate(current.progress, { const containerTranslateY = interpolate(current.progress, {
inputRange: [0, 1], inputRange: [0, 1],
outputRange: [screen.height, 0], outputRange: [screen.height, 0],
@@ -206,7 +209,7 @@ export function forScaleFromCenterAndroid({
current, current,
next, next,
closing, closing,
}: CardInterpolationProps): CardInterpolatedStyle { }: StackCardInterpolationProps): StackCardInterpolatedStyle {
const progress = add(current.progress, next ? next.progress : 0); const progress = add(current.progress, next ? next.progress : 0);
const opacity = interpolate(progress, { const opacity = interpolate(progress, {

View File

@@ -1,6 +1,9 @@
import { I18nManager } from 'react-native'; import { I18nManager } from 'react-native';
import Animated from 'react-native-reanimated'; import Animated from 'react-native-reanimated';
import { HeaderInterpolationProps, HeaderInterpolatedStyle } from '../types'; import {
StackHeaderInterpolationProps,
StackHeaderInterpolatedStyle,
} from '../types';
const { interpolate, add } = Animated; const { interpolate, add } = Animated;
@@ -11,7 +14,7 @@ export function forUIKit({
current, current,
next, next,
layouts, layouts,
}: HeaderInterpolationProps): HeaderInterpolatedStyle { }: StackHeaderInterpolationProps): StackHeaderInterpolatedStyle {
const defaultOffset = 100; const defaultOffset = 100;
const leftSpacing = 27; const leftSpacing = 27;
@@ -95,7 +98,7 @@ export function forUIKit({
export function forFade({ export function forFade({
current, current,
next, next,
}: HeaderInterpolationProps): HeaderInterpolatedStyle { }: StackHeaderInterpolationProps): StackHeaderInterpolatedStyle {
const progress = add(current.progress, next ? next.progress : 0); const progress = add(current.progress, next ? next.progress : 0);
const opacity = interpolate(progress, { const opacity = interpolate(progress, {
inputRange: [0, 1, 2], inputRange: [0, 1, 2],
@@ -117,7 +120,7 @@ export function forStatic({
current, current,
next, next,
layouts: { screen }, layouts: { screen },
}: HeaderInterpolationProps): HeaderInterpolatedStyle { }: StackHeaderInterpolationProps): StackHeaderInterpolatedStyle {
const progress = add(current.progress, next ? next.progress : 0); const progress = add(current.progress, next ? next.progress : 0);
const translateX = interpolate(progress, { const translateX = interpolate(progress, {
inputRange: [0, 1, 2], inputRange: [0, 1, 2],
@@ -136,6 +139,6 @@ export function forStatic({
}; };
} }
export function forNoAnimation(): HeaderInterpolatedStyle { export function forNoAnimation(): StackHeaderInterpolatedStyle {
return {}; return {};
} }

View File

@@ -34,4 +34,16 @@ export { default as StackGestureContext } from './utils/StackGestureContext';
/** /**
* Types * Types
*/ */
export { StackNavigationOptions, StackNavigationProp } from './types'; export {
StackNavigationOptions,
StackNavigationProp,
StackHeaderProps,
StackHeaderLeftButtonProps,
StackHeaderTitleProps,
StackCardInterpolatedStyle,
StackCardInterpolationProps,
StackCardStyleInterpolator,
StackHeaderInterpolatedStyle,
StackHeaderInterpolationProps,
StackHeaderStyleInterpolator,
} from './types';

View File

@@ -67,9 +67,7 @@ export type Layout = { width: number; height: number };
export type GestureDirection = 'horizontal' | 'vertical'; export type GestureDirection = 'horizontal' | 'vertical';
export type HeaderMode = 'float' | 'screen' | 'none'; export type Scene<T> = {
export type HeaderScene<T> = {
/** /**
* Current route object, * Current route object,
*/ */
@@ -99,14 +97,16 @@ export type HeaderScene<T> = {
}; };
}; };
export type HeaderOptions = { export type StackHeaderMode = 'float' | 'screen' | 'none';
export type StackHeaderOptions = {
/** /**
* String or a function that returns a React Element to be used by the header. * String or a function that returns a React Element to be used by the header.
* Defaults to scene `title`. * Defaults to scene `title`.
* It receives `allowFontScaling`, `onLayout`, `style` and `children` in the options object as an argument. * It receives `allowFontScaling`, `onLayout`, `style` and `children` in the options object as an argument.
* The title string is passed in `children`. * The title string is passed in `children`.
*/ */
headerTitle?: string | ((props: HeaderTitleProps) => React.ReactNode); headerTitle?: string | ((props: StackHeaderTitleProps) => React.ReactNode);
/** /**
* Style object for the title component. * Style object for the title component.
*/ */
@@ -151,7 +151,7 @@ export type HeaderOptions = {
* Function which returns a React Element to display on the left side of the header. * Function which returns a React Element to display on the left side of the header.
* It receives a number of arguments when rendered (`onPress`, `label`, `labelStyle` and more. * It receives a number of arguments when rendered (`onPress`, `label`, `labelStyle` and more.
*/ */
headerLeft?: (props: HeaderLeftButtonProps) => React.ReactNode; headerLeft?: (props: StackHeaderLeftButtonProps) => React.ReactNode;
/** /**
* Style object for the container of the `headerLeft` component, for example to add padding. * Style object for the container of the `headerLeft` component, for example to add padding.
*/ */
@@ -169,7 +169,7 @@ export type HeaderOptions = {
* It receives the `tintColor` in in the options object as an argument. object. * It receives the `tintColor` in in the options object as an argument. object.
* Defaults to Image component with a the default back icon image for the platform (a chevron on iOS and an arrow on Android). * Defaults to Image component with a the default back icon image for the platform (a chevron on iOS and an arrow on Android).
*/ */
headerBackImage?: HeaderLeftButtonProps['backImage']; headerBackImage?: StackHeaderLeftButtonProps['backImage'];
/** /**
* Color for material ripple (Android >= 5.0 only). * Color for material ripple (Android >= 5.0 only).
*/ */
@@ -196,7 +196,7 @@ export type HeaderOptions = {
headerTransparent?: boolean; headerTransparent?: boolean;
}; };
export type HeaderProps = { export type StackHeaderProps = {
/** /**
* Mode of the header: `float` renders a single floating header across all screens, * Mode of the header: `float` renders a single floating header across all screens,
* `screen` renders separate headers for each screen. * `screen` renders separate headers for each screen.
@@ -209,11 +209,11 @@ export type HeaderProps = {
/** /**
* Object representing the current scene, such as the route object and animation progress. * Object representing the current scene, such as the route object and animation progress.
*/ */
scene: HeaderScene<Route<string>>; scene: Scene<Route<string>>;
/** /**
* Object representing the previous scene. * Object representing the previous scene.
*/ */
previous?: HeaderScene<Route<string>>; previous?: Scene<Route<string>>;
/** /**
* Navigation prop for the header. * Navigation prop for the header.
*/ */
@@ -221,7 +221,7 @@ export type HeaderProps = {
/** /**
* Interpolated styles for various elements in the header. * Interpolated styles for various elements in the header.
*/ */
styleInterpolator: HeaderStyleInterpolator; styleInterpolator: StackHeaderStyleInterpolator;
}; };
export type StackDescriptor = Descriptor< export type StackDescriptor = Descriptor<
@@ -235,7 +235,7 @@ export type StackDescriptorMap = {
[key: string]: StackDescriptor; [key: string]: StackDescriptor;
}; };
export type StackNavigationOptions = HeaderOptions & export type StackNavigationOptions = StackHeaderOptions &
Partial<TransitionPreset> & { Partial<TransitionPreset> & {
/** /**
* String that can be displayed in the header as a fallback for `headerTitle`. * String that can be displayed in the header as a fallback for `headerTitle`.
@@ -245,7 +245,7 @@ export type StackNavigationOptions = HeaderOptions &
* Function that given `HeaderProps` returns a React Element to display as a header. * Function that given `HeaderProps` returns a React Element to display as a header.
* Setting to `null` hides header. * Setting to `null` hides header.
*/ */
header?: null | ((props: HeaderProps) => React.ReactNode); header?: null | ((props: StackHeaderProps) => React.ReactNode);
/** /**
* Whether a shadow is visible for the card during transitions. Defaults to `true`. * Whether a shadow is visible for the card during transitions. Defaults to `true`.
*/ */
@@ -295,7 +295,7 @@ export type StackNavigationOptions = HeaderOptions &
export type StackNavigationConfig = { export type StackNavigationConfig = {
mode?: 'card' | 'modal'; mode?: 'card' | 'modal';
headerMode?: HeaderMode; headerMode?: StackHeaderMode;
/** /**
* If `false`, the keyboard will NOT automatically dismiss when navigating to a new screen. * If `false`, the keyboard will NOT automatically dismiss when navigating to a new screen.
* Defaults to `true`. * Defaults to `true`.
@@ -303,7 +303,7 @@ export type StackNavigationConfig = {
keyboardHandlingEnabled?: boolean; keyboardHandlingEnabled?: boolean;
}; };
export type HeaderLeftButtonProps = { export type StackHeaderLeftButtonProps = {
/** /**
* Whether the button is disabled. * Whether the button is disabled.
*/ */
@@ -365,7 +365,7 @@ export type HeaderLeftButtonProps = {
canGoBack?: boolean; canGoBack?: boolean;
}; };
export type HeaderTitleProps = { export type StackHeaderTitleProps = {
/** /**
* Callback to trigger when the size of the title element changes. * Callback to trigger when the size of the title element changes.
*/ */
@@ -408,7 +408,7 @@ export type TransitionSpec =
| { animation: 'spring'; config: SpringConfig } | { animation: 'spring'; config: SpringConfig }
| { animation: 'timing'; config: TimingConfig }; | { animation: 'timing'; config: TimingConfig };
export type CardInterpolationProps = { export type StackCardInterpolationProps = {
/** /**
* Values for the current screen. * Values for the current screen.
*/ */
@@ -447,7 +447,7 @@ export type CardInterpolationProps = {
}; };
}; };
export type CardInterpolatedStyle = { export type StackCardInterpolatedStyle = {
/** /**
* Interpolated style for the container view wrapping the card. * Interpolated style for the container view wrapping the card.
*/ */
@@ -466,11 +466,11 @@ export type CardInterpolatedStyle = {
shadowStyle?: any; shadowStyle?: any;
}; };
export type CardStyleInterpolator = ( export type StackCardStyleInterpolator = (
props: CardInterpolationProps props: StackCardInterpolationProps
) => CardInterpolatedStyle; ) => StackCardInterpolatedStyle;
export type HeaderInterpolationProps = { export type StackHeaderInterpolationProps = {
/** /**
* Values for the current screen (the screen which owns this header). * Values for the current screen (the screen which owns this header).
*/ */
@@ -509,7 +509,7 @@ export type HeaderInterpolationProps = {
}; };
}; };
export type HeaderInterpolatedStyle = { export type StackHeaderInterpolatedStyle = {
/** /**
* Interpolated style for the label of the left button (back button label). * Interpolated style for the label of the left button (back button label).
*/ */
@@ -532,9 +532,9 @@ export type HeaderInterpolatedStyle = {
backgroundStyle?: any; backgroundStyle?: any;
}; };
export type HeaderStyleInterpolator = ( export type StackHeaderStyleInterpolator = (
props: HeaderInterpolationProps props: StackHeaderInterpolationProps
) => HeaderInterpolatedStyle; ) => StackHeaderInterpolatedStyle;
export type TransitionPreset = { export type TransitionPreset = {
/** /**
@@ -557,9 +557,9 @@ export type TransitionPreset = {
/** /**
* Function which specifies interpolated styles for various parts of the card, e.g. the overlay, shadow etc. * Function which specifies interpolated styles for various parts of the card, e.g. the overlay, shadow etc.
*/ */
cardStyleInterpolator: CardStyleInterpolator; cardStyleInterpolator: StackCardStyleInterpolator;
/** /**
* Function which specifies interpolated styles for various parts of the header, e.g. the title, left button etc. * Function which specifies interpolated styles for various parts of the header, e.g. the title, left button etc.
*/ */
headerStyleInterpolator: HeaderStyleInterpolator; headerStyleInterpolator: StackHeaderStyleInterpolator;
}; };

View File

@@ -0,0 +1,9 @@
import { Platform } from 'react-native';
import { getStatusBarHeight as getStatusBarHeightNative } from 'react-native-safe-area-view';
const getStatusBarHeight = Platform.select({
default: getStatusBarHeightNative,
web: () => 0,
});
export default getStatusBarHeight;

View File

@@ -1,67 +1,59 @@
import * as React from 'react'; import * as React from 'react';
import { StackActions } from '@react-navigation/routers'; import { StackActions } from '@react-navigation/routers';
import HeaderSegment from './HeaderSegment'; import HeaderSegment from './HeaderSegment';
import { HeaderProps, HeaderTitleProps } from '../../types'; import { StackHeaderProps, StackHeaderTitleProps } from '../../types';
import HeaderTitle from './HeaderTitle'; import HeaderTitle from './HeaderTitle';
export default class Header extends React.PureComponent<HeaderProps> { export default React.memo(function Header(props: StackHeaderProps) {
render() { const { scene, previous, layout, navigation, styleInterpolator } = props;
const { const { options } = scene.descriptor;
scene, const title =
previous, typeof options.headerTitle !== 'function' &&
layout, options.headerTitle !== undefined
navigation, ? options.headerTitle
styleInterpolator, : options.title !== undefined
} = this.props; ? options.title
const { options } = scene.descriptor; : scene.route.name;
const title =
typeof options.headerTitle !== 'function' &&
options.headerTitle !== undefined
? options.headerTitle
: options.title !== undefined
? options.title
: scene.route.name;
let leftLabel; let leftLabel;
// The label for the left back button shows the title of the previous screen // The label for the left back button shows the title of the previous screen
// If a custom label is specified, we use it, otherwise use previous screen's title // If a custom label is specified, we use it, otherwise use previous screen's title
if (options.headerBackTitle !== undefined) { if (options.headerBackTitle !== undefined) {
leftLabel = options.headerBackTitle; leftLabel = options.headerBackTitle;
} else if (previous) { } else if (previous) {
const o = previous.descriptor.options; const o = previous.descriptor.options;
leftLabel = leftLabel =
typeof o.headerTitle !== 'function' && o.headerTitle !== undefined typeof o.headerTitle !== 'function' && o.headerTitle !== undefined
? o.headerTitle ? o.headerTitle
: o.title !== undefined : o.title !== undefined
? o.title ? o.title
: previous.route.name; : previous.route.name;
}
return (
<HeaderSegment
{...options}
layout={layout}
scene={scene}
title={title}
leftLabel={leftLabel}
headerTitle={
typeof options.headerTitle !== 'function'
? (props: HeaderTitleProps) => <HeaderTitle {...props} />
: options.headerTitle
}
onGoBack={
previous
? () =>
navigation.dispatch({
...StackActions.pop(),
source: scene.route.key,
})
: undefined
}
styleInterpolator={styleInterpolator}
/>
);
} }
}
return (
<HeaderSegment
{...options}
layout={layout}
scene={scene}
title={title}
leftLabel={leftLabel}
headerTitle={
typeof options.headerTitle !== 'function'
? (props: StackHeaderTitleProps) => <HeaderTitle {...props} />
: options.headerTitle
}
onGoBack={
previous
? () =>
navigation.dispatch({
...StackActions.pop(),
source: scene.route.key,
})
: undefined
}
styleInterpolator={styleInterpolator}
/>
);
});

View File

@@ -6,18 +6,13 @@ import {
Platform, Platform,
StyleSheet, StyleSheet,
LayoutChangeEvent, LayoutChangeEvent,
UIManager,
} from 'react-native'; } from 'react-native';
import Animated from 'react-native-reanimated'; import Animated from 'react-native-reanimated';
import MaskedView from '@react-native-community/masked-view'; import MaskedView from '../MaskedView';
import TouchableItem from '../TouchableItem'; import TouchableItem from '../TouchableItem';
import { HeaderLeftButtonProps } from '../../types'; import { StackHeaderLeftButtonProps } from '../../types';
const isMaskedViewAvailable = type Props = StackHeaderLeftButtonProps & {
// @ts-ignore
UIManager.getViewManagerConfig('RNCMaskedView') != null;
type Props = HeaderLeftButtonProps & {
tintColor: string; tintColor: string;
}; };
@@ -129,7 +124,7 @@ class HeaderBackButton extends React.Component<Props, State> {
</View> </View>
); );
if (!isMaskedViewAvailable || backImage || Platform.OS !== 'ios') { if (backImage || Platform.OS !== 'ios') {
// When a custom backimage is specified, we can't mask the label // When a custom backimage is specified, we can't mask the label
// Otherwise there might be weird effect due to our mask not being the same as the image // Otherwise there might be weird effect due to our mask not being the same as the image
return labelElement; return labelElement;

View File

@@ -1,8 +1,9 @@
import * as React from 'react'; import * as React from 'react';
import { View, StyleSheet, Platform, ViewProps } from 'react-native'; import { StyleSheet, Platform, ViewProps } from 'react-native';
import Animated from 'react-native-reanimated';
export default function HeaderBackground({ style, ...rest }: ViewProps) { export default function HeaderBackground({ style, ...rest }: ViewProps) {
return <View style={[styles.container, style]} {...rest} />; return <Animated.View style={[styles.container, style]} {...rest} />;
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({

View File

@@ -1,21 +1,25 @@
import * as React from 'react'; import * as React from 'react';
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native'; import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
import { Route, ParamListBase } from '@react-navigation/core'; import {
NavigationContext,
Route,
ParamListBase,
} from '@react-navigation/core';
import { StackNavigationState } from '@react-navigation/routers'; import { StackNavigationState } from '@react-navigation/routers';
import Header from './Header'; import Header from './Header';
import { forStatic } from '../../TransitionConfigs/HeaderStyleInterpolators'; import { forStatic } from '../../TransitionConfigs/HeaderStyleInterpolators';
import { import {
Layout, Layout,
HeaderScene, Scene,
HeaderStyleInterpolator, StackHeaderStyleInterpolator,
StackNavigationProp, StackNavigationProp,
} from '../../types'; } from '../../types';
export type Props = { export type Props = {
mode: 'float' | 'screen'; mode: 'float' | 'screen';
layout: Layout; layout: Layout;
scenes: Array<HeaderScene<Route<string>> | undefined>; scenes: Array<Scene<Route<string>> | undefined>;
state: StackNavigationState; state: StackNavigationState;
getPreviousRoute: (props: { getPreviousRoute: (props: {
route: Route<string>; route: Route<string>;
@@ -24,7 +28,7 @@ export type Props = {
route: Route<string>; route: Route<string>;
height: number; height: number;
}) => void; }) => void;
styleInterpolator: HeaderStyleInterpolator; styleInterpolator: StackHeaderStyleInterpolator;
style?: StyleProp<ViewStyle>; style?: StyleProp<ViewStyle>;
}; };
@@ -92,36 +96,40 @@ export default function HeaderContainer({
}; };
return ( return (
<View <NavigationContext.Provider
key={scene.route.key} key={scene.route.key}
onLayout={ value={scene.descriptor.navigation}
onContentHeightChange
? e =>
onContentHeightChange({
route: scene.route,
height: e.nativeEvent.layout.height,
})
: undefined
}
pointerEvents="box-none"
accessibilityElementsHidden={!isFocused}
importantForAccessibility={
isFocused ? 'auto' : 'no-hide-descendants'
}
style={
mode === 'float' || options.headerTransparent
? styles.header
: null
}
> >
{options.header !== undefined ? ( <View
options.header === null ? null : ( onLayout={
options.header(props) onContentHeightChange
) ? e =>
) : ( onContentHeightChange({
<Header {...props} /> route: scene.route,
)} height: e.nativeEvent.layout.height,
</View> })
: undefined
}
pointerEvents="box-none"
accessibilityElementsHidden={!isFocused}
importantForAccessibility={
isFocused ? 'auto' : 'no-hide-descendants'
}
style={
mode === 'float' || options.headerTransparent
? styles.header
: null
}
>
{options.header !== undefined ? (
options.header === null ? null : (
options.header(props)
)
) : (
<Header {...props} />
)}
</View>
</NavigationContext.Provider>
); );
})} })}
</View> </View>

View File

@@ -7,18 +7,18 @@ import {
ViewStyle, ViewStyle,
} from 'react-native'; } from 'react-native';
import Animated from 'react-native-reanimated'; import Animated from 'react-native-reanimated';
import { getStatusBarHeight } from 'react-native-safe-area-view';
import { Route } from '@react-navigation/core'; import { Route } from '@react-navigation/core';
import HeaderBackButton from './HeaderBackButton'; import HeaderBackButton from './HeaderBackButton';
import HeaderBackground from './HeaderBackground'; import HeaderBackground from './HeaderBackground';
import getStatusBarHeight from '../../utils/getStatusBarHeight';
import memoize from '../../utils/memoize'; import memoize from '../../utils/memoize';
import { import {
Layout, Layout,
HeaderStyleInterpolator, StackHeaderStyleInterpolator,
HeaderLeftButtonProps, StackHeaderLeftButtonProps,
HeaderTitleProps, StackHeaderTitleProps,
HeaderOptions, StackHeaderOptions,
HeaderScene, Scene,
} from '../../types'; } from '../../types';
export type Scene<T> = { export type Scene<T> = {
@@ -26,14 +26,14 @@ export type Scene<T> = {
progress: Animated.Node<number>; progress: Animated.Node<number>;
}; };
type Props = HeaderOptions & { type Props = StackHeaderOptions & {
headerTitle: (props: HeaderTitleProps) => React.ReactNode; headerTitle: (props: StackHeaderTitleProps) => React.ReactNode;
layout: Layout; layout: Layout;
onGoBack?: () => void; onGoBack?: () => void;
title?: string; title?: string;
leftLabel?: string; leftLabel?: string;
scene: HeaderScene<Route<string>>; scene: Scene<Route<string>>;
styleInterpolator: HeaderStyleInterpolator; styleInterpolator: StackHeaderStyleInterpolator;
}; };
type State = { type State = {
@@ -113,7 +113,7 @@ export default class HeaderSegment extends React.Component<Props, State> {
private getInterpolatedStyle = memoize( private getInterpolatedStyle = memoize(
( (
styleInterpolator: HeaderStyleInterpolator, styleInterpolator: StackHeaderStyleInterpolator,
layout: Layout, layout: Layout,
current: Animated.Node<number>, current: Animated.Node<number>,
next: Animated.Node<number> | undefined, next: Animated.Node<number> | undefined,
@@ -140,7 +140,7 @@ export default class HeaderSegment extends React.Component<Props, State> {
onGoBack, onGoBack,
headerTitle, headerTitle,
headerLeft: left = onGoBack headerLeft: left = onGoBack
? (props: HeaderLeftButtonProps) => <HeaderBackButton {...props} /> ? (props: StackHeaderLeftButtonProps) => <HeaderBackButton {...props} />
: undefined, : undefined,
// @ts-ignore // @ts-ignore
headerStatusBarHeight = getStatusBarHeight(layout.width > layout.height), headerStatusBarHeight = getStatusBarHeight(layout.width > layout.height),

View File

@@ -1,12 +1,13 @@
import * as React from 'react'; import * as React from 'react';
import { Text, StyleSheet, Platform, TextProps } from 'react-native'; import { StyleSheet, Platform, TextProps } from 'react-native';
import Animated from 'react-native-reanimated';
type Props = TextProps & { type Props = TextProps & {
children?: string; children?: string;
}; };
export default function HeaderTitle({ style, ...rest }: Props) { export default function HeaderTitle({ style, ...rest }: Props) {
return <Text {...rest} style={[styles.title, style]} />; return <Animated.Text {...rest} style={[styles.title, style]} />;
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({

View File

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

View File

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

View File

@@ -16,7 +16,7 @@ import {
} from 'react-native-gesture-handler'; } from 'react-native-gesture-handler';
import { import {
TransitionSpec, TransitionSpec,
CardStyleInterpolator, StackCardStyleInterpolator,
Layout, Layout,
SpringConfig, SpringConfig,
TimingConfig, TimingConfig,
@@ -52,7 +52,7 @@ type Props = ViewProps & {
open: TransitionSpec; open: TransitionSpec;
close: TransitionSpec; close: TransitionSpec;
}; };
styleInterpolator: CardStyleInterpolator; styleInterpolator: StackCardStyleInterpolator;
containerStyle?: StyleProp<ViewStyle>; containerStyle?: StyleProp<ViewStyle>;
contentStyle?: StyleProp<ViewStyle>; contentStyle?: StyleProp<ViewStyle>;
}; };
@@ -122,9 +122,8 @@ const {
// We need to be prepared for both version of reanimated. With and w/out proc // We need to be prepared for both version of reanimated. With and w/out proc
let memoizedSpring = spring; let memoizedSpring = spring;
// @ts-ignore
if (Animated.proc) { if (Animated.proc) {
// @ts-ignore
const springHelper = Animated.proc( const springHelper = Animated.proc(
( (
finished: Animated.Value<number>, finished: Animated.Value<number>,
@@ -136,7 +135,7 @@ if (Animated.proc) {
damping: Animated.Adaptable<number>, damping: Animated.Adaptable<number>,
mass: Animated.Adaptable<number>, mass: Animated.Adaptable<number>,
stiffness: Animated.Adaptable<number>, stiffness: Animated.Adaptable<number>,
overshootClamping: Animated.Adaptable<boolean>, overshootClamping: Animated.Adaptable<number>,
restSpeedThreshold: Animated.Adaptable<number>, restSpeedThreshold: Animated.Adaptable<number>,
restDisplacementThreshold: Animated.Adaptable<number>, restDisplacementThreshold: Animated.Adaptable<number>,
clock: Animated.Clock clock: Animated.Clock
@@ -177,7 +176,7 @@ if (Animated.proc) {
damping: Animated.Adaptable<number>; damping: Animated.Adaptable<number>;
mass: Animated.Adaptable<number>; mass: Animated.Adaptable<number>;
stiffness: Animated.Adaptable<number>; stiffness: Animated.Adaptable<number>;
overshootClamping: Animated.Adaptable<boolean>; overshootClamping: Animated.Adaptable<number>;
restSpeedThreshold: Animated.Adaptable<number>; restSpeedThreshold: Animated.Adaptable<number>;
restDisplacementThreshold: Animated.Adaptable<number>; restDisplacementThreshold: Animated.Adaptable<number>;
} }
@@ -476,11 +475,14 @@ export default class Card extends React.Component<Props> {
); );
private exec = [ private exec = [
set( cond(
this.gesture, eq(this.direction, DIRECTION_HORIZONTAL),
multiply( set(
this.gestureUntraversed, this.gesture,
I18nManager.isRTL ? MINUS_ONE_NODE : TRUE_NODE multiply(
this.gestureUntraversed,
I18nManager.isRTL ? MINUS_ONE_NODE : TRUE_NODE
)
) )
), ),
set( set(
@@ -655,7 +657,7 @@ export default class Card extends React.Component<Props> {
// Changing it during an animations can result in unexpected results // Changing it during an animations can result in unexpected results
private getInterpolatedStyle = memoize( private getInterpolatedStyle = memoize(
( (
styleInterpolator: CardStyleInterpolator, styleInterpolator: StackCardStyleInterpolator,
index: number, index: number,
current: Animated.Node<number>, current: Animated.Node<number>,
next: Animated.Node<number> | undefined, next: Animated.Node<number> | undefined,

View File

@@ -23,8 +23,8 @@ import {
import { forNoAnimation } from '../../TransitionConfigs/HeaderStyleInterpolators'; import { forNoAnimation } from '../../TransitionConfigs/HeaderStyleInterpolators';
import { import {
Layout, Layout,
HeaderMode, StackHeaderMode,
HeaderScene, Scene,
StackDescriptorMap, StackDescriptorMap,
StackNavigationOptions, StackNavigationOptions,
StackNavigationHelpers, StackNavigationHelpers,
@@ -51,7 +51,7 @@ type Props = {
getGesturesEnabled: (props: { route: Route<string> }) => boolean; getGesturesEnabled: (props: { route: Route<string> }) => boolean;
renderHeader: (props: HeaderContainerProps) => React.ReactNode; renderHeader: (props: HeaderContainerProps) => React.ReactNode;
renderScene: (props: { route: Route<string> }) => React.ReactNode; renderScene: (props: { route: Route<string> }) => React.ReactNode;
headerMode: HeaderMode; headerMode: StackHeaderMode;
onPageChangeStart?: () => void; onPageChangeStart?: () => void;
onPageChangeConfirm?: () => void; onPageChangeConfirm?: () => void;
onPageChangeCancel?: () => void; onPageChangeCancel?: () => void;
@@ -60,7 +60,7 @@ type Props = {
type State = { type State = {
routes: Route<string>[]; routes: Route<string>[];
descriptors: StackDescriptorMap; descriptors: StackDescriptorMap;
scenes: HeaderScene<Route<string>>[]; scenes: Scene<Route<string>>[];
progress: ProgressValues; progress: ProgressValues;
layout: Layout; layout: Layout;
floatingHeaderHeights: { [key: string]: number }; floatingHeaderHeights: { [key: string]: number };

View File

@@ -1,5 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import { StyleSheet, Platform, StyleProp, ViewStyle } from 'react-native'; import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
import Animated from 'react-native-reanimated'; import Animated from 'react-native-reanimated';
import { StackNavigationState } from '@react-navigation/routers'; import { StackNavigationState } from '@react-navigation/routers';
import { Route } from '@react-navigation/core'; import { Route } from '@react-navigation/core';
@@ -7,9 +7,9 @@ import { Props as HeaderContainerProps } from '../Header/HeaderContainer';
import Card from './Card'; import Card from './Card';
import { import {
StackNavigationHelpers, StackNavigationHelpers,
HeaderScene, Scene,
Layout, Layout,
HeaderMode, StackHeaderMode,
TransitionPreset, TransitionPreset,
} from '../../types'; } from '../../types';
@@ -20,8 +20,8 @@ type Props = TransitionPreset & {
closing: boolean; closing: boolean;
layout: Layout; layout: Layout;
current: Animated.Value<number>; current: Animated.Value<number>;
previousScene?: HeaderScene<Route<string>>; previousScene?: Scene<Route<string>>;
scene: HeaderScene<Route<string>>; scene: Scene<Route<string>>;
state: StackNavigationState; state: StackNavigationState;
navigation: StackNavigationHelpers; navigation: StackNavigationHelpers;
cardTransparent?: boolean; cardTransparent?: boolean;
@@ -49,7 +49,7 @@ type Props = TransitionPreset & {
vertical?: number; vertical?: number;
horizontal?: number; horizontal?: number;
}; };
headerMode: HeaderMode; headerMode: StackHeaderMode;
headerTransparent?: boolean; headerTransparent?: boolean;
floatingHeaderHeight: number; floatingHeaderHeight: number;
hasCustomHeader: boolean; hasCustomHeader: boolean;
@@ -153,26 +153,32 @@ export default class StackItem extends React.PureComponent<Props> {
contentStyle={cardStyle} contentStyle={cardStyle}
style={StyleSheet.absoluteFill} style={StyleSheet.absoluteFill}
> >
{headerMode === 'screen' <View style={styles.container}>
? renderHeader({ <View style={styles.scene}>
mode: 'screen', {renderScene({ route: scene.route })}
layout, </View>
scenes: [previousScene, scene], {headerMode === 'screen'
state, ? renderHeader({
getPreviousRoute, mode: 'screen',
styleInterpolator: headerStyleInterpolator, layout,
style: styles.header, scenes: [previousScene, scene],
}) state,
: null} getPreviousRoute,
{renderScene({ route: scene.route })} styleInterpolator: headerStyleInterpolator,
})
: null}
</View>
</Card> </Card>
); );
} }
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
header: { container: {
// This is needed to show elevation shadow flex: 1,
zIndex: Platform.OS === 'android' ? 1 : 0, flexDirection: 'column-reverse',
},
scene: {
flex: 1,
}, },
}); });

View File

@@ -57,10 +57,6 @@ class StackView extends React.Component<Props, State> {
); );
} }
if (!routes.length) {
throw new Error(`There should always be at least one route.`);
}
// If there was no change in routes, we don't need to compute anything // If there was no change in routes, we don't need to compute anything
if (routes === state.routes || !state.routes.length) { if (routes === state.routes || !state.routes.length) {
return { return {
@@ -144,6 +140,20 @@ class StackView extends React.Component<Props, State> {
// i.e. the currently focused route already existed and the previously focused route still exists // i.e. the currently focused route already existed and the previously focused route still exists
// We don't know how to animate this // We don't know how to animate this
} }
} else {
// Keep the routes we are closing or replacing
routes = routes.slice();
routes.splice(
routes.length - 1,
0,
...state.routes.filter(
({ key }) => replacing.includes(key) || closing.includes(key)
)
);
}
if (!routes.length) {
throw new Error(`There should always be at least one route.`);
} }
const descriptors = routes.reduce( const descriptors = routes.reduce(

2547
yarn.lock

File diff suppressed because it is too large Load Diff