Compare commits

..

33 Commits

Author SHA1 Message Date
Satyajit Sahoo
353b3fd7de chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.22
 - @react-navigation/compat@5.0.0-alpha.15
 - @react-navigation/core@5.0.0-alpha.23
 - @react-navigation/drawer@5.0.0-alpha.23
 - @react-navigation/example@5.0.0-alpha.22
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.21
 - @react-navigation/material-top-tabs@5.0.0-alpha.18
 - @react-navigation/native-stack@5.0.0-alpha.13
 - @react-navigation/native@5.0.0-alpha.16
 - @react-navigation/routers@5.0.0-alpha.15
 - @react-navigation/stack@5.0.0-alpha.37
2019-11-17 02:46:59 +01:00
Satyajit Sahoo
d619292bf2 chore: upgrade deps 2019-11-17 02:42:28 +01:00
Danijel Dedic
cd7c9c4398 fix: pass labelStyle prop in DrawerItem label (#170) 2019-11-17 01:25:54 +01:00
Janic Duplessis
442e1121fc docs: headerHideShadow works on iOS too 2019-11-17 01:22:48 +01:00
Satyajit Sahoo
11efb06642 fix: merge initial params on push 2019-11-17 01:23:49 +01:00
Satyajit Sahoo
c17ad18b20 fix: workaround SafereaProvider causing jumping
see #174
2019-11-16 19:41:42 +01:00
Satyajit Sahoo
31b8819e17 refactor: use functions to specify custom react node for icons and label 2019-11-16 19:11:42 +01:00
Satyajit Sahoo
2baa235ce9 refactor: drop drawerLockMode in favor of gestureEnabled in drawer 2019-11-16 19:06:23 +01:00
Satyajit Sahoo
71b2bcd14f chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.21
 - @react-navigation/compat@5.0.0-alpha.14
 - @react-navigation/core@5.0.0-alpha.22
 - @react-navigation/drawer@5.0.0-alpha.22
 - @react-navigation/example@5.0.0-alpha.21
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.20
 - @react-navigation/material-top-tabs@5.0.0-alpha.17
 - @react-navigation/native-stack@5.0.0-alpha.12
 - @react-navigation/routers@5.0.0-alpha.14
 - @react-navigation/stack@5.0.0-alpha.36
2019-11-11 00:34:18 +01:00
Satyajit Sahoo
56c2779184 chore: add icons for the iOS app 2019-11-10 21:28:40 +01:00
Satyajit Sahoo
c77532174a chore: upgrade to screens alpha 7 2019-11-10 21:17:44 +01:00
Satyajit Sahoo
d4072e7d88 fix: throw when containers are nested within another 2019-11-10 20:40:45 +01:00
Satyajit Sahoo
941249dba9 refactor: rename createNavigator since it doesn't create a navigator 2019-11-10 20:12:32 +01:00
Satyajit Sahoo
d1ca7f9a09 fix: make bottom tab bar consistent across platforms 2019-11-10 20:10:51 +01:00
Satyajit Sahoo
f494f992fa chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.20
 - @react-navigation/compat@5.0.0-alpha.13
 - @react-navigation/core@5.0.0-alpha.21
 - @react-navigation/drawer@5.0.0-alpha.21
 - @react-navigation/example@5.0.0-alpha.20
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.19
 - @react-navigation/material-top-tabs@5.0.0-alpha.16
 - @react-navigation/native-stack@5.0.0-alpha.11
 - @react-navigation/native@5.0.0-alpha.15
 - @react-navigation/routers@5.0.0-alpha.13
 - @react-navigation/stack@5.0.0-alpha.35
2019-11-08 15:07:35 +01:00
Janic Duplessis
66551f29d4 fix: don't call getNode if ref is already scrollable (#162)
66e72bb4e0 deprecates `getNode` since Animated components now use `React.forwardRef`. To avoid triggering the warning I added a check to see if the node is already a scrollable node before trying to call the various method to get the scrollable node. This avoids calling getNode in newer RN versions.
2019-11-08 15:03:48 +01:00
Satyajit Sahoo
270fbdcfaf fix: don't crash if initialState is null 2019-11-07 16:00:24 +01:00
Satyajit Sahoo
e871fdb074 fix: fix types for resetRoot to accept undefined 2019-11-07 15:48:40 +01:00
Satyajit Sahoo
b5d9ad900d fix: handle invalid initialRouteName gracefully 2019-11-07 15:43:51 +01:00
Satyajit Sahoo
6aebeec90c chore: upgrade to typescript 3.7 2019-11-06 21:01:18 +01:00
satyajit.happy
75ed888b33 chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.19
 - @react-navigation/native-stack@5.0.0-alpha.10
2019-11-04 17:21:32 +01:00
satyajit.happy
ee82ab1d1b refactor: remove TouchableWithoutFeedbackWrapper 2019-11-04 17:20:36 +01:00
satyajit.happy
301c35ec32 fix: popToTop on tab press in native stack 2019-11-04 17:09:42 +01:00
Oliver Winter
22cb675608 fix: fix default BottomTabBar button (#161) 2019-11-04 17:05:05 +01:00
satyajit.happy
c41c824aae chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.18
 - @react-navigation/compat@5.0.0-alpha.12
 - @react-navigation/drawer@5.0.0-alpha.20
 - @react-navigation/example@5.0.0-alpha.19
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.18
 - @react-navigation/material-top-tabs@5.0.0-alpha.15
 - @react-navigation/native-stack@5.0.0-alpha.9
 - @react-navigation/routers@5.0.0-alpha.12
 - @react-navigation/stack@5.0.0-alpha.34
2019-11-04 07:52:29 +01:00
Freddy Harris
a93a81e5d3 feat: support transform style for header (#158) 2019-11-04 07:50:02 +01:00
satyajit.happy
57b411cea8 refactor: replace XComponent props in favor of render callbacks
Making these props components makes it impossible pass additional props to them from the parent component. Render callbacks are more dynamic and flexible for this case
2019-11-04 07:47:41 +01:00
satyajit.happy
3a4c38bb72 fix: close drawer on back button press 2019-11-02 08:52:12 +01:00
satyajit.happy
e6a06ac56e chore: publish
- @react-navigation/core@5.0.0-alpha.20
 - @react-navigation/native-stack@5.0.0-alpha.8
 - @react-navigation/stack@5.0.0-alpha.33
2019-11-02 05:12:02 +01:00
satyajit.happy
2ef5ad4cc2 fix: add horizontal margin to centered title 2019-11-02 05:08:10 +01:00
freddy
74ee216ed4 fix: remove unnecessary paddingHorizontal on stack header 2019-11-02 04:54:07 +01:00
Tien Pham
77f29d374f feat: add headerBackTitleVisible to navigation options in native stack 2019-11-02 04:53:23 +01:00
satyajit.happy
5a34764404 fix: pass rehydrated state in onStateChange and devtools 2019-11-02 04:43:47 +01:00
111 changed files with 3135 additions and 2055 deletions

View File

@@ -35,7 +35,7 @@ Navigators bundle a router and a view which takes the navigation state and decid
A simple navigator could look like this:
```js
import { createNavigator } from '@react-navigation/core';
import { createNavigatorFactory } from '@react-navigation/core';
function StackNavigator({ initialRouteName, children, ...rest }) {
// The `navigation` object contains the navigation state and some helpers (e.g. push, pop)
@@ -56,7 +56,7 @@ function StackNavigator({ initialRouteName, children, ...rest }) {
);
}
export default createNavigator(StackNavigator);
export default createNavigatorFactory(StackNavigator);
```
The navigator can render a screen by calling `descriptors[route.key].render()`. Internally, the descriptor adds appropriate wrappers to handle nested state.

View File

@@ -22,23 +22,23 @@
"example": "yarn --cwd packages/example"
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/preset-env": "^7.6.2",
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.6.0",
"@babel/runtime": "^7.6.2",
"@babel/plugin-proposal-class-properties": "^7.7.0",
"@babel/preset-env": "^7.7.1",
"@babel/preset-react": "^7.7.0",
"@babel/preset-typescript": "^7.7.2",
"@babel/runtime": "^7.7.2",
"@commitlint/config-conventional": "^8.2.0",
"@types/jest": "^24.0.13",
"@types/jest": "^24.0.23",
"codecov": "^3.6.1",
"commitlint": "^8.2.0",
"core-js": "^3.2.1",
"eslint": "^6.5.1",
"core-js": "^3.4.1",
"eslint": "^6.6.0",
"eslint-config-satya164": "^3.1.2",
"husky": "^3.0.8",
"husky": "^3.0.9",
"jest": "^24.8.0",
"lerna": "^3.16.4",
"prettier": "^1.18.2",
"typescript": "^3.6.3"
"lerna": "^3.18.4",
"prettier": "^1.19.1",
"typescript": "^3.7.2"
},
"resolutions": {
"react": "~16.8.3",

View File

@@ -3,6 +3,55 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.22](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.21...@react-navigation/bottom-tabs@5.0.0-alpha.22) (2019-11-17)
### Bug Fixes
* workaround SafereaProvider causing jumping ([c17ad18](https://github.com/react-navigation/navigation-ex/commit/c17ad18b20cb05c577e1235a58ccc1c856fee086)), closes [#174](https://github.com/react-navigation/navigation-ex/issues/174)
# [5.0.0-alpha.21](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.20...@react-navigation/bottom-tabs@5.0.0-alpha.21) (2019-11-10)
### Bug Fixes
* make bottom tab bar consistent across platforms ([d1ca7f9](https://github.com/react-navigation/navigation-ex/commit/d1ca7f9))
# [5.0.0-alpha.20](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.19...@react-navigation/bottom-tabs@5.0.0-alpha.20) (2019-11-08)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [5.0.0-alpha.19](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.18...@react-navigation/bottom-tabs@5.0.0-alpha.19) (2019-11-04)
### Bug Fixes
* fix default BottomTabBar button ([#161](https://github.com/react-navigation/navigation-ex/issues/161)) ([22cb675](https://github.com/react-navigation/navigation-ex/commit/22cb675))
# [5.0.0-alpha.18](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.17...@react-navigation/bottom-tabs@5.0.0-alpha.18) (2019-11-04)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [5.0.0-alpha.17](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.16...@react-navigation/bottom-tabs@5.0.0-alpha.17) (2019-10-30)

View File

@@ -10,7 +10,7 @@
"android",
"tab"
],
"version": "5.0.0-alpha.17",
"version": "5.0.0-alpha.22",
"license": "MIT",
"repository": {
"type": "git",
@@ -33,17 +33,17 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.11"
"@react-navigation/routers": "^5.0.0-alpha.15"
},
"devDependencies": {
"@react-native-community/bob": "^0.7.0",
"@types/react": "^16.9.4",
"@types/react-native": "^0.60.17",
"@types/react": "^16.9.11",
"@types/react-native": "^0.60.22",
"del-cli": "^3.0.0",
"react": "~16.8.3",
"react-native": "~0.59.10",
"react-native-safe-area-context": "^0.3.6",
"typescript": "^3.6.3"
"react-native-safe-area-context": "^0.6.0",
"typescript": "^3.7.2"
},
"peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -1,9 +1,7 @@
/**
* Navigators
*/
export {
default as createBottomTabNavigator,
} from './navigators/createBottomTabNavigator';
export { default as createBottomTabNavigator } from './navigators/createBottomTabNavigator';
/**
* Views

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import {
useNavigationBuilder,
createNavigator,
createNavigatorFactory,
DefaultNavigatorOptions,
} from '@react-navigation/core';
import {
@@ -49,7 +49,7 @@ function BottomTabNavigator({
);
}
export default createNavigator<
export default createNavigatorFactory<
BottomTabNavigationOptions,
typeof BottomTabNavigator
>(BottomTabNavigator);

View File

@@ -1,5 +1,6 @@
import * as React from 'react';
import {
TouchableWithoutFeedbackProps,
AccessibilityRole,
AccessibilityStates,
StyleProp,
@@ -26,8 +27,6 @@ export type BottomTabNavigationEventMap = {
tabLongPress: undefined;
};
export type Orientation = 'horizontal' | 'vertical';
export type LabelPosition = 'beside-icon' | 'below-icon';
export type BottomTabNavigationHelpers = NavigationHelpers<
@@ -52,7 +51,7 @@ export type BottomTabNavigationProp<
* @param [params] Params object for the route.
*/
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
...args: ParamList[RouteName] extends (undefined | any)
...args: ParamList[RouteName] extends undefined | any
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;
@@ -65,24 +64,22 @@ export type BottomTabNavigationOptions = {
title?: string;
/**
* Title string of a tab displayed in the tab bar or React Element
* or a function that given { focused: boolean, color: string } returns a React.Node, to display in tab bar.
* Title string of a tab displayed in the tab bar
* or a function that given { focused: boolean, color: string } returns a React.Node to display in tab bar.
* When undefined, scene title is used. To hide, see tabBarOptions.showLabel in the previous section.
*/
tabBarLabel?:
| React.ReactNode
| string
| ((props: { focused: boolean; color: string }) => React.ReactNode);
/**
* React Element or a function that given { focused: boolean, color: string } returns a React.Node, to display in the tab bar.
* A function that given { focused: boolean, color: string } returns a React.Node to display in the tab bar.
*/
tabBarIcon?:
| React.ReactNode
| ((props: {
focused: boolean;
color: string;
size: number;
}) => React.ReactNode);
tabBarIcon?: (props: {
focused: boolean;
color: string;
size: number;
}) => React.ReactNode;
/**
* Accessibility label for the tab button. This is read by the screen reader when the user taps the tab.
@@ -101,9 +98,10 @@ export type BottomTabNavigationOptions = {
tabBarVisible?: boolean;
/**
* Buttton component to render for the tab items instead of the default `TouchableWithoutFeedback`
* Function which returns a React element to render as the tab bar button.
* Renders `TouchableWithoutFeedback` by default.
*/
tabBarButtonComponent?: React.ComponentType<any>;
tabBarButton?: (props: BottomTabBarButtonProps) => React.ReactNode;
};
export type BottomTabDescriptor = Descriptor<
@@ -129,9 +127,9 @@ export type BottomTabNavigationConfig = {
*/
unmountInactiveScreens?: boolean;
/**
* Custom tab bar component.
* Function that returns a React element to display as the tab bar.
*/
tabBarComponent?: React.ComponentType<BottomTabBarProps>;
tabBar?: (props: BottomTabBarProps) => React.ReactNode;
/**
* Options for the tab bar which will be passed as props to the tab bar component.
*/
@@ -181,12 +179,14 @@ export type BottomTabBarOptions = {
tabStyle?: StyleProp<ViewStyle>;
/**
* Whether the label is renderd below the icon or beside the icon.
* When a function is passed, it receives the device orientation to render the label differently.
* When a function is passed, it receives the device dimensions to render the label differently.
* By default, in `vertical` orinetation, label is rendered below and in `horizontal` orientation, it's renderd beside.
*/
labelPosition?:
| LabelPosition
| ((options: { deviceOrientation: Orientation }) => LabelPosition);
| ((options: {
dimensions: { height: number; width: number };
}) => LabelPosition);
/**
* Whether the label position should adapt to the orientation.
*/
@@ -213,9 +213,6 @@ export type BottomTabBarProps = BottomTabBarOptions & {
route: Route<string>;
focused: boolean;
}) => AccessibilityStates[];
getButtonComponent: (props: {
route: Route<string>;
}) => React.ComponentType<any> | undefined;
getLabelText: (props: {
route: Route<string>;
}) =>
@@ -223,14 +220,19 @@ export type BottomTabBarProps = BottomTabBarOptions & {
focused: boolean;
color: string;
}) => React.ReactNode | undefined)
| React.ReactNode;
| string;
getTestID: (props: { route: Route<string> }) => string | undefined;
renderButton: (
props: { route: Route<string> } & BottomTabBarButtonProps
) => React.ReactNode;
renderIcon: (props: {
route: Route<string>;
focused: boolean;
color: string;
size: number;
}) => React.ReactNode;
activeTintColor: string;
inactiveTintColor: string;
};
export type BottomTabBarButtonProps = TouchableWithoutFeedbackProps & {
children: React.ReactNode;
};

View File

@@ -13,7 +13,6 @@ import { Route, NavigationContext } from '@react-navigation/core';
import { SafeAreaConsumer } from 'react-native-safe-area-context';
import TabBarIcon from './TabBarIcon';
import TouchableWithoutFeedbackWrapper from './TouchableWithoutFeedbackWrapper';
import { BottomTabBarProps } from '../types';
type State = {
@@ -23,12 +22,12 @@ type State = {
visible: Animated.Value;
};
type Props = BottomTabBarProps;
const majorVersion = parseInt(Platform.Version as string, 10);
const isIos = Platform.OS === 'ios';
const isIOS11 = majorVersion >= 11 && isIos;
type Props = BottomTabBarProps & {
activeTintColor: string;
inactiveTintColor: string;
};
const DEFAULT_TABBAR_HEIGHT = 50;
const DEFAULT_MAX_TAB_ITEM_WIDTH = 125;
export default class TabBarBottom extends React.Component<Props, State> {
@@ -41,7 +40,7 @@ export default class TabBarBottom extends React.Component<Props, State> {
showLabel: true,
showIcon: true,
allowFontScaling: true,
adaptive: isIOS11,
adaptive: true,
};
state = {
@@ -156,11 +155,11 @@ export default class TabBarBottom extends React.Component<Props, State> {
);
}
if (typeof label === 'function') {
return label({ focused, color });
if (typeof label === 'string') {
return label;
}
return label;
return label({ focused, color });
};
private renderIcon = ({
@@ -175,7 +174,6 @@ export default class TabBarBottom extends React.Component<Props, State> {
inactiveTintColor,
renderIcon,
showIcon,
showLabel,
} = this.props;
if (showIcon === false) {
@@ -196,11 +194,7 @@ export default class TabBarBottom extends React.Component<Props, State> {
activeTintColor={activeTintColor}
inactiveTintColor={inactiveTintColor}
renderIcon={renderIcon}
style={[
styles.iconWithExplicitHeight,
showLabel === false && !horizontal && styles.iconWithoutLabel,
showLabel !== false && !horizontal && styles.iconWithLabel,
]}
style={horizontal ? styles.iconHorizontal : styles.iconVertical}
/>
);
};
@@ -213,12 +207,11 @@ export default class TabBarBottom extends React.Component<Props, State> {
if (labelPosition) {
let position;
if (typeof labelPosition === 'string') {
position = labelPosition;
} else {
position = labelPosition({
deviceOrientation: isLandscape ? 'horizontal' : 'vertical',
});
position = labelPosition({ dimensions });
}
if (position) {
@@ -230,8 +223,8 @@ export default class TabBarBottom extends React.Component<Props, State> {
return false;
}
// @ts-ignore
if (Platform.isPad) {
if (dimensions.width >= 768) {
// Screen size matches a tablet
let maxTabItemWidth = DEFAULT_MAX_TAB_ITEM_WIDTH;
const flattenedStyle = StyleSheet.flatten(tabStyle);
@@ -262,7 +255,7 @@ export default class TabBarBottom extends React.Component<Props, State> {
getAccessibilityLabel,
getAccessibilityRole,
getAccessibilityStates,
getButtonComponent,
renderButton,
getTestID,
style,
tabStyle,
@@ -292,11 +285,7 @@ export default class TabBarBottom extends React.Component<Props, State> {
}
: null,
{
height:
// @ts-ignore
(this.shouldUseHorizontalLabels() && !Platform.isPad
? COMPACT_HEIGHT
: DEFAULT_HEIGHT) + (insets ? insets.bottom : 0),
height: DEFAULT_TABBAR_HEIGHT + (insets ? insets.bottom : 0),
paddingBottom: insets ? insets.bottom : 0,
},
style,
@@ -325,34 +314,34 @@ export default class TabBarBottom extends React.Component<Props, State> {
? activeBackgroundColor
: inactiveBackgroundColor;
const ButtonComponent =
getButtonComponent({ route }) ||
TouchableWithoutFeedbackWrapper;
return (
<NavigationContext.Provider
key={route.key}
value={descriptors[route.key].navigation}
>
<ButtonComponent
onPress={() => onTabPress({ route })}
onLongPress={() => onTabLongPress({ route })}
testID={testID}
accessibilityLabel={accessibilityLabel}
accessibilityRole={accessibilityRole}
accessibilityStates={accessibilityStates}
style={[
{renderButton({
route,
onPress: () => onTabPress({ route }),
onLongPress: () => onTabLongPress({ route }),
testID,
accessibilityLabel,
accessibilityRole,
accessibilityStates,
style: [
styles.tab,
{ backgroundColor },
this.shouldUseHorizontalLabels()
? styles.tabLandscape
: styles.tabPortrait,
tabStyle,
]}
>
{this.renderIcon(scene)}
{this.renderLabel(scene)}
</ButtonComponent>
],
children: (
<React.Fragment>
{this.renderIcon(scene)}
{this.renderLabel(scene)}
</React.Fragment>
),
})}
</NavigationContext.Provider>
);
})}
@@ -364,9 +353,6 @@ export default class TabBarBottom extends React.Component<Props, State> {
}
}
const DEFAULT_HEIGHT = 49;
const COMPACT_HEIGHT = 29;
const styles = StyleSheet.create({
tabBar: {
left: 0,
@@ -383,7 +369,7 @@ const styles = StyleSheet.create({
},
tab: {
flex: 1,
alignItems: isIos ? 'center' : 'stretch',
alignItems: 'center',
},
tabPortrait: {
justifyContent: 'flex-end',
@@ -393,15 +379,11 @@ const styles = StyleSheet.create({
justifyContent: 'center',
flexDirection: 'row',
},
iconWithoutLabel: {
iconVertical: {
flex: 1,
},
iconWithLabel: {
flex: 1,
},
iconWithExplicitHeight: {
// @ts-ignore
height: Platform.isPad ? DEFAULT_HEIGHT : COMPACT_HEIGHT,
iconHorizontal: {
height: '100%',
},
label: {
textAlign: 'center',

View File

@@ -1,23 +1,27 @@
import * as React from 'react';
import {
View,
TouchableWithoutFeedback,
StyleSheet,
AccessibilityRole,
AccessibilityStates,
} from 'react-native';
import { Route, CommonActions } from '@react-navigation/core';
import { TabNavigationState } from '@react-navigation/routers';
// eslint-disable-next-line import/no-unresolved
import { ScreenContainer } from 'react-native-screens';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import SafeAreaProviderCompat from './SafeAreaProviderCompat';
import ResourceSavingScene from './ResourceSavingScene';
import BottomTabBar from './BottomTabBar';
import {
BottomTabNavigationConfig,
BottomTabDescriptorMap,
BottomTabNavigationHelpers,
BottomTabBarProps,
BottomTabBarButtonProps,
} from '../types';
import ResourceSavingScene from './ResourceSavingScene';
type Props = BottomTabNavigationConfig & {
state: TabNavigationState;
@@ -49,16 +53,25 @@ export default class BottomTabView extends React.Component<Props, State> {
loaded: [this.props.state.index],
};
private getButtonComponent = ({ route }: { route: Route<string> }) => {
private renderButton = ({
route,
children,
style,
...rest
}: { route: Route<string> } & BottomTabBarButtonProps) => {
const { descriptors } = this.props;
const descriptor = descriptors[route.key];
const options = descriptor.options;
if (options.tabBarButtonComponent) {
return options.tabBarButtonComponent;
if (options.tabBarButton) {
return options.tabBarButton({ children, style, ...rest });
}
return undefined;
return (
<TouchableWithoutFeedback {...rest}>
<View style={style}>{children}</View>
</TouchableWithoutFeedback>
);
};
private renderIcon = ({
@@ -77,9 +90,9 @@ export default class BottomTabView extends React.Component<Props, State> {
const options = descriptor.options;
if (options.tabBarIcon) {
return typeof options.tabBarIcon === 'function'
? options.tabBarIcon({ focused, color, size })
: options.tabBarIcon;
return typeof options.tabBarIcon === 'string'
? options.tabBarIcon
: options.tabBarIcon({ focused, color, size });
}
return null;
@@ -159,7 +172,7 @@ export default class BottomTabView extends React.Component<Props, State> {
private renderTabBar = () => {
const {
tabBarComponent: TabBarComponent = BottomTabBar,
tabBar = (props: BottomTabBarProps) => <BottomTabBar {...props} />,
tabBarOptions,
state,
navigation,
@@ -174,23 +187,21 @@ export default class BottomTabView extends React.Component<Props, State> {
return null;
}
return (
<TabBarComponent
{...tabBarOptions}
state={state}
descriptors={descriptors}
navigation={navigation}
onTabPress={this.handleTabPress}
onTabLongPress={this.handleTabLongPress}
getLabelText={this.getLabelText}
getButtonComponent={this.getButtonComponent}
getAccessibilityLabel={this.getAccessibilityLabel}
getAccessibilityRole={this.getAccessibilityRole}
getAccessibilityStates={this.getAccessibilityStates}
getTestID={this.getTestID}
renderIcon={this.renderIcon}
/>
);
return tabBar({
...tabBarOptions,
state: state,
descriptors: descriptors,
navigation: navigation,
onTabPress: this.handleTabPress,
onTabLongPress: this.handleTabLongPress,
getLabelText: this.getLabelText,
getAccessibilityLabel: this.getAccessibilityLabel,
getAccessibilityRole: this.getAccessibilityRole,
getAccessibilityStates: this.getAccessibilityStates,
getTestID: this.getTestID,
renderButton: this.renderButton,
renderIcon: this.renderIcon,
});
};
render() {
@@ -199,7 +210,7 @@ export default class BottomTabView extends React.Component<Props, State> {
const { loaded } = this.state;
return (
<SafeAreaProvider>
<SafeAreaProviderCompat>
<View style={styles.container}>
<ScreenContainer style={styles.pages}>
{routes.map((route, index) => {
@@ -235,7 +246,7 @@ export default class BottomTabView extends React.Component<Props, State> {
</ScreenContainer>
{this.renderTabBar()}
</View>
</SafeAreaProvider>
</SafeAreaProviderCompat>
);
}
}

View File

@@ -0,0 +1,26 @@
import * as React from 'react';
import {
SafeAreaProvider,
SafeAreaConsumer,
} from 'react-native-safe-area-context';
type Props = {
children: React.ReactNode;
};
export default function SafeAreaProviderCompat({ children }: Props) {
return (
<SafeAreaConsumer>
{insets => {
if (insets) {
// If we already have insets, don't wrap the stack in another safe area provider
// This avoids an issue with updates at the cost of potentially incorrect values
// https://github.com/react-navigation/navigation-ex/issues/174
return children;
}
return <SafeAreaProvider>{children}</SafeAreaProvider>;
}}
</SafeAreaConsumer>
);
}

View File

@@ -1,28 +0,0 @@
import React from 'react';
import { TouchableWithoutFeedback, View } from 'react-native';
export default function TouchableWithoutFeedbackWrapper({
onPress,
onLongPress,
testID,
accessibilityLabel,
accessibilityRole,
accessibilityStates,
...rest
}: React.ComponentProps<typeof TouchableWithoutFeedback> & {
children: React.ReactNode;
}) {
return (
<TouchableWithoutFeedback
onPress={onPress}
onLongPress={onLongPress}
testID={testID}
hitSlop={{ left: 15, right: 15, top: 0, bottom: 5 }}
accessibilityLabel={accessibilityLabel}
accessibilityRole={accessibilityRole}
accessibilityStates={accessibilityStates}
>
<View {...rest} />
</TouchableWithoutFeedback>
);
}

View File

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

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/compat",
"description": "Compatibility layer to write navigator definitions in static configuration format",
"version": "5.0.0-alpha.11",
"version": "5.0.0-alpha.15",
"license": "MIT",
"repository": {
"type": "git",
@@ -24,12 +24,12 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.11"
"@react-navigation/routers": "^5.0.0-alpha.15"
},
"devDependencies": {
"@types/react": "^16.9.4",
"@types/react": "^16.9.11",
"react": "~16.8.3",
"typescript": "^3.6.3"
"typescript": "^3.7.2"
},
"peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -1,6 +1,6 @@
import {
useNavigationBuilder,
createNavigator,
createNavigatorFactory,
DefaultNavigatorOptions,
} from '@react-navigation/core';
import {
@@ -24,5 +24,5 @@ function SwitchNavigator(props: Props) {
}
export default createCompatNavigatorFactory(
createNavigator<{}, typeof SwitchNavigator>(SwitchNavigator)
createNavigatorFactory<{}, typeof SwitchNavigator>(SwitchNavigator)
);

View File

@@ -5,13 +5,9 @@ import * as SwitchActions from './SwitchActions';
export { NavigationActions, StackActions, DrawerActions, SwitchActions };
export {
default as createCompatNavigatorFactory,
} from './createCompatNavigatorFactory';
export { default as createCompatNavigatorFactory } from './createCompatNavigatorFactory';
export {
default as createCompatNavigationProp,
} from './createCompatNavigationProp';
export { default as createCompatNavigationProp } from './createCompatNavigationProp';
export { default as createSwitchNavigator } from './createSwitchNavigator';

View File

@@ -3,6 +3,51 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.23](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.22...@react-navigation/core@5.0.0-alpha.23) (2019-11-17)
### Bug Fixes
* merge initial params on push ([11efb06](https://github.com/react-navigation/navigation-ex/commit/11efb066429a3fc8b7e8e48d897286208d9a5449))
# [5.0.0-alpha.22](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.21...@react-navigation/core@5.0.0-alpha.22) (2019-11-10)
### Bug Fixes
* throw when containers are nested within another ([d4072e7](https://github.com/react-navigation/navigation-ex/commit/d4072e7))
# [5.0.0-alpha.21](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.20...@react-navigation/core@5.0.0-alpha.21) (2019-11-08)
### Bug Fixes
* don't crash if initialState is null ([270fbdc](https://github.com/react-navigation/navigation-ex/commit/270fbdc))
* fix types for resetRoot to accept undefined ([e871fdb](https://github.com/react-navigation/navigation-ex/commit/e871fdb))
# [5.0.0-alpha.20](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.19...@react-navigation/core@5.0.0-alpha.20) (2019-11-02)
### Bug Fixes
* pass rehydrated state in onStateChange and devtools ([5a34764](https://github.com/react-navigation/navigation-ex/commit/5a34764))
# [5.0.0-alpha.19](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.18...@react-navigation/core@5.0.0-alpha.19) (2019-10-30)

View File

@@ -15,7 +15,7 @@ yarn add @react-navigation/core
A basic custom navigator bundling a router and a view looks like this:
```js
import { useNavigationBuilder } from '@react-navigation/core';
import { createNavigatorFactory, useNavigationBuilder } from '@react-navigation/core';
import { StackRouter } from '@react-navigation/routers';
function StackNavigator({ initialRouteName, children, ...rest }) {
@@ -34,5 +34,5 @@ function StackNavigator({ initialRouteName, children, ...rest }) {
);
}
export default createNavigator(StackNavigator);
export default createNavigatorFactory(StackNavigator);
```

View File

@@ -6,7 +6,7 @@
"react-native",
"react-navigation"
],
"version": "5.0.0-alpha.19",
"version": "5.0.0-alpha.23",
"license": "MIT",
"repository": {
"type": "git",
@@ -30,20 +30,20 @@
},
"dependencies": {
"escape-string-regexp": "^2.0.0",
"query-string": "^6.8.3",
"query-string": "^6.9.0",
"shortid": "^2.2.15",
"use-subscription": "^1.1.1"
"use-subscription": "^1.3.0"
},
"devDependencies": {
"@babel/core": "^7.6.2",
"@babel/core": "^7.7.2",
"@react-native-community/bob": "^0.7.0",
"@types/react": "^16.9.4",
"@types/react": "^16.9.11",
"@types/shortid": "^0.0.29",
"del-cli": "^3.0.0",
"react": "~16.8.3",
"react-native-testing-library": "^1.9.1",
"react-test-renderer": "~16.8.3",
"typescript": "^3.6.3"
"typescript": "^3.7.2"
},
"peerDependencies": {
"react": "~16.8.3"

View File

@@ -23,6 +23,7 @@ const MISSING_CONTEXT_ERROR =
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?";
export const NavigationStateContext = React.createContext<{
isDefault?: true;
state?: NavigationState | PartialState<NavigationState>;
getState: () => NavigationState | PartialState<NavigationState> | undefined;
setState: (
@@ -31,6 +32,8 @@ export const NavigationStateContext = React.createContext<{
key?: string;
performTransaction: (action: () => void) => void;
}>({
isDefault: true,
get getState(): any {
throw new Error(MISSING_CONTEXT_ERROR);
},
@@ -83,11 +86,24 @@ const getPartialState = (
* @param props.ref Ref object which refers to the navigation object containing helper methods.
*/
const Container = React.forwardRef(function NavigationContainer(
{ initialState, onStateChange, children }: NavigationContainerProps,
{
initialState,
onStateChange,
independent,
children,
}: NavigationContainerProps,
ref: React.Ref<NavigationContainerRef>
) {
const parent = React.useContext(NavigationStateContext);
if (!parent.isDefault && !independent) {
throw new Error(
"Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitely."
);
}
const [state, setNavigationState] = React.useState<State>(() =>
getPartialState(initialState)
getPartialState(initialState == null ? undefined : initialState)
);
const navigationStateRef = React.useRef<State>();
@@ -130,16 +146,16 @@ const Container = React.forwardRef(function NavigationContainer(
};
const resetRoot = React.useCallback(
(state: PartialState<NavigationState> | NavigationState) => {
(state?: PartialState<NavigationState> | NavigationState) => {
trackAction('@@RESET_ROOT');
setNavigationState(state);
},
[trackAction]
);
const getRootState = () => {
const getRootState = React.useCallback(() => {
return getStateForRoute('root');
};
}, [getStateForRoute]);
React.useImperativeHandle(ref, () => ({
...(Object.keys(CommonActions) as Array<keyof typeof CommonActions>).reduce<
@@ -220,18 +236,18 @@ const Container = React.forwardRef(function NavigationContainer(
if (skipTrackingRef.current) {
skipTrackingRef.current = false;
} else {
trackState(state);
trackState(getRootState);
}
navigationStateRef.current = state;
transactionStateRef.current = null;
if (!isFirstMountRef.current && onStateChange) {
onStateChange(state);
onStateChange(getRootState());
}
isFirstMountRef.current = false;
}, [state, onStateChange, trackState]);
}, [state, onStateChange, trackState, getRootState]);
return (
<NavigationBuilderContext.Provider value={builderContext}>

View File

@@ -122,6 +122,32 @@ it('throws when nesting performTransaction', () => {
);
});
it('throws when nesting containers', () => {
expect(() =>
render(
<NavigationContainer>
<NavigationContainer>
<React.Fragment />
</NavigationContainer>
</NavigationContainer>
)
).toThrowError(
"Looks like you have nested a 'NavigationContainer' inside another."
);
expect(() =>
render(
<NavigationContainer>
<NavigationContainer independent>
<React.Fragment />
</NavigationContainer>
</NavigationContainer>
)
).not.toThrowError(
"Looks like you have nested a 'NavigationContainer' inside another."
);
});
it('handle dispatching with ref', () => {
const CurrentParentRouter = MockRouter;
@@ -137,14 +163,14 @@ it('handle dispatching with ref', () => {
return true;
},
getStateForAction(state, action) {
getStateForAction(state, action, options) {
if (action.type === 'REVERSE') {
return {
...state,
routes: state.routes.slice().reverse(),
};
}
return CurrentMockRouter.getStateForAction(state, action);
return CurrentMockRouter.getStateForAction(state, action, options);
},
};
return ChildRouter;
@@ -186,7 +212,10 @@ it('handle dispatching with ref', () => {
index: 0,
key: '4',
routeNames: ['qux', 'lex'],
routes: [{ key: 'qux', name: 'qux' }, { key: 'lex', name: 'lex' }],
routes: [
{ key: 'qux', name: 'qux' },
{ key: 'lex', name: 'lex' },
],
},
},
{ key: 'bar', name: 'bar' },
@@ -247,7 +276,10 @@ it('handle dispatching with ref', () => {
index: 0,
key: '1',
routeNames: ['qux', 'lex'],
routes: [{ key: 'lex', name: 'lex' }, { key: 'qux', name: 'qux' }],
routes: [
{ key: 'lex', name: 'lex' },
{ key: 'qux', name: 'qux' },
],
},
},
{ key: 'bar', name: 'bar' },
@@ -307,7 +339,10 @@ it('handle resetting state with ref', () => {
index: 0,
key: '4',
routeNames: ['qux', 'lex'],
routes: [{ key: 'qux', name: 'qux' }, { key: 'lex', name: 'lex' }],
routes: [
{ key: 'qux', name: 'qux' },
{ key: 'lex', name: 'lex' },
],
},
},
{ key: 'bar', name: 'bar' },
@@ -321,7 +356,31 @@ it('handle resetting state with ref', () => {
});
expect(onStateChange).toBeCalledTimes(1);
expect(onStateChange).lastCalledWith(state);
expect(onStateChange).lastCalledWith({
index: 1,
key: '5',
routeNames: ['foo', 'foo2', 'bar', 'baz'],
routes: [
{
key: 'baz',
name: 'baz',
state: {
index: 0,
key: '6',
routeNames: ['qux', 'lex'],
routes: [
{ key: 'qux', name: 'qux' },
{ key: 'lex', name: 'lex' },
],
stale: false,
type: 'test',
},
},
{ key: 'bar', name: 'bar' },
],
stale: false,
type: 'test',
});
});
it('handle getRootState', () => {
@@ -367,7 +426,10 @@ it('handle getRootState', () => {
index: 0,
key: '8',
routeNames: ['qux', 'lex'],
routes: [{ key: 'qux', name: 'qux' }, { key: 'lex', name: 'lex' }],
routes: [
{ key: 'qux', name: 'qux' },
{ key: 'lex', name: 'lex' },
],
stale: false,
type: 'test',
},

View File

@@ -64,6 +64,27 @@ it('initializes state for a navigator on navigation', () => {
});
});
it("doesn't crash when initialState is null", () => {
const TestNavigator = (props: any) => {
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
return descriptors[state.routes[state.index].key].render();
};
const TestScreen = () => null;
const element = (
// @ts-ignore
<NavigationContainer initialState={null}>
<TestNavigator>
<Screen name="foo" component={TestScreen} />
</TestNavigator>
</NavigationContainer>
);
expect(() => render(element)).not.toThrowError();
});
it('rehydrates state for a navigator on navigation', () => {
const TestNavigator = (props: any) => {
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
@@ -82,7 +103,10 @@ it('rehydrates state for a navigator on navigation', () => {
const initialState = {
index: 1,
routes: [{ key: 'foo', name: 'foo' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar' },
],
};
const onStateChange = jest.fn();
@@ -105,7 +129,10 @@ it('rehydrates state for a navigator on navigation', () => {
index: 1,
key: '0',
routeNames: ['foo', 'bar'],
routes: [{ key: 'foo', name: 'foo' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar' },
],
stale: false,
type: 'test',
});
@@ -130,7 +157,10 @@ it("doesn't rehydrate state if the type of state didn't match router", () => {
const initialState = {
index: 1,
type: 'something-else',
routes: [{ key: 'foo', name: 'foo' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar' },
],
};
const onStateChange = jest.fn();
@@ -377,7 +407,10 @@ it('cleans up state when the navigator unmounts', () => {
index: 0,
key: '0',
routeNames: ['foo', 'bar'],
routes: [{ key: 'foo', name: 'foo' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar' },
],
});
root.update(
@@ -430,7 +463,10 @@ it('allows state updates by dispatching a function returning an action', () => {
index: 1,
key: '0',
routeNames: ['foo', 'bar'],
routes: [{ key: 'foo', name: 'foo' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar' },
],
});
});
@@ -534,7 +570,19 @@ it('updates route params with setParams applied to parent', () => {
key: '0',
routeNames: ['foo', 'bar'],
routes: [
{ key: 'foo', name: 'foo', params: { username: 'alice' } },
{
key: 'foo',
name: 'foo',
params: { username: 'alice' },
state: {
index: 0,
key: '1',
routeNames: ['baz'],
routes: [{ key: 'baz', name: 'baz' }],
stale: false,
type: 'test',
},
},
{ key: 'bar', name: 'bar' },
],
stale: false,
@@ -549,7 +597,19 @@ it('updates route params with setParams applied to parent', () => {
key: '0',
routeNames: ['foo', 'bar'],
routes: [
{ key: 'foo', name: 'foo', params: { username: 'alice', age: 25 } },
{
key: 'foo',
name: 'foo',
params: { username: 'alice', age: 25 },
state: {
index: 0,
key: '1',
routeNames: ['baz'],
routes: [{ key: 'baz', name: 'baz' }],
stale: false,
type: 'test',
},
},
{ key: 'bar', name: 'bar' },
],
stale: false,

View File

@@ -419,12 +419,12 @@ it(`returns false for canGoBack when current router doesn't handle GO_BACK`, ()
const ChildRouter: Router<NavigationState, MockActions> = {
...CurrentMockRouter,
getStateForAction(state, action) {
getStateForAction(state, action, options) {
if (action.type === 'GO_BACK') {
return null;
}
return CurrentMockRouter.getStateForAction(state, action);
return CurrentMockRouter.getStateForAction(state, action, options);
},
};
return ChildRouter;
@@ -470,12 +470,12 @@ it('returns true for canGoBack when current router handles GO_BACK', () => {
const ChildRouter: Router<NavigationState, MockActions> = {
...CurrentMockRouter,
getStateForAction(state, action) {
getStateForAction(state, action, options) {
if (action.type === 'GO_BACK') {
return state;
}
return CurrentMockRouter.getStateForAction(state, action);
return CurrentMockRouter.getStateForAction(state, action, options);
},
};
return ChildRouter;
@@ -537,12 +537,12 @@ it('returns true for canGoBack when parent router handles GO_BACK', () => {
const ChildRouter: Router<NavigationState, MockActions> = {
...CurrentMockRouter,
getStateForAction(state, action) {
getStateForAction(state, action, options) {
if (action.type === 'GO_BACK') {
return state;
}
return CurrentMockRouter.getStateForAction(state, action);
return CurrentMockRouter.getStateForAction(state, action, options);
},
};
return ChildRouter;

View File

@@ -230,7 +230,7 @@ it('fires blur event when a route is removed with a delay', async () => {
};
},
getStateForAction(state, action) {
getStateForAction(state, action, options) {
switch (action.type) {
case 'PUSH':
return {
@@ -248,7 +248,7 @@ it('fires blur event when a route is removed with a delay', async () => {
};
}
default:
return router.getStateForAction(state, action);
return router.getStateForAction(state, action, options);
}
},

View File

@@ -20,7 +20,7 @@ it("lets parent handle the action if child didn't", () => {
> = {
...CurrentMockRouter,
getStateForAction(state, action) {
getStateForAction(state, action, options) {
if (action.type === 'REVERSE') {
return {
...state,
@@ -28,7 +28,7 @@ it("lets parent handle the action if child didn't", () => {
};
}
return CurrentMockRouter.getStateForAction(state, action);
return CurrentMockRouter.getStateForAction(state, action, options);
},
};
return ParentRouter;
@@ -103,14 +103,14 @@ it("lets children handle the action if parent didn't", () => {
return true;
},
getStateForAction(state, action) {
getStateForAction(state, action, options) {
if (action.type === 'REVERSE') {
return {
...state,
routes: state.routes.slice().reverse(),
};
}
return CurrentMockRouter.getStateForAction(state, action);
return CurrentMockRouter.getStateForAction(state, action, options);
},
};
return ChildRouter;
@@ -160,7 +160,10 @@ it("lets children handle the action if parent didn't", () => {
index: 0,
key: '4',
routeNames: ['qux', 'lex'],
routes: [{ key: 'qux', name: 'qux' }, { key: 'lex', name: 'lex' }],
routes: [
{ key: 'qux', name: 'qux' },
{ key: 'lex', name: 'lex' },
],
},
},
{ key: 'bar', name: 'bar' },
@@ -206,7 +209,10 @@ it("lets children handle the action if parent didn't", () => {
index: 0,
key: '1',
routeNames: ['qux', 'lex'],
routes: [{ key: 'lex', name: 'lex' }, { key: 'qux', name: 'qux' }],
routes: [
{ key: 'lex', name: 'lex' },
{ key: 'qux', name: 'qux' },
],
},
},
{ key: 'bar', name: 'bar' },
@@ -229,7 +235,7 @@ it("action doesn't bubble if target is specified", () => {
return true;
},
getStateForAction(state, action) {
getStateForAction(state, action, options) {
if (action.type === 'REVERSE') {
return {
...state,
@@ -237,7 +243,7 @@ it("action doesn't bubble if target is specified", () => {
};
}
return CurrentMockRouter.getStateForAction(state, action);
return CurrentMockRouter.getStateForAction(state, action, options);
},
};
return ChildRouter;
@@ -333,7 +339,10 @@ it("doesn't crash if no navigator handled the action", () => {
index: 0,
key: '4',
routeNames: ['qux', 'lex'],
routes: [{ key: 'qux', name: 'qux' }, { key: 'lex', name: 'lex' }],
routes: [
{ key: 'qux', name: 'qux' },
{ key: 'lex', name: 'lex' },
],
},
},
{ key: 'bar', name: 'bar' },

View File

@@ -9,7 +9,7 @@ import { ParamListBase, TypedNavigator } from './types';
* @param Navigator The navigtor component to wrap.
* @returns Factory method to create a `Navigator` and `Screen` pair.
*/
export default function createNavigator<
export default function createNavigatorFactory<
ScreenOptions extends object,
NavigatorComponent extends React.ComponentType<any>
>(Navigator: NavigatorComponent) {

View File

@@ -4,7 +4,7 @@ export { CommonActions };
export { default as BaseRouter } from './BaseRouter';
export { default as NavigationContainer } from './NavigationContainer';
export { default as createNavigator } from './createNavigator';
export { default as createNavigatorFactory } from './createNavigatorFactory';
export { default as NavigationContext } from './NavigationContext';
export { default as NavigationRouteContext } from './NavigationRouteContext';

View File

@@ -118,6 +118,11 @@ export type RouterFactory<
RouterOptions extends DefaultRouterOptions
> = (options: RouterOptions) => Router<State, Action>;
export type RouterConfigOptions = {
routeNames: string[];
routeParamList: ParamListBase;
};
export type Router<
State extends NavigationState,
Action extends NavigationAction
@@ -134,10 +139,7 @@ export type Router<
* @param options.routeNames List of valid route names as defined in the screen components.
* @param options.routeParamsList Object containing params for each route.
*/
getInitialState(options: {
routeNames: string[];
routeParamList: ParamListBase;
}): State;
getInitialState(options: RouterConfigOptions): State;
/**
* Rehydrate the full navigation state from a given partial state.
@@ -148,10 +150,7 @@ export type Router<
*/
getRehydratedState(
partialState: PartialState<State> | State,
options: {
routeNames: string[];
routeParamList: ParamListBase;
}
options: RouterConfigOptions
): State;
/**
@@ -163,10 +162,7 @@ export type Router<
*/
getStateForRouteNamesChange(
state: State,
options: {
routeNames: string[];
routeParamList: ParamListBase;
}
options: RouterConfigOptions
): State;
/**
@@ -183,10 +179,13 @@ export type Router<
*
* @param state State object to apply the action on.
* @param action Action object to apply.
* @param options.routeNames List of valid route names as defined in the screen components.
* @param options.routeParamsList Object containing params for each route.
*/
getStateForAction(
state: State,
action: Action
action: Action,
options: RouterConfigOptions
): State | PartialState<State> | null;
/**
@@ -298,7 +297,7 @@ type NavigationHelpersCommon<
* @param [params] Params object for the route.
*/
navigate<RouteName extends keyof ParamList>(
...args: ParamList[RouteName] extends (undefined | any)
...args: ParamList[RouteName] extends undefined | any
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;
@@ -338,7 +337,7 @@ type NavigationHelpersCommon<
*
* @param state Navigation state object.
*/
resetRoot(state: PartialState<NavigationState> | NavigationState): void;
resetRoot(state?: PartialState<NavigationState> | NavigationState): void;
/**
* Go back to the previous route in history.
@@ -377,10 +376,23 @@ export type NavigationHelpers<
};
export type NavigationContainerProps = {
/**
* Initial navigation state for the child navigators.
*/
initialState?: InitialState;
onStateChange?: (
state: NavigationState | PartialState<NavigationState> | undefined
) => void;
/**
* Callback which is called with the latest navigation state when it changes.
*/
onStateChange?: (state: NavigationState | undefined) => void;
/**
* Whether this navigation container should be independent of parent containers.
* If this is not set to `true`, this container cannot be nested inside another container.
* Setting it to `true` disconnects any children navigators from parent container.
*/
independent?: boolean;
/**
* Children elements to render.
*/
children: React.ReactNode;
};
@@ -540,18 +552,19 @@ export type RouteConfig<
route: RouteProp<ParamList, RouteName>;
navigation: any;
}) => React.ReactNode;
});
}
);
export type NavigationContainerRef =
| NavigationHelpers<ParamListBase> & {
| (NavigationHelpers<ParamListBase> & {
/**
* Reset the navigation state of the root navigator to the provided state.
*
* @param state Navigation state object.
*/
resetRoot(state: PartialState<NavigationState> | NavigationState): void;
resetRoot(state?: PartialState<NavigationState> | NavigationState): void;
getRootState(): NavigationState;
}
})
| undefined
| null;

View File

@@ -62,7 +62,7 @@ export default function useDevTools({ name, reset, state }: Options) {
);
const trackState = React.useCallback(
(state: State) => {
(getState: () => State) => {
if (!devTools) {
return;
}
@@ -71,9 +71,11 @@ export default function useDevTools({ name, reset, state }: Options) {
devTools.send(actions.current.shift(), lastStateRef.current);
}
const state = getState();
if (actions.current.length) {
devTools.send(actions.current.pop(), state);
} else if (lastStateRef.current !== state) {
} else {
devTools.send('@@UNKNOWN', state);
}

View File

@@ -61,11 +61,9 @@ const getRouteConfigsFromChildren = <ScreenOptions extends object>(
if (child.type === Screen) {
// We can only extract the config from `Screen` elements
// If something else was rendered, it's probably a bug
acc.push(child.props as RouteConfig<
ParamListBase,
string,
ScreenOptions
>);
acc.push(
child.props as RouteConfig<ParamListBase, string, ScreenOptions>
);
return acc;
}
@@ -105,9 +103,9 @@ export default function useNavigationBuilder<
) {
useRegisterNavigator();
const route = React.useContext(NavigationRouteContext) as (
const route = React.useContext(NavigationRouteContext) as
| NavigatorRoute
| undefined);
| undefined;
const previousRouteRef = React.useRef(route);
@@ -243,7 +241,11 @@ export default function useNavigationBuilder<
// The update should be limited to current navigator only, so we call the router manually
const updatedState = router.getStateForAction(
state,
navigate(route.params.screen, route.params.params)
navigate(route.params.screen, route.params.params),
{
routeNames,
routeParamList,
}
);
nextState =
@@ -309,6 +311,10 @@ export default function useNavigationBuilder<
setState,
key,
listeners: actionListeners,
routerConfigOptions: {
routeNames,
routeParamList,
},
});
const onRouteFocus = useOnRouteFocus({

View File

@@ -73,13 +73,18 @@ export default function useNavigationHelpers<
isFocused: parentNavigationHelpers
? parentNavigationHelpers.isFocused
: () => true,
canGoBack: () =>
router.getStateForAction(
getState(),
CommonActions.goBack() as Action
) !== null ||
(parentNavigationHelpers && parentNavigationHelpers.canGoBack()) ||
false,
canGoBack: () => {
const state = getState();
return (
router.getStateForAction(state, CommonActions.goBack() as Action, {
routeNames: state.routeNames,
routeParamList: {},
}) !== null ||
(parentNavigationHelpers && parentNavigationHelpers.canGoBack()) ||
false
);
},
} as NavigationHelpers<ParamListBase, EventMap> &
(NavigationProp<ParamListBase, string, any, any, any> | undefined);
}, [

View File

@@ -7,6 +7,7 @@ import {
NavigationState,
PartialState,
Router,
RouterConfigOptions,
} from './types';
type Options = {
@@ -15,6 +16,7 @@ type Options = {
getState: () => NavigationState;
setState: (state: NavigationState | PartialState<NavigationState>) => void;
listeners: ChildActionListener[];
routerConfigOptions: RouterConfigOptions;
};
/**
@@ -32,6 +34,7 @@ export default function useOnAction({
setState,
key,
listeners,
routerConfigOptions,
}: Options) {
const {
onAction: onActionParent,
@@ -40,6 +43,14 @@ export default function useOnAction({
trackAction,
} = React.useContext(NavigationBuilderContext);
const routerConfigOptionsRef = React.useRef<RouterConfigOptions>(
routerConfigOptions
);
React.useEffect(() => {
routerConfigOptionsRef.current = routerConfigOptions;
});
const onAction = React.useCallback(
(
action: NavigationAction,
@@ -59,7 +70,11 @@ export default function useOnAction({
return false;
}
let result = router.getStateForAction(state, action);
let result = router.getStateForAction(
state,
action,
routerConfigOptionsRef.current
);
// If a target is specified and set to current navigator, the action shouldn't bubble
// So instead of `null`, we use the state object for such cases to signal that action was handled

View File

@@ -14,7 +14,7 @@ export default function useOnGetState({
const route = React.useContext(NavigationRouteContext);
const key = route ? route.key : 'root';
const getter = React.useCallback(() => {
const getRehydratedState = React.useCallback(() => {
const state = getState();
return {
...state,
@@ -26,6 +26,6 @@ export default function useOnGetState({
}, [getState, getStateForRoute]);
React.useEffect(() => {
return addStateGetter && addStateGetter(key, getter);
}, [addStateGetter, getter, key]);
return addStateGetter && addStateGetter(key, getRehydratedState);
}, [addStateGetter, getRehydratedState, key]);
}

View File

@@ -9,7 +9,7 @@ export default function useStateGetters() {
const stateGetters = React.useRef<Record<string, NavigatorStateGetter>>({});
const getStateForRoute = React.useCallback(
routeKey =>
(routeKey: string) =>
stateGetters.current[routeKey] === undefined
? undefined
: stateGetters.current[routeKey](),

View File

@@ -3,6 +3,42 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.23](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.22...@react-navigation/drawer@5.0.0-alpha.23) (2019-11-17)
### Bug Fixes
* pass labelStyle prop in DrawerItem label ([#170](https://github.com/react-navigation/navigation-ex/issues/170)) ([cd7c9c4](https://github.com/react-navigation/navigation-ex/commit/cd7c9c4398ce12a1e965786d91fdbe6e3c42ee0a))
* workaround SafereaProvider causing jumping ([c17ad18](https://github.com/react-navigation/navigation-ex/commit/c17ad18b20cb05c577e1235a58ccc1c856fee086)), closes [#174](https://github.com/react-navigation/navigation-ex/issues/174)
# [5.0.0-alpha.22](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.21...@react-navigation/drawer@5.0.0-alpha.22) (2019-11-10)
**Note:** Version bump only for package @react-navigation/drawer
# [5.0.0-alpha.21](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.20...@react-navigation/drawer@5.0.0-alpha.21) (2019-11-08)
**Note:** Version bump only for package @react-navigation/drawer
# [5.0.0-alpha.20](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.19...@react-navigation/drawer@5.0.0-alpha.20) (2019-11-04)
**Note:** Version bump only for package @react-navigation/drawer
# [5.0.0-alpha.19](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.18...@react-navigation/drawer@5.0.0-alpha.19) (2019-11-02)
**Note:** Version bump only for package @react-navigation/drawer

View File

@@ -11,7 +11,7 @@
"material",
"drawer"
],
"version": "5.0.0-alpha.19",
"version": "5.0.0-alpha.23",
"license": "MIT",
"repository": {
"type": "git",
@@ -34,20 +34,20 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.11"
"@react-navigation/routers": "^5.0.0-alpha.15"
},
"devDependencies": {
"@react-native-community/bob": "^0.7.0",
"@types/react": "^16.9.4",
"@types/react-native": "^0.60.17",
"@types/react": "^16.9.11",
"@types/react-native": "^0.60.22",
"del-cli": "^3.0.0",
"react": "~16.8.3",
"react-native": "~0.59.10",
"react-native-gesture-handler": "^1.3.0",
"react-native-reanimated": "^1.3.0",
"react-native-safe-area-context": "^0.3.6",
"react-native-screens": "^2.0.0-alpha.7",
"typescript": "^3.6.3"
"react-native-gesture-handler": "^1.5.0",
"react-native-reanimated": "^1.4.0",
"react-native-safe-area-context": "^0.6.0",
"react-native-screens": "^2.0.0-alpha.11",
"typescript": "^3.7.2"
},
"peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -1,9 +1,7 @@
/**
* Navigators
*/
export {
default as createDrawerNavigator,
} from './navigators/createDrawerNavigator';
export { default as createDrawerNavigator } from './navigators/createDrawerNavigator';
/**
* Views

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import {
createNavigator,
createNavigatorFactory,
useNavigationBuilder,
DefaultNavigatorOptions,
} from '@react-navigation/core';
@@ -48,6 +48,7 @@ function DrawerNavigator({
);
}
export default createNavigator<DrawerNavigationOptions, typeof DrawerNavigator>(
DrawerNavigator
);
export default createNavigatorFactory<
DrawerNavigationOptions,
typeof DrawerNavigator
>(DrawerNavigator);

View File

@@ -69,14 +69,14 @@ export type DrawerNavigationConfig<T = DrawerContentOptions> = {
*/
unmountInactiveScreens?: boolean;
/**
* Custom component used to render as the content of the drawer, for example, navigation items.
* Defaults to `DrawerItems`.
* Function that returns React element to render as the content of the drawer, for example, navigation items.
* Defaults to `DrawerContent`.
*/
contentComponent: React.ComponentType<DrawerContentComponentProps<T>>;
drawerContent: (props: DrawerContentComponentProps<T>) => React.ReactNode;
/**
* Options for the content component which will be passed as props.
*/
contentOptions?: T;
drawerContentOptions?: T;
/**
* Style object for the component wrapping the screen content.
*/
@@ -89,16 +89,34 @@ export type DrawerNavigationConfig<T = DrawerContentOptions> = {
};
export type DrawerNavigationOptions = {
/**
* Title text for the screen.
*/
title?: string;
/**
* Title string of a screen displayed in the drawer
* or a function that given { focused: boolean, color: string } returns a React.Node
* When undefined, scene title is used.
*/
drawerLabel?:
| string
| ((props: { color: string; focused: boolean }) => React.ReactNode);
/**
* A function that given { focused: boolean, color: string } returns a React.Node to display an icon the drawer.
*/
drawerIcon?: (props: {
color: string;
size: number;
focused: boolean;
}) => React.ReactNode;
drawerLockMode?: 'unlocked' | 'locked-closed' | 'locked-open';
/**
* Whether you can use gestures to open or close the drawer.
* Defaults to `true`
*/
gestureEnabled?: boolean;
};
export type DrawerContentComponentProps<T = DrawerContentOptions> = T & {

View File

@@ -78,7 +78,7 @@ type Props = {
onOpen: () => void;
onClose: () => void;
onGestureRef?: (ref: PanGestureHandler | null) => void;
locked: boolean;
gestureEnabled: boolean;
drawerPosition: 'left' | 'right';
drawerType: 'front' | 'back' | 'slide';
keyboardDismissMode: 'none' | 'on-drag';
@@ -112,14 +112,14 @@ export default class DrawerView extends React.PureComponent<Props> {
open,
drawerPosition,
drawerType,
locked,
gestureEnabled,
swipeDistanceThreshold,
swipeVelocityThreshold,
hideStatusBar,
} = this.props;
if (prevProps.locked !== locked) {
this.isLocked.setValue(locked ? TRUE : FALSE);
if (prevProps.gestureEnabled !== gestureEnabled) {
this.isGestureEnabled.setValue(gestureEnabled ? TRUE : FALSE);
}
if (
@@ -168,7 +168,9 @@ export default class DrawerView extends React.PureComponent<Props> {
private isDrawerTypeFront = new Value<Binary>(
this.props.drawerType === 'front' ? TRUE : FALSE
);
private isLocked = new Value(this.props.locked ? TRUE : FALSE);
private isGestureEnabled = new Value(
this.props.gestureEnabled ? TRUE : FALSE
);
private isOpen = new Value<Binary>(this.props.open ? TRUE : FALSE);
private nextIsOpen = new Value<Binary | -1>(UNSET);
@@ -446,7 +448,7 @@ export default class DrawerView extends React.PureComponent<Props> {
nativeEvent: {
oldState: (s: Animated.Value<number>) =>
cond(
and(eq(s, State.ACTIVE), eq(this.isLocked, FALSE)),
and(eq(s, State.ACTIVE), this.isGestureEnabled),
set(this.manuallyTriggerSpring, TRUE)
),
},
@@ -488,7 +490,7 @@ export default class DrawerView extends React.PureComponent<Props> {
render() {
const {
open,
locked,
gestureEnabled,
drawerPosition,
drawerType,
swipeEdgeWidth,
@@ -529,7 +531,7 @@ export default class DrawerView extends React.PureComponent<Props> {
onGestureEvent={this.handleGestureEvent}
onHandlerStateChange={this.handleGestureStateChange}
hitSlop={hitSlop}
enabled={!locked}
enabled={gestureEnabled}
{...gestureHandlerProps}
>
<Animated.View

View File

@@ -64,6 +64,7 @@ type Props = {
export default function DrawerItem({
icon,
label,
labelStyle,
focused = false,
activeTintColor = '#6200ee',
inactiveTintColor = 'rgba(0, 0, 0, .68)',
@@ -99,24 +100,29 @@ export default function DrawerItem({
>
<React.Fragment>
{iconNode}
{typeof label === 'function' ? (
label({ color, focused })
) : (
<Text
numberOfLines={1}
style={[
styles.label,
{
color,
fontWeight: '500',
marginLeft: iconNode ? 32 : 0,
marginVertical: 5,
},
]}
>
{label}
</Text>
)}
<View
style={[
styles.label,
{ marginLeft: iconNode ? 32 : 0, marginVertical: 5 },
]}
>
{typeof label === 'string' ? (
<Text
numberOfLines={1}
style={[
{
color,
fontWeight: '500',
},
labelStyle,
]}
>
{label}
</Text>
) : (
label({ color, focused })
)}
</View>
</React.Fragment>
</TouchableItem>
</View>

View File

@@ -6,7 +6,6 @@ import {
Platform,
ScaledSize,
} from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
// eslint-disable-next-line import/no-unresolved
import { ScreenContainer } from 'react-native-screens';
import { PanGestureHandler } from 'react-native-gesture-handler';
@@ -16,6 +15,7 @@ import {
} from '@react-navigation/routers';
import DrawerGestureContext from '../utils/DrawerGestureContext';
import SafeAreaProviderCompat from './SafeAreaProviderCompat';
import ResourceSavingScene from './ResourceSavingScene';
import DrawerContent from './DrawerContent';
import Drawer from './Drawer';
@@ -23,6 +23,7 @@ import {
DrawerDescriptorMap,
DrawerNavigationConfig,
DrawerNavigationHelpers,
DrawerContentComponentProps,
} from '../types';
type Props = Omit<DrawerNavigationConfig, 'overlayColor'> & {
@@ -64,7 +65,9 @@ const getDefaultDrawerWidth = ({
export default class DrawerView extends React.PureComponent<Props, State> {
static defaultProps = {
lazy: true,
contentComponent: DrawerContent,
drawerContent: (props: DrawerContentComponentProps) => (
<DrawerContent {...props} />
),
drawerPosition: I18nManager.isRTL ? 'right' : 'left',
keyboardDismissMode: 'on-drag',
overlayColor: 'rgba(0, 0, 0, 0.5)',
@@ -135,20 +138,18 @@ export default class DrawerView extends React.PureComponent<Props, State> {
navigation,
descriptors,
drawerPosition,
contentComponent: ContentComponent,
contentOptions,
drawerContent,
drawerContentOptions,
} = this.props;
return (
<ContentComponent
progress={progress}
state={state}
navigation={navigation}
descriptors={descriptors}
drawerPosition={drawerPosition}
{...contentOptions}
/>
);
return drawerContent({
...drawerContentOptions,
progress: progress,
state: state,
navigation: navigation,
descriptors: descriptors,
drawerPosition: drawerPosition,
});
};
private renderContent = () => {
@@ -209,24 +210,14 @@ export default class DrawerView extends React.PureComponent<Props, State> {
const { drawerWidth } = this.state;
const activeKey = state.routes[state.index].key;
const { drawerLockMode } = descriptors[activeKey].options;
const isOpen =
drawerLockMode === 'locked-closed'
? false
: drawerLockMode === 'locked-open'
? true
: state.isDrawerOpen;
const { gestureEnabled } = descriptors[activeKey].options;
return (
<SafeAreaProvider>
<SafeAreaProviderCompat>
<DrawerGestureContext.Provider value={this.drawerGestureRef}>
<Drawer
open={isOpen}
locked={
drawerLockMode === 'locked-open' ||
drawerLockMode === 'locked-closed'
}
open={state.isDrawerOpen}
gestureEnabled={gestureEnabled === true}
onOpen={this.handleDrawerOpen}
onClose={this.handleDrawerClose}
onGestureRef={this.setDrawerGestureRef}
@@ -244,7 +235,7 @@ export default class DrawerView extends React.PureComponent<Props, State> {
renderSceneContent={this.renderContent}
/>
</DrawerGestureContext.Provider>
</SafeAreaProvider>
</SafeAreaProviderCompat>
);
}
}

View File

@@ -0,0 +1,26 @@
import * as React from 'react';
import {
SafeAreaProvider,
SafeAreaConsumer,
} from 'react-native-safe-area-context';
type Props = {
children: React.ReactNode;
};
export default function SafeAreaProviderCompat({ children }: Props) {
return (
<SafeAreaConsumer>
{insets => {
if (insets) {
// If we already have insets, don't wrap the stack in another safe area provider
// This avoids an issue with updates at the cost of potentially incorrect values
// https://github.com/react-navigation/navigation-ex/issues/174
return children;
}
return <SafeAreaProvider>{children}</SafeAreaProvider>;
}}
</SafeAreaConsumer>
);
}

View File

@@ -3,6 +3,38 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.22](https://github.com/satya164/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.21...@react-navigation/example@5.0.0-alpha.22) (2019-11-17)
**Note:** Version bump only for package @react-navigation/example
# [5.0.0-alpha.21](https://github.com/satya164/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.20...@react-navigation/example@5.0.0-alpha.21) (2019-11-10)
**Note:** Version bump only for package @react-navigation/example
# [5.0.0-alpha.20](https://github.com/satya164/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.19...@react-navigation/example@5.0.0-alpha.20) (2019-11-08)
**Note:** Version bump only for package @react-navigation/example
# [5.0.0-alpha.19](https://github.com/satya164/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.18...@react-navigation/example@5.0.0-alpha.19) (2019-11-04)
**Note:** Version bump only for package @react-navigation/example
# [5.0.0-alpha.18](https://github.com/satya164/navigation-ex/compare/@react-navigation/example@5.0.0-alpha.17...@react-navigation/example@5.0.0-alpha.18) (2019-11-02)

View File

@@ -34,7 +34,7 @@ PODS:
- glog (0.3.5)
- React (0.59.10):
- React/Core (= 0.59.10)
- react-native-safe-area-context (0.3.6):
- react-native-safe-area-context (0.6.0):
- React
- React/Core (0.59.10):
- yoga (= 0.59.10.React)
@@ -93,7 +93,7 @@ PODS:
- React
- RNReanimated (1.2.0):
- React
- RNScreens (2.0.0-alpha.7):
- RNScreens (2.0.0-alpha.11):
- React
- UMBarCodeScannerInterface (4.0.0)
- UMCameraInterface (4.0.0)
@@ -264,10 +264,10 @@ SPEC CHECKSUMS:
Folly: de497beb10f102453a1afa9edbf8cf8a251890de
glog: aefd1eb5dda2ab95ba0938556f34b98e2da3a60d
React: 36d0768f9e93be2473b37e7fa64f92c1d5341eef
react-native-safe-area-context: e380a6f783ccaec848e2f3cc8eb205a62362950d
react-native-safe-area-context: d288138da2c800caa111f9352e9333f186a06ead
RNGestureHandler: 5329a942fce3d41c68b84c2c2276ce06a696d8b0
RNReanimated: 1b52415c4302f198cb581282a0166690bad62c43
RNScreens: 2f53466846305189a0cfd1745f26b6ca141b3a08
RNScreens: ad3661f864ef18d952e9a4799b6791683e33c1fc
UMBarCodeScannerInterface: d5a6fdc98ed6241225b0a8432a7f4e2b397668bc
UMCameraInterface: 68870a3197fee85bd5afca5609ba4a5b7257d19d
UMConstantsInterface: d25b8e8887ca7aaf568c06caf08f4d40734ee4ef

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1017 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,38 +1 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"}]}

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/example",
"description": "Demo app to showcase various functionality of React Navigation",
"version": "5.0.0-alpha.18",
"version": "5.0.0-alpha.22",
"private": true,
"workspaces": {
"nohoist": [
@@ -18,35 +18,35 @@
"postinstall": "jetify"
},
"dependencies": {
"@expo/vector-icons": "^10.0.0",
"@react-native-community/masked-view": "^0.1.1",
"expo": "^35.0.0",
"@expo/vector-icons": "^10.0.5",
"@react-native-community/masked-view": "^0.1.5",
"expo": "^35.0.1",
"expo-asset": "~7.0.0",
"query-string": "^6.8.3",
"query-string": "^6.9.0",
"react": "~16.8.3",
"react-dom": "~16.8.3",
"react-native": "~0.59.10",
"react-native-gesture-handler": "~1.3.0",
"react-native-paper": "^3.1.1",
"react-native-gesture-handler": "~1.5.0",
"react-native-paper": "^3.2.1",
"react-native-reanimated": "~1.2.0",
"react-native-reanimated-web": "npm:react-native-reanimated@^1.3.2",
"react-native-safe-area-context": "~0.3.6",
"react-native-screens": "^2.0.0-alpha.7",
"react-native-tab-view": "2.10.0",
"react-native-safe-area-context": "~0.6.0",
"react-native-screens": "^2.0.0-alpha.11",
"react-native-tab-view": "2.10.2",
"react-native-unimodules": "^0.7.0-rc.1",
"react-native-web": "^0.11.7",
"scheduler": "^0.16.1",
"scheduler": "^0.18.0",
"shortid": "^2.2.15",
"use-subscription": "^1.1.1"
"use-subscription": "^1.3.0"
},
"devDependencies": {
"@babel/core": "^7.6.2",
"@expo/webpack-config": "^0.7.12",
"@types/react": "^16.9.4",
"@types/react-native": "^0.60.19",
"babel-preset-expo": "^7.0.0",
"expo-cli": "^3.4.1",
"@babel/core": "^7.7.2",
"@expo/webpack-config": "^0.10.1",
"@types/react": "^16.9.11",
"@types/react-native": "^0.60.22",
"babel-preset-expo": "^7.1.0",
"expo-cli": "^3.8.0",
"jetifier": "^1.6.4",
"typescript": "^3.6.3"
"typescript": "^3.7.2"
}
}

View File

@@ -9,17 +9,11 @@ import SimpleStackScreen from './SimpleStack';
const getTabBarIcon = (name: string) => ({
color,
horizontal,
size,
}: {
color: string;
horizontal: boolean;
}) => (
<MaterialCommunityIcons
name={name}
color={color}
size={horizontal ? 17 : 24}
/>
);
size: number;
}) => <MaterialCommunityIcons name={name} color={color} size={size} />;
type BottomTabParams = {
article: undefined;
@@ -32,13 +26,16 @@ const BottomTabs = createBottomTabNavigator<BottomTabParams>();
export default function BottomTabsScreen() {
return (
<BottomTabs.Navigator>
<BottomTabs.Navigator
screenOptions={{
tabBarButton: props => <TouchableBounce {...props} />,
}}
>
<BottomTabs.Screen
name="article"
options={{
title: 'Article',
tabBarIcon: getTabBarIcon('file-document-box'),
tabBarButtonComponent: TouchableBounce,
}}
>
{props => <SimpleStackScreen {...props} headerMode="none" />}
@@ -49,7 +46,6 @@ export default function BottomTabsScreen() {
options={{
tabBarLabel: 'Chat',
tabBarIcon: getTabBarIcon('message-reply'),
tabBarButtonComponent: TouchableBounce,
}}
/>
<BottomTabs.Screen
@@ -58,7 +54,6 @@ export default function BottomTabsScreen() {
options={{
title: 'Contacts',
tabBarIcon: getTabBarIcon('contacts'),
tabBarButtonComponent: TouchableBounce,
}}
/>
<BottomTabs.Screen
@@ -67,7 +62,6 @@ export default function BottomTabsScreen() {
options={{
title: 'Albums',
tabBarIcon: getTabBarIcon('image-album'),
tabBarButtonComponent: TouchableBounce,
}}
/>
</BottomTabs.Navigator>

View File

@@ -17,9 +17,10 @@ type CompatStackParams = {
Album: undefined;
};
const ArticleScreen: CompatScreenType<
StackNavigationProp<CompatStackParams, 'Article'>
> = ({ navigation }) => {
const ArticleScreen: CompatScreenType<StackNavigationProp<
CompatStackParams,
'Article'
>> = ({ navigation }) => {
return (
<React.Fragment>
<View style={styles.buttons}>
@@ -47,9 +48,9 @@ ArticleScreen.navigationOptions = ({ navigation }) => ({
title: `Article by ${navigation.getParam('author')}`,
});
const AlbumsScreen: CompatScreenType<
StackNavigationProp<CompatStackParams>
> = ({ navigation }) => {
const AlbumsScreen: CompatScreenType<StackNavigationProp<
CompatStackParams
>> = ({ navigation }) => {
return (
<React.Fragment>
<View style={styles.buttons}>

View File

@@ -96,11 +96,11 @@ export default function NativeStackScreen({ navigation }: Props) {
>;
navigation.setOptions({ gestureEnabled: false });
drawer.setOptions({ drawerLockMode: 'locked-closed' });
drawer.setOptions({ gestureEnabled: false });
return () => {
navigation.setOptions({ gestureEnabled: true });
drawer.setOptions({ drawerLockMode: 'unlocked' });
drawer.setOptions({ gestureEnabled: true });
};
}, [navigation])
);

View File

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

View File

@@ -11,7 +11,7 @@
"material",
"tab"
],
"version": "5.0.0-alpha.17",
"version": "5.0.0-alpha.21",
"license": "MIT",
"repository": {
"type": "git",
@@ -34,19 +34,19 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.11"
"@react-navigation/routers": "^5.0.0-alpha.15"
},
"devDependencies": {
"@react-native-community/bob": "^0.7.0",
"@types/react": "^16.9.4",
"@types/react-native": "^0.60.17",
"@types/react": "^16.9.11",
"@types/react-native": "^0.60.22",
"@types/react-native-vector-icons": "^6.4.4",
"del-cli": "^3.0.0",
"react": "~16.8.3",
"react-native": "~0.59.10",
"react-native-paper": "^3.1.1",
"react-native-paper": "^3.2.1",
"react-native-vector-icons": "^6.6.0",
"typescript": "^3.6.3"
"typescript": "^3.7.2"
},
"peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -1,9 +1,7 @@
/**
* Navigators
*/
export {
default as createMaterialBottomTabNavigator,
} from './navigators/createMaterialBottomTabNavigator';
export { default as createMaterialBottomTabNavigator } from './navigators/createMaterialBottomTabNavigator';
/**
* Types

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import {
useNavigationBuilder,
createNavigator,
createNavigatorFactory,
DefaultNavigatorOptions,
} from '@react-navigation/core';
import {
@@ -50,7 +50,7 @@ function MaterialBottomTabNavigator({
);
}
export default createNavigator<
export default createNavigatorFactory<
MaterialBottomTabNavigationOptions,
typeof MaterialBottomTabNavigator
>(MaterialBottomTabNavigator);

View File

@@ -36,7 +36,7 @@ export type MaterialBottomTabNavigationProp<
* @param [params] Params object for the route.
*/
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
...args: ParamList[RouteName] extends (undefined | any)
...args: ParamList[RouteName] extends undefined | any
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;

View File

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

View File

@@ -11,7 +11,7 @@
"material",
"tab"
],
"version": "5.0.0-alpha.14",
"version": "5.0.0-alpha.18",
"license": "MIT",
"repository": {
"type": "git",
@@ -34,19 +34,19 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.11"
"@react-navigation/routers": "^5.0.0-alpha.15"
},
"devDependencies": {
"@react-native-community/bob": "^0.7.0",
"@types/react": "^16.9.4",
"@types/react-native": "^0.60.17",
"@types/react": "^16.9.11",
"@types/react-native": "^0.60.22",
"del-cli": "^3.0.0",
"react": "~16.8.3",
"react-native": "~0.59.10",
"react-native-gesture-handler": "^1.3.0",
"react-native-reanimated": "^1.3.0",
"react-native-tab-view": "^2.10.0",
"typescript": "^3.6.3"
"react-native-gesture-handler": "^1.5.0",
"react-native-reanimated": "^1.4.0",
"react-native-tab-view": "^2.10.1",
"typescript": "^3.7.2"
},
"peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -1,9 +1,7 @@
/**
* Navigators
*/
export {
default as createMaterialTopTabNavigator,
} from './navigators/createMaterialTopTabNavigator';
export { default as createMaterialTopTabNavigator } from './navigators/createMaterialTopTabNavigator';
/**
* Views

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import {
useNavigationBuilder,
createNavigator,
createNavigatorFactory,
DefaultNavigatorOptions,
} from '@react-navigation/core';
import {
@@ -49,7 +49,7 @@ function MaterialTopTabNavigator({
);
}
export default createNavigator<
export default createNavigatorFactory<
MaterialTopTabNavigationOptions,
typeof MaterialTopTabNavigator
>(MaterialTopTabNavigator);

View File

@@ -50,7 +50,7 @@ export type MaterialTopTabNavigationProp<
* @param [params] Params object for the route.
*/
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
...args: ParamList[RouteName] extends (undefined | any)
...args: ParamList[RouteName] extends undefined | any
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;
@@ -63,20 +63,18 @@ export type MaterialTopTabNavigationOptions = {
title?: string;
/**
* Title string of a tab displayed in the tab bar or React Element
* Title string of a tab displayed in the tab bar
* or a function that given { focused: boolean, color: string } returns a React.Node, to display in tab bar.
* When undefined, scene title is used. To hide, see tabBarOptions.showLabel in the previous section.
*/
tabBarLabel?:
| React.ReactNode
| string
| ((props: { focused: boolean; color: string }) => React.ReactNode);
/**
* React Element or a function that given { focused: boolean, color: string } returns a React.Node, to display in the tab bar.
* A function that given { focused: boolean, color: string } returns a React.Node to display in the tab bar.
*/
tabBarIcon?:
| React.ReactNode
| ((props: { focused: boolean; color: string }) => React.ReactNode);
tabBarIcon?: (props: { focused: boolean; color: string }) => React.ReactNode;
/**
* Accessibility label for the tab button. This is read by the screen reader when the user taps the tab.
@@ -119,7 +117,7 @@ export type MaterialTopTabNavigationConfig = Partial<
>
> & {
/**
* Component to render for routes that haven't been rendered yet.
* Function that returns a React element to render for routes that haven't been rendered yet.
* Receives an object containing the route as the prop.
* The lazy prop also needs to be enabled.
*
@@ -127,11 +125,11 @@ export type MaterialTopTabNavigationConfig = Partial<
*
* By default, this renders null.
*/
lazyPlaceholderComponent?: React.ComponentType<{ route: Route<string> }>;
lazyPlaceholder?: (props: { route: Route<string> }) => React.ReactNode;
/**
* Custom tab bar component.
* Function that returns a React element to display as the tab bar.
*/
tabBarComponent?: React.ComponentType<MaterialTopTabBarProps>;
tabBar?: (props: MaterialTopTabBarProps) => React.ReactNode;
/**
* Options for the tab bar which will be passed as props to the tab bar component.
*/
@@ -197,7 +195,7 @@ export type MaterialTopTabBarProps = MaterialTopTabBarOptions &
route: Route<string>;
}) =>
| ((scene: { focused: boolean; color: string }) => React.ReactNode)
| React.ReactNode;
| string;
getAccessibilityLabel: (props: {
route: Route<string>;
}) => string | undefined;

View File

@@ -52,11 +52,7 @@ export default class TabBarTop extends React.PureComponent<
);
}
if (typeof label === 'function') {
return label({ focused, color });
}
return label;
return label({ focused, color });
};
private renderIcon = ({
@@ -77,10 +73,7 @@ export default class TabBarTop extends React.PureComponent<
const { options } = descriptors[route.key];
if (options.tabBarIcon !== undefined) {
const icon =
typeof options.tabBarIcon === 'function'
? options.tabBarIcon({ focused, color })
: options.tabBarIcon;
const icon = options.tabBarIcon({ focused, color });
return <View style={[styles.icon, iconStyle]}>{icon}</View>;
}

View File

@@ -8,6 +8,7 @@ import {
MaterialTopTabDescriptorMap,
MaterialTopTabNavigationConfig,
MaterialTopTabNavigationHelpers,
MaterialTopTabBarProps,
} from '../types';
type Props = MaterialTopTabNavigationConfig & {
@@ -23,10 +24,10 @@ export default class MaterialTopTabView extends React.PureComponent<Props> {
};
private renderLazyPlaceholder = (props: { route: Route<string> }) => {
const { lazyPlaceholderComponent: LazyPlaceholder } = this.props;
const { lazyPlaceholder } = this.props;
if (LazyPlaceholder != null) {
return <LazyPlaceholder {...props} />;
if (lazyPlaceholder != null) {
return lazyPlaceholder(props);
}
return null;
@@ -99,30 +100,30 @@ export default class MaterialTopTabView extends React.PureComponent<Props> {
const {
navigation,
tabBarComponent: TabBarComponent = MaterialTopTabBar,
tabBar = (props: MaterialTopTabBarProps) => (
<MaterialTopTabBar {...props} />
),
tabBarPosition,
tabBarOptions,
} = this.props;
if (TabBarComponent === null || !tabBarVisible) {
if (tabBarVisible === false) {
return null;
}
return (
<TabBarComponent
{...tabBarOptions}
{...props}
tabBarPosition={tabBarPosition}
state={state}
navigation={navigation}
descriptors={descriptors}
getAccessibilityLabel={this.getAccessibilityLabel}
getLabelText={this.getLabelText}
getTestID={this.getTestID}
onTabPress={this.handleTabPress}
onTabLongPress={this.handleTabLongPress}
/>
);
return tabBar({
...tabBarOptions,
...props,
tabBarPosition: tabBarPosition,
state: state,
navigation: navigation,
descriptors: descriptors,
getAccessibilityLabel: this.getAccessibilityLabel,
getLabelText: this.getLabelText,
getTestID: this.getTestID,
onTabPress: this.handleTabPress,
onTabLongPress: this.handleTabLongPress,
});
};
private handleSwipeStart = () =>
@@ -138,8 +139,8 @@ export default class MaterialTopTabView extends React.PureComponent<Props> {
render() {
const {
/* eslint-disable @typescript-eslint/no-unused-vars */
lazyPlaceholderComponent,
tabBarComponent,
lazyPlaceholder,
tabBar,
tabBarOptions,
/* eslint-enable @typescript-eslint/no-unused-vars */
state,

View File

@@ -3,6 +3,60 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.13](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.12...@react-navigation/native-stack@5.0.0-alpha.13) (2019-11-17)
**Note:** Version bump only for package @react-navigation/native-stack
# [5.0.0-alpha.12](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.11...@react-navigation/native-stack@5.0.0-alpha.12) (2019-11-10)
**Note:** Version bump only for package @react-navigation/native-stack
# [5.0.0-alpha.11](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.10...@react-navigation/native-stack@5.0.0-alpha.11) (2019-11-08)
**Note:** Version bump only for package @react-navigation/native-stack
# [5.0.0-alpha.10](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.9...@react-navigation/native-stack@5.0.0-alpha.10) (2019-11-04)
### Bug Fixes
* popToTop on tab press in native stack ([301c35e](https://github.com/react-navigation/navigation-ex/commit/301c35e))
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.8...@react-navigation/native-stack@5.0.0-alpha.9) (2019-11-04)
**Note:** Version bump only for package @react-navigation/native-stack
# [5.0.0-alpha.8](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.7...@react-navigation/native-stack@5.0.0-alpha.8) (2019-11-02)
### Features
* add headerBackTitleVisible to navigation options in native stack ([77f29d3](https://github.com/react-navigation/navigation-ex/commit/77f29d3))
# [5.0.0-alpha.7](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.6...@react-navigation/native-stack@5.0.0-alpha.7) (2019-11-02)

View File

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

View File

@@ -1,9 +1,7 @@
/**
* Navigators
*/
export {
default as createNativeStackNavigator,
} from './navigators/createNativeStackNavigator';
export { default as createNativeStackNavigator } from './navigators/createNativeStackNavigator';
/**
* Types

View File

@@ -1,10 +1,15 @@
import React from 'react';
import { createNavigator, useNavigationBuilder } from '@react-navigation/core';
import {
createNavigatorFactory,
useNavigationBuilder,
EventArg,
} from '@react-navigation/core';
import {
StackRouter,
StackNavigationState,
StackRouterOptions,
StackActions,
} from '@react-navigation/routers';
import {
@@ -36,6 +41,28 @@ function NativeStackNavigator(props: NativeStackNavigatorProps) {
screenOptions,
});
React.useEffect(
() =>
navigation.addListener &&
navigation.addListener('tabPress', (e: EventArg<'tabPress'>) => {
const isFocused = navigation.isFocused();
// Run the operation in the next frame so we're sure all listeners have been run
// This is necessary to know if preventDefault() has been called
requestAnimationFrame(() => {
if (state.index > 0 && isFocused && !e.defaultPrevented) {
// When user taps on already focused tab and we're inside the tab,
// reset the stack to replicate native behaviour
navigation.dispatch({
...StackActions.popToTop(),
target: state.key,
});
}
});
}),
[navigation, state.index, state.key]
);
return (
<StackView
state={state}
@@ -46,7 +73,7 @@ function NativeStackNavigator(props: NativeStackNavigatorProps) {
);
}
export default createNavigator<
export default createNavigatorFactory<
NativeStackNavigationOptions,
typeof NativeStackNavigator
>(NativeStackNavigator);

View File

@@ -29,7 +29,7 @@ export type NativeStackNavigationProp<
* @param [params] Params object for the route.
*/
push<RouteName extends keyof ParamList>(
...args: ParamList[RouteName] extends (undefined | any)
...args: ParamList[RouteName] extends undefined | any
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;
@@ -65,6 +65,13 @@ export type NativeStackNavigationOptions = {
* @platform ios
*/
headerBackTitle?: string;
/**
* Whether the back button title should be visible or not. Defaults to `true`.
* Only supported on iOS.
*
* @platform ios
*/
headerBackTitleVisible?: boolean;
/**
* Whether to show the header.
*/
@@ -99,10 +106,7 @@ export type NativeStackNavigationOptions = {
*/
headerHideBackButton?: boolean;
/**
* Boolean indicating whether to hide the elevation shadow on the header.
* Only supported on Android.
*
* @platform android
* Boolean indicating whether to hide the elevation shadow or the bottom border on the header.
*/
headerHideShadow?: boolean;
/**

View File

@@ -20,6 +20,7 @@ export default function HeaderConfig(props: Props) {
headerRight,
headerTitle,
headerBackTitle,
headerBackTitleVisible = true,
headerHideBackButton,
headerHideShadow,
headerTintColor,
@@ -53,7 +54,7 @@ export default function HeaderConfig(props: Props) {
? headerTitleStyle.color
: headerTintColor
}
backTitle={headerBackTitle}
backTitle={headerBackTitleVisible ? headerBackTitle : ''}
backTitleFontFamily={headerBackTitleStyle.fontFamily}
backTitleFontSize={headerBackTitleStyle.fontSize}
color={headerTintColor}

View File

@@ -5,7 +5,8 @@ import { StackNavigationState, StackActions } from '@react-navigation/routers';
import {
// @ts-ignore
ScreenStack,
Screen,
Screen as ScreenComponent,
ScreenProps,
// eslint-disable-next-line import/no-unresolved
} from 'react-native-screens';
import HeaderConfig from './HeaderConfig';
@@ -14,6 +15,14 @@ import {
NativeStackDescriptorMap,
} from '../types';
const Screen = (ScreenComponent as unknown) as React.ComponentType<
ScreenProps & {
stackPresentation?: 'push' | 'modal' | 'transparentModal';
stackAnimation?: 'default' | 'fade' | 'none';
onDismissed?: () => void;
}
>;
type Props = {
state: StackNavigationState;
navigation: NativeStackNavigationHelpers;
@@ -28,7 +37,6 @@ export default function StackView({ state, navigation, descriptors }: Props) {
const { presentation = 'push', animation, contentStyle } = options;
return (
// @ts-ignore
<Screen
key={route.key}
style={StyleSheet.absoluteFill}

View File

@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.16](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native@5.0.0-alpha.15...@react-navigation/native@5.0.0-alpha.16) (2019-11-17)
**Note:** Version bump only for package @react-navigation/native
# [5.0.0-alpha.15](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native@5.0.0-alpha.14...@react-navigation/native@5.0.0-alpha.15) (2019-11-08)
### Bug Fixes
* don't call getNode if ref is already scrollable ([#162](https://github.com/react-navigation/navigation-ex/issues/162)) ([66551f2](https://github.com/react-navigation/navigation-ex/commit/66551f2))
# [5.0.0-alpha.14](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native@5.0.0-alpha.13...@react-navigation/native@5.0.0-alpha.14) (2019-10-30)

View File

@@ -7,7 +7,7 @@
"ios",
"android"
],
"version": "5.0.0-alpha.14",
"version": "5.0.0-alpha.16",
"license": "MIT",
"repository": {
"type": "git",
@@ -31,12 +31,12 @@
},
"devDependencies": {
"@react-native-community/bob": "^0.7.0",
"@types/react": "^16.9.4",
"@types/react-native": "^0.60.17",
"@types/react": "^16.9.11",
"@types/react-native": "^0.60.22",
"del-cli": "^3.0.0",
"react": "~16.8.3",
"react-native": "~0.59.10",
"typescript": "^3.6.3"
"typescript": "^3.7.2"
},
"peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0",

View File

@@ -1,6 +1,4 @@
export {
default as NavigationNativeContainer,
} from './NavigationNativeContainer';
export { default as NavigationNativeContainer } from './NavigationNativeContainer';
export { default as useBackButton } from './useBackButton';
export { default as useLinking } from './useLinking';

View File

@@ -19,13 +19,23 @@ function getScrollableNode(ref: React.RefObject<ScrollableWrapper>) {
return null;
}
if ('getScrollResponder' in ref.current) {
if (
'scrollToTop' in ref.current ||
'scrollTo' in ref.current ||
'scrollToOffset' in ref.current ||
'scrollResponderScrollTo' in ref.current
) {
// This is already a scrollable node.
return ref.current;
} else if ('getScrollResponder' in ref.current) {
// If the view is a wrapper like FlatList, SectionList etc.
// We need to use `getScrollResponder` to get access to the scroll responder
return ref.current.getScrollResponder();
} else if ('getNode' in ref.current) {
// When a `ScrollView` is wraped in `Animated.createAnimatedComponent`
// we need to use `getNode` to get the ref to the actual scrollview
// we need to use `getNode` to get the ref to the actual scrollview.
// Note that `getNode` is deprecated in newer versions of react-native
// this is why we check if we already have a scrollable node above.
return ref.current.getNode();
} else {
return ref.current;

View File

@@ -3,6 +3,47 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.15](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.14...@react-navigation/routers@5.0.0-alpha.15) (2019-11-17)
### Bug Fixes
* merge initial params on push ([11efb06](https://github.com/react-navigation/navigation-ex/commit/11efb066429a3fc8b7e8e48d897286208d9a5449))
# [5.0.0-alpha.14](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.13...@react-navigation/routers@5.0.0-alpha.14) (2019-11-10)
**Note:** Version bump only for package @react-navigation/routers
# [5.0.0-alpha.13](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.12...@react-navigation/routers@5.0.0-alpha.13) (2019-11-08)
### Bug Fixes
* handle invalid initialRouteName gracefully ([b5d9ad9](https://github.com/react-navigation/navigation-ex/commit/b5d9ad9))
# [5.0.0-alpha.12](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.11...@react-navigation/routers@5.0.0-alpha.12) (2019-11-04)
### Bug Fixes
* close drawer on back button press ([3a4c38b](https://github.com/react-navigation/navigation-ex/commit/3a4c38b))
# [5.0.0-alpha.11](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.10...@react-navigation/routers@5.0.0-alpha.11) (2019-10-30)
**Note:** Version bump only for package @react-navigation/routers

View File

@@ -17,7 +17,7 @@ yarn add @react-navigation/core @react-navigation/routers
A basic custom navigator bundling a router and a view looks like this:
```js
import { useNavigationBuilder } from '@react-navigation/core';
import { createNavigatorFactory, useNavigationBuilder } from '@react-navigation/core';
import { StackRouter } from '@react-navigation/routers';
function StackNavigator({ initialRouteName, children, ...rest }) {
@@ -36,5 +36,5 @@ function StackNavigator({ initialRouteName, children, ...rest }) {
);
}
export default createNavigator(StackNavigator);
export default createNavigatorFactory(StackNavigator);
```

View File

@@ -71,7 +71,10 @@ it('gets rehydrated state from partial state', () => {
expect(
router.getRehydratedState(
{
routes: [{ key: 'bar-0', name: 'bar' }, { key: 'qux-1', name: 'qux' }],
routes: [
{ key: 'bar-0', name: 'bar' },
{ key: 'qux-1', name: 'qux' },
],
},
options
)
@@ -216,6 +219,10 @@ it("doesn't rehydrate state if it's not stale", () => {
it('handles navigate action', () => {
const router = DrawerRouter({});
const options = {
routeNames: ['baz', 'bar'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -227,9 +234,13 @@ it('handles navigate action', () => {
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
isDrawerOpen: false,
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.navigate('baz', { answer: 42 })
CommonActions.navigate('baz', { answer: 42 }),
options
)
).toEqual({
stale: false,
@@ -248,6 +259,10 @@ it('handles navigate action', () => {
it('handles navigate action with open drawer', () => {
const router = DrawerRouter({});
const options = {
routeNames: ['baz', 'bar'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -259,9 +274,13 @@ it('handles navigate action with open drawer', () => {
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
isDrawerOpen: true,
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.navigate('baz', { answer: 42 })
CommonActions.navigate('baz', { answer: 42 }),
options
)
).toEqual({
stale: false,
@@ -280,6 +299,10 @@ it('handles navigate action with open drawer', () => {
it('handles open drawer action', () => {
const router = DrawerRouter({});
const options = {
routeNames: ['baz', 'bar'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -291,9 +314,13 @@ it('handles open drawer action', () => {
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
isDrawerOpen: false,
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
DrawerActions.openDrawer()
DrawerActions.openDrawer(),
options
)
).toEqual({
stale: false,
@@ -303,7 +330,10 @@ it('handles open drawer action', () => {
routeNames: ['baz', 'bar'],
isDrawerOpen: true,
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
});
const state = {
@@ -314,16 +344,23 @@ it('handles open drawer action', () => {
routeNames: ['baz', 'bar'],
isDrawerOpen: true,
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
};
expect(router.getStateForAction(state, DrawerActions.openDrawer())).toBe(
state
);
expect(
router.getStateForAction(state, DrawerActions.openDrawer(), options)
).toBe(state);
});
it('handles close drawer action', () => {
const router = DrawerRouter({});
const options = {
routeNames: ['baz', 'bar'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -335,9 +372,13 @@ it('handles close drawer action', () => {
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
isDrawerOpen: true,
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
DrawerActions.closeDrawer()
DrawerActions.closeDrawer(),
options
)
).toEqual({
stale: false,
@@ -347,7 +388,10 @@ it('handles close drawer action', () => {
routeNames: ['baz', 'bar'],
isDrawerOpen: false,
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
});
const state = {
@@ -358,16 +402,23 @@ it('handles close drawer action', () => {
routeNames: ['baz', 'bar'],
isDrawerOpen: false,
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
};
expect(router.getStateForAction(state, DrawerActions.closeDrawer())).toBe(
state
);
expect(
router.getStateForAction(state, DrawerActions.closeDrawer(), options)
).toBe(state);
});
it('handles toggle drawer action', () => {
const router = DrawerRouter({});
const options = {
routeNames: ['baz', 'bar'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -379,9 +430,13 @@ it('handles toggle drawer action', () => {
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
isDrawerOpen: true,
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
DrawerActions.toggleDrawer()
DrawerActions.toggleDrawer(),
options
)
).toEqual({
stale: false,
@@ -391,7 +446,10 @@ it('handles toggle drawer action', () => {
routeNames: ['baz', 'bar'],
isDrawerOpen: false,
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
});
expect(
@@ -404,9 +462,13 @@ it('handles toggle drawer action', () => {
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
isDrawerOpen: false,
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
DrawerActions.toggleDrawer()
DrawerActions.toggleDrawer(),
options
)
).toEqual({
stale: false,
@@ -416,7 +478,10 @@ it('handles toggle drawer action', () => {
routeNames: ['baz', 'bar'],
isDrawerOpen: true,
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
});
});

View File

@@ -59,7 +59,10 @@ it('gets rehydrated state from partial state', () => {
expect(
router.getRehydratedState(
{
routes: [{ key: 'bar-0', name: 'bar' }, { key: 'qux-1', name: 'qux' }],
routes: [
{ key: 'bar-0', name: 'bar' },
{ key: 'qux-1', name: 'qux' },
],
},
options
)
@@ -240,6 +243,10 @@ it('gets state on route names change with initialRouteName', () => {
it('handles navigate action', () => {
const router = StackRouter({});
const options = {
routeNames: ['baz', 'bar', 'qux'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -249,9 +256,13 @@ it('handles navigate action', () => {
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.navigate('qux', { answer: 42 })
CommonActions.navigate('qux', { answer: 42 }),
options
)
).toEqual({
stale: false,
@@ -278,9 +289,13 @@ it('handles navigate action', () => {
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.navigate('baz', { answer: 42 })
CommonActions.navigate('baz', { answer: 42 }),
options
)
).toEqual({
stale: false,
@@ -304,7 +319,8 @@ it('handles navigate action', () => {
{ key: 'bar', name: 'bar', params: { answer: 42 } },
],
},
CommonActions.navigate('bar', { answer: 96 })
CommonActions.navigate('bar', { answer: 96 }),
options
)
).toEqual({
stale: false,
@@ -326,9 +342,13 @@ it('handles navigate action', () => {
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.navigate('unknown')
CommonActions.navigate('unknown'),
options
)
).toBe(null);
@@ -340,9 +360,13 @@ it('handles navigate action', () => {
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz-0', name: 'baz' }, { key: 'bar-0', name: 'bar' }],
routes: [
{ key: 'baz-0', name: 'baz' },
{ key: 'bar-0', name: 'bar' },
],
},
CommonActions.navigate({ key: 'unknown' })
CommonActions.navigate({ key: 'unknown' }),
options
)
).toBe(null);
@@ -354,12 +378,16 @@ it('handles navigate action', () => {
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz-0', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz-0', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
{
type: 'NAVIGATE',
payload: { key: 'baz-0', name: 'baz' },
}
},
options
)
).toEqual({
stale: false,
@@ -378,9 +406,13 @@ it('handles navigate action', () => {
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz-0', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz-0', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.navigate({ key: 'baz-1', name: 'baz' })
CommonActions.navigate({ key: 'baz-1', name: 'baz' }),
options
)
).toEqual({
stale: false,
@@ -398,6 +430,10 @@ it('handles navigate action', () => {
it('handles go back action', () => {
const router = StackRouter({});
const options = {
routeNames: ['baz', 'bar', 'qux'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -407,9 +443,13 @@ it('handles go back action', () => {
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.goBack()
CommonActions.goBack(),
options
)
).toEqual({
stale: false,
@@ -430,13 +470,18 @@ it('handles go back action', () => {
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz', name: 'baz' }],
},
CommonActions.goBack()
CommonActions.goBack(),
options
)
).toBe(null);
});
it('handles pop action', () => {
const router = StackRouter({});
const options = {
routeNames: ['baz', 'bar', 'qux'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -452,7 +497,8 @@ it('handles pop action', () => {
{ key: 'qux', name: 'qux' },
],
},
StackActions.pop()
StackActions.pop(),
options
)
).toEqual({
stale: false,
@@ -460,7 +506,10 @@ it('handles pop action', () => {
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
});
expect(
@@ -477,7 +526,8 @@ it('handles pop action', () => {
{ key: 'qux', name: 'qux' },
],
},
StackActions.pop(2)
StackActions.pop(2),
options
)
).toEqual({
stale: false,
@@ -506,7 +556,8 @@ it('handles pop action', () => {
...StackActions.pop(),
target: 'root',
source: 'bar-0',
}
},
options
)
).toEqual({
stale: false,
@@ -527,13 +578,18 @@ it('handles pop action', () => {
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz-0', name: 'baz' }],
},
StackActions.pop()
StackActions.pop(),
options
)
).toBe(null);
});
it('handles pop to top action', () => {
const router = StackRouter({});
const options = {
routeNames: ['baz', 'bar', 'qux'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -549,7 +605,8 @@ it('handles pop to top action', () => {
{ key: 'qux', name: 'qux' },
],
},
StackActions.popToTop()
StackActions.popToTop(),
options
)
).toEqual({
stale: false,
@@ -563,6 +620,12 @@ it('handles pop to top action', () => {
it('handles push action', () => {
const router = StackRouter({});
const options = {
routeNames: ['baz', 'bar', 'qux'],
routeParamList: {
baz: { foo: 21 },
},
};
expect(
router.getStateForAction(
@@ -574,7 +637,8 @@ it('handles push action', () => {
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'bar', name: 'bar' }],
},
StackActions.push('baz')
StackActions.push('baz'),
options
)
).toEqual({
stale: false,
@@ -582,7 +646,10 @@ it('handles push action', () => {
key: 'root',
index: 3,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'bar', name: 'bar' }, { key: 'baz-test', name: 'baz' }],
routes: [
{ key: 'bar', name: 'bar' },
{ key: 'baz-test', name: 'baz', params: { foo: 21 } },
],
});
expect(
@@ -595,7 +662,33 @@ it('handles push action', () => {
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'bar', name: 'bar' }],
},
StackActions.push('unknown')
StackActions.push('baz', { bar: 29 }),
options
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 3,
routeNames: ['baz', 'bar', 'qux'],
routes: [
{ key: 'bar', name: 'bar' },
{ key: 'baz-test', name: 'baz', params: { foo: 21, bar: 29 } },
],
});
expect(
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 2,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'bar', name: 'bar' }],
},
StackActions.push('unknown'),
options
)
).toBe(null);
});
@@ -623,7 +716,10 @@ it('changes index on focus change', () => {
index: 1,
key: 'stack-test',
routeNames: ['bar', 'baz', 'qux'],
routes: [{ key: 'bar-0', name: 'bar' }, { key: 'baz-0', name: 'baz' }],
routes: [
{ key: 'bar-0', name: 'bar' },
{ key: 'baz-0', name: 'baz' },
],
stale: false,
type: 'stack',
});
@@ -632,7 +728,10 @@ it('changes index on focus change', () => {
index: 0,
key: 'stack-test',
routeNames: ['bar', 'baz', 'qux'],
routes: [{ key: 'bar-0', name: 'bar' }, { key: 'baz-0', name: 'baz' }],
routes: [
{ key: 'bar-0', name: 'bar' },
{ key: 'baz-0', name: 'baz' },
],
stale: false as const,
type: 'stack' as const,
};

View File

@@ -69,7 +69,10 @@ it('gets rehydrated state from partial state', () => {
expect(
router.getRehydratedState(
{
routes: [{ key: 'bar-0', name: 'bar' }, { key: 'qux-1', name: 'qux' }],
routes: [
{ key: 'bar-0', name: 'bar' },
{ key: 'qux-1', name: 'qux' },
],
},
options
)
@@ -249,6 +252,10 @@ it('gets state on route names change', () => {
it('handles navigate action', () => {
const router = TabRouter({});
const options = {
routeNames: ['bar', 'baz'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -259,9 +266,13 @@ it('handles navigate action', () => {
index: 1,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz-1', name: 'baz' }, { key: 'bar-1', name: 'bar' }],
routes: [
{ key: 'baz-1', name: 'baz' },
{ key: 'bar-1', name: 'bar' },
],
},
CommonActions.navigate({ key: 'bar-1', params: { answer: 42 } })
CommonActions.navigate({ key: 'bar-1', params: { answer: 42 } }),
options
)
).toEqual({
stale: false,
@@ -285,9 +296,13 @@ it('handles navigate action', () => {
index: 1,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.navigate('baz', { answer: 42 })
CommonActions.navigate('baz', { answer: 42 }),
options
)
).toEqual({
stale: false,
@@ -311,15 +326,23 @@ it('handles navigate action', () => {
index: 1,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.navigate('non-existent')
CommonActions.navigate('non-existent'),
options
)
).toBe(null);
});
it('handles jump to action', () => {
const router = TabRouter({});
const options = {
routeNames: ['bar', 'baz'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -330,9 +353,13 @@ it('handles jump to action', () => {
index: 0,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
TabActions.jumpTo('bar')
TabActions.jumpTo('bar'),
options
)
).toEqual({
stale: false,
@@ -341,12 +368,19 @@ it('handles jump to action', () => {
index: 1,
routeNames: ['baz', 'bar'],
routeKeyHistory: ['baz'],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
});
});
it('handles back action with backBehavior: history', () => {
const router = TabRouter({ backBehavior: 'history' });
const options = {
routeNames: ['bar', 'baz'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -357,9 +391,13 @@ it('handles back action with backBehavior: history', () => {
index: 0,
routeNames: ['baz', 'bar'],
routeKeyHistory: ['bar'],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.goBack()
CommonActions.goBack(),
options
)
).toEqual({
stale: false,
@@ -368,7 +406,10 @@ it('handles back action with backBehavior: history', () => {
index: 1,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
});
expect(
@@ -380,15 +421,23 @@ it('handles back action with backBehavior: history', () => {
index: 0,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.goBack()
CommonActions.goBack(),
options
)
).toBe(null);
});
it('handles back action with backBehavior: order', () => {
const router = TabRouter({ backBehavior: 'order' });
const options = {
routeNames: ['bar', 'baz'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -399,9 +448,13 @@ it('handles back action with backBehavior: order', () => {
index: 1,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.goBack()
CommonActions.goBack(),
options
)
).toEqual({
stale: false,
@@ -410,7 +463,10 @@ it('handles back action with backBehavior: order', () => {
index: 0,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
});
expect(
@@ -422,9 +478,13 @@ it('handles back action with backBehavior: order', () => {
index: 0,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.goBack()
CommonActions.goBack(),
options
)
).toBe(null);
});
@@ -435,6 +495,11 @@ it('handles back action with backBehavior: initialRoute', () => {
initialRouteName: 'bar',
});
const options = {
routeNames: ['bar', 'baz'],
routeParamList: {},
};
expect(
router.getStateForAction(
{
@@ -444,9 +509,13 @@ it('handles back action with backBehavior: initialRoute', () => {
index: 0,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.goBack()
CommonActions.goBack(),
options
)
).toEqual({
stale: false,
@@ -455,7 +524,10 @@ it('handles back action with backBehavior: initialRoute', () => {
index: 1,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
});
expect(
@@ -467,15 +539,23 @@ it('handles back action with backBehavior: initialRoute', () => {
index: 1,
routeNames: ['baz', 'bar'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.goBack()
CommonActions.goBack(),
options
)
).toBe(null);
});
it('handles back action with backBehavior: none', () => {
const router = TabRouter({ backBehavior: 'none' });
const options = {
routeNames: ['bar', 'baz'],
routeParamList: {},
};
expect(
router.getStateForAction(
@@ -484,17 +564,25 @@ it('handles back action with backBehavior: none', () => {
type: 'tab',
key: 'root',
index: 0,
routeNames: ['baz', 'bar'],
routeNames: ['bar', 'baz'],
routeKeyHistory: [],
routes: [{ key: 'baz', name: 'baz' }, { key: 'bar', name: 'bar' }],
routes: [
{ key: 'baz', name: 'baz' },
{ key: 'bar', name: 'bar' },
],
},
CommonActions.goBack()
CommonActions.goBack(),
options
)
).toEqual(null);
});
it('updates route key history on navigate and jump to', () => {
const router = TabRouter({ backBehavior: 'history' });
const options = {
routeNames: ['bar', 'baz', 'qux'],
routeParamList: {},
};
let state: TabNavigationState = {
index: 1,
@@ -514,35 +602,40 @@ it('updates route key history on navigate and jump to', () => {
state = router.getStateForAction(
state,
TabActions.jumpTo('qux')
TabActions.jumpTo('qux'),
options
) as TabNavigationState;
expect(state.routeKeyHistory).toEqual(['baz-0']);
state = router.getStateForAction(
state,
CommonActions.navigate('bar')
CommonActions.navigate('bar'),
options
) as TabNavigationState;
expect(state.routeKeyHistory).toEqual(['baz-0', 'qux-0']);
state = router.getStateForAction(
state,
TabActions.jumpTo('baz')
TabActions.jumpTo('baz'),
options
) as TabNavigationState;
expect(state.routeKeyHistory).toEqual(['qux-0', 'bar-0']);
state = router.getStateForAction(
state,
CommonActions.goBack()
CommonActions.goBack(),
options
) as TabNavigationState;
expect(state.routeKeyHistory).toEqual(['qux-0']);
state = router.getStateForAction(
state,
CommonActions.goBack()
CommonActions.goBack(),
options
) as TabNavigationState;
expect(state.routeKeyHistory).toEqual([]);

View File

@@ -6,7 +6,7 @@
"react-native",
"react-navigation"
],
"version": "5.0.0-alpha.11",
"version": "5.0.0-alpha.15",
"license": "MIT",
"repository": {
"type": "git",
@@ -34,7 +34,7 @@
"devDependencies": {
"@react-native-community/bob": "^0.7.0",
"del-cli": "^3.0.0",
"typescript": "^3.6.3"
"typescript": "^3.7.2"
},
"peerDependencies": {
"@react-navigation/core": "^5.0.0-alpha.0"

View File

@@ -115,7 +115,7 @@ export default function DrawerRouter(
return result;
},
getStateForAction(state, action) {
getStateForAction(state, action, options) {
switch (action.type) {
case 'OPEN_DRAWER':
if (state.isDrawerOpen) {
@@ -149,11 +149,22 @@ export default function DrawerRouter(
...state,
isDrawerOpen: false,
},
action
action,
options
);
case 'GO_BACK':
if (state.isDrawerOpen) {
return {
...state,
isDrawerOpen: false,
};
}
return router.getStateForAction(state, action, options);
default:
return router.getStateForAction(state, action);
return router.getStateForAction(state, action, options);
}
},

View File

@@ -56,7 +56,8 @@ export default function StackRouter(options: StackRouterOptions) {
getInitialState({ routeNames, routeParamList }) {
const initialRouteName =
options.initialRouteName !== undefined
options.initialRouteName !== undefined &&
routeNames.includes(options.initialRouteName)
? options.initialRouteName
: routeNames[0];
@@ -164,7 +165,9 @@ export default function StackRouter(options: StackRouterOptions) {
};
},
getStateForAction(state, action) {
getStateForAction(state, action, options) {
const { routeParamList } = options;
switch (action.type) {
case 'PUSH':
if (state.routeNames.includes(action.payload.name)) {
@@ -179,7 +182,13 @@ export default function StackRouter(options: StackRouterOptions) {
? `${action.payload.name}-${shortid()}`
: action.payload.key,
name: action.payload.name,
params: action.payload.params,
params:
routeParamList[action.payload.name] !== undefined
? {
...routeParamList[action.payload.name],
...action.payload.params,
}
: action.payload.params,
},
],
};
@@ -210,10 +219,14 @@ export default function StackRouter(options: StackRouterOptions) {
}
case 'POP_TO_TOP':
return router.getStateForAction(state, {
type: 'POP',
payload: { count: state.routes.length - 1 },
});
return router.getStateForAction(
state,
{
type: 'POP',
payload: { count: state.routes.length - 1 },
},
options
);
case 'NAVIGATE':
if (
@@ -252,14 +265,18 @@ export default function StackRouter(options: StackRouterOptions) {
}
if (index === -1 && action.payload.name !== undefined) {
return router.getStateForAction(state, {
type: 'PUSH',
payload: {
key: action.payload.key,
name: action.payload.name,
params: action.payload.params,
return router.getStateForAction(
state,
{
type: 'PUSH',
payload: {
key: action.payload.key,
name: action.payload.name,
params: action.payload.params,
},
},
});
options
);
}
return {
@@ -284,12 +301,16 @@ export default function StackRouter(options: StackRouterOptions) {
case 'GO_BACK':
if (state.index > 0) {
return router.getStateForAction(state, {
type: 'POP',
payload: { count: 1 },
target: action.target,
source: action.source,
});
return router.getStateForAction(
state,
{
type: 'POP',
payload: { count: 1 },
target: action.target,
source: action.source,
},
options
);
}
return null;

View File

@@ -62,9 +62,9 @@ export default function TabRouter({
getInitialState({ routeNames, routeParamList }) {
const index =
initialRouteName === undefined
? 0
: routeNames.indexOf(initialRouteName);
initialRouteName !== undefined && routeNames.includes(initialRouteName)
? routeNames.indexOf(initialRouteName)
: 0;
return {
stale: false,

Some files were not shown because too many files have changed in this diff Show More