Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea5d14a720 | ||
|
|
313d0726a8 | ||
|
|
b52f153747 | ||
|
|
44621005ff | ||
|
|
bf58364c3d | ||
|
|
b55053cde6 | ||
|
|
9abb2644a9 | ||
|
|
6a946d6ab7 | ||
|
|
395abe5200 | ||
|
|
ba62509ff4 | ||
|
|
45391db7d9 | ||
|
|
7f86362e86 | ||
|
|
99605737e9 | ||
|
|
842f5eb7b2 | ||
|
|
183ea82416 | ||
|
|
108a6504a7 | ||
|
|
f92d671746 | ||
|
|
e0c4a8f7d3 | ||
|
|
bc881c8aa1 | ||
|
|
118c19dcce | ||
|
|
01b43974e6 | ||
|
|
2f90899620 | ||
|
|
6cc86f66e1 | ||
|
|
4be99b6645 | ||
|
|
80016b7218 | ||
|
|
f555a9ec9a | ||
|
|
05cbd85d5c | ||
|
|
51965eac38 | ||
|
|
a3956bf3ce | ||
|
|
ce24c66b5a | ||
|
|
5467f0e22d | ||
|
|
1e7d8d55c3 | ||
|
|
1d2ce862c2 | ||
|
|
d778479e4a | ||
|
|
352dae50e1 | ||
|
|
61385cae59 | ||
|
|
aa3c13891e | ||
|
|
9696d7220d | ||
|
|
2b83b44816 | ||
|
|
ec749023ed | ||
|
|
adc9389eb3 | ||
|
|
54d143fee2 | ||
|
|
d50e74d0c7 | ||
|
|
22926c5230 | ||
|
|
f6c47a6c66 | ||
|
|
046a9f8930 | ||
|
|
72f17538c2 | ||
|
|
550001b053 |
22
.eslintrc
@@ -7,18 +7,18 @@
|
||||
"prettier/react"
|
||||
],
|
||||
"parser": "babel-eslint",
|
||||
"plugins": [
|
||||
"react",
|
||||
"prettier"
|
||||
],
|
||||
"plugins": ["react", "prettier"],
|
||||
"env": {
|
||||
"jasmine": true
|
||||
},
|
||||
"rules": {
|
||||
"prettier/prettier": ["error", {
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": true
|
||||
}],
|
||||
"prettier/prettier": [
|
||||
"error",
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": true
|
||||
}
|
||||
],
|
||||
|
||||
"no-underscore-dangle": "off",
|
||||
"no-use-before-define": "off",
|
||||
@@ -27,17 +27,15 @@
|
||||
"no-plusplus": "off",
|
||||
"no-class-assign": "off",
|
||||
"no-duplicate-imports": "off",
|
||||
|
||||
"import/extensions": "off",
|
||||
"import/no-extraneous-dependencies": "off",
|
||||
"import/no-unresolved": "off",
|
||||
|
||||
"react/jsx-filename-extension": [
|
||||
"off", { "extensions": [".js", ".jsx"] }
|
||||
],
|
||||
"react/jsx-filename-extension": ["off", { "extensions": [".js", ".jsx"] }],
|
||||
|
||||
"react/sort-comp": "off",
|
||||
"react/prefer-stateless-function": "off",
|
||||
"react/no-deprecated": "off",
|
||||
|
||||
"react/forbid-prop-types": "warn",
|
||||
"react/prop-types": "off",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# React Navigation
|
||||
|
||||
[](https://badge.fury.io/js/react-navigation) [](https://codecov.io/gh/react-community/react-navigation) [](https://reactnavigation.org/docs/contributing.html)
|
||||
[](https://badge.fury.io/js/react-navigation) [](https://codecov.io/gh/react-navigation/react-navigation) [](https://circleci.com/gh/react-navigation/react-navigation/tree/master) [](https://reactnavigation.org/docs/contributing.html)
|
||||
|
||||
React Navigation is born from the React Native community's need for an extensible yet easy-to-use navigation solution based on Javascript.
|
||||
|
||||
@@ -55,4 +55,4 @@ This library has adopted a Code of Conduct that we expect project participants t
|
||||
|
||||
## License
|
||||
|
||||
React-navigation is licensed under the [BSD 2-clause "Simplified" License](https://github.com/react-community/react-navigation/blob/master/LICENSE).
|
||||
React Navigation is licensed under the [BSD 2-clause "Simplified" License](https://github.com/react-community/react-navigation/blob/master/LICENSE).
|
||||
|
||||
@@ -55,8 +55,6 @@ module.system=haste
|
||||
|
||||
emoji=true
|
||||
|
||||
experimental.strict_type_args=true
|
||||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
@@ -77,7 +75,5 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
unsafe.enable_getters_and_setters=true
|
||||
|
||||
[version]
|
||||
^0.61.0
|
||||
^0.67.0
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"splash": {
|
||||
"image": "./assets/icons/splash.png"
|
||||
},
|
||||
"sdkVersion": "26.0.0",
|
||||
"sdkVersion": "27.0.0",
|
||||
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||
"packagerOpts": {
|
||||
"assetExts": [
|
||||
|
||||
@@ -15,7 +15,11 @@ import {
|
||||
createStackNavigator,
|
||||
SafeAreaView,
|
||||
withNavigation,
|
||||
NavigationActions,
|
||||
StackActions,
|
||||
} from 'react-navigation';
|
||||
import invariant from 'invariant';
|
||||
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
import { HeaderButtons } from './commonComponents/HeaderButtons';
|
||||
@@ -48,25 +52,55 @@ const MyBackButtonWithNavigation = withNavigation(MyBackButton);
|
||||
class MyNavScreen extends React.Component<MyNavScreenProps> {
|
||||
render() {
|
||||
const { navigation, banner } = this.props;
|
||||
const { push, replace, popToTop, pop, dismiss } = navigation;
|
||||
invariant(
|
||||
push && replace && popToTop && pop && dismiss,
|
||||
'missing action creators for StackNavigator'
|
||||
);
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<SampleText>{banner}</SampleText>
|
||||
<Button
|
||||
onPress={() => navigation.push('Profile', { name: 'Jane' })}
|
||||
onPress={() => push('Profile', { name: 'Jane' })}
|
||||
title="Push a profile screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() =>
|
||||
navigation.dispatch(
|
||||
StackActions.reset({
|
||||
index: 0,
|
||||
actions: [
|
||||
NavigationActions.navigate({
|
||||
routeName: 'Photos',
|
||||
params: { name: 'Jane' },
|
||||
}),
|
||||
],
|
||||
})
|
||||
)
|
||||
}
|
||||
title="Reset photos"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('Photos', { name: 'Jane' })}
|
||||
title="Navigate to a photos screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.replace('Profile', { name: 'Lucy' })}
|
||||
onPress={() => replace('Profile', { name: 'Lucy' })}
|
||||
title="Replace with profile"
|
||||
/>
|
||||
<Button onPress={() => navigation.popToTop()} title="Pop to top" />
|
||||
<Button onPress={() => navigation.pop()} title="Pop" />
|
||||
<Button onPress={() => navigation.goBack()} title="Go back" />
|
||||
<Button onPress={() => navigation.dismiss()} title="Dismiss" />
|
||||
<Button onPress={() => popToTop()} title="Pop to top" />
|
||||
<Button onPress={() => pop()} title="Pop" />
|
||||
<Button
|
||||
onPress={() => {
|
||||
if (navigation.goBack()) {
|
||||
console.log('goBack handled');
|
||||
} else {
|
||||
console.log('goBack unhandled');
|
||||
}
|
||||
}}
|
||||
title="Go back"
|
||||
/>
|
||||
<Button onPress={() => dismiss()} title="Dismiss" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
||||
@@ -6,6 +6,8 @@ import type { NavigationScreenProp } from 'react-navigation';
|
||||
import * as React from 'react';
|
||||
import { ScrollView, StatusBar } from 'react-native';
|
||||
import { createStackNavigator, SafeAreaView } from 'react-navigation';
|
||||
import invariant from 'invariant';
|
||||
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
type NavScreenProps = {
|
||||
@@ -19,15 +21,14 @@ class HomeScreen extends React.Component<NavScreenProps> {
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
const { push } = navigation;
|
||||
invariant(push, 'missing `push` action creator for StackNavigator');
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ paddingTop: 30 }}>
|
||||
<Button onPress={() => push('Other')} title="Push another screen" />
|
||||
<Button
|
||||
onPress={() => navigation.push('Other')}
|
||||
title="Push another screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.push('ScreenWithNoHeader')}
|
||||
onPress={() => push('ScreenWithNoHeader')}
|
||||
title="Push screen with no header"
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go Home" />
|
||||
@@ -44,18 +45,20 @@ class OtherScreen extends React.Component<NavScreenProps> {
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
const { push, pop } = navigation;
|
||||
invariant(push && pop, 'missing action creators for StackNavigator');
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ paddingTop: 30 }}>
|
||||
<Button
|
||||
onPress={() => navigation.push('ScreenWithLongTitle')}
|
||||
onPress={() => push('ScreenWithLongTitle')}
|
||||
title="Push another screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.push('ScreenWithNoHeader')}
|
||||
onPress={() => push('ScreenWithNoHeader')}
|
||||
title="Push screen with no header"
|
||||
/>
|
||||
<Button onPress={() => navigation.pop()} title="Pop" />
|
||||
<Button onPress={() => pop()} title="Pop" />
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
@@ -70,10 +73,12 @@ class ScreenWithLongTitle extends React.Component<NavScreenProps> {
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
const { pop } = navigation;
|
||||
invariant(pop, 'missing `pop` action creator for StackNavigator');
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ paddingTop: 30 }}>
|
||||
<Button onPress={() => navigation.pop()} title="Pop" />
|
||||
<Button onPress={() => pop()} title="Pop" />
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
@@ -89,14 +94,13 @@ class ScreenWithNoHeader extends React.Component<NavScreenProps> {
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
const { push, pop } = navigation;
|
||||
invariant(push && pop, 'missing action creators for StackNavigator');
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ paddingTop: 30 }}>
|
||||
<Button
|
||||
onPress={() => navigation.push('Other')}
|
||||
title="Push another screen"
|
||||
/>
|
||||
<Button onPress={() => navigation.pop()} title="Pop" />
|
||||
<Button onPress={() => push('Other')} title="Push another screen" />
|
||||
<Button onPress={() => pop()} title="Pop" />
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { Header, createStackNavigator } from 'react-navigation';
|
||||
import invariant from 'invariant';
|
||||
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
import { HeaderButtons } from './commonComponents/HeaderButtons';
|
||||
@@ -31,11 +33,16 @@ type MyNavScreenProps = {
|
||||
class MyNavScreen extends React.Component<MyNavScreenProps> {
|
||||
render() {
|
||||
const { navigation, banner } = this.props;
|
||||
const { push, replace, popToTop, pop } = navigation;
|
||||
invariant(
|
||||
push && replace && popToTop && pop,
|
||||
'missing action creators for StackNavigator'
|
||||
);
|
||||
return (
|
||||
<ScrollView style={{ flex: 1 }} {...this.getHeaderInset()}>
|
||||
<SampleText>{banner}</SampleText>
|
||||
<Button
|
||||
onPress={() => navigation.push('Profile', { name: 'Jane' })}
|
||||
onPress={() => push('Profile', { name: 'Jane' })}
|
||||
title="Push a profile screen"
|
||||
/>
|
||||
<Button
|
||||
@@ -43,11 +50,11 @@ class MyNavScreen extends React.Component<MyNavScreenProps> {
|
||||
title="Navigate to a photos screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.replace('Profile', { name: 'Lucy' })}
|
||||
onPress={() => replace('Profile', { name: 'Lucy' })}
|
||||
title="Replace with profile"
|
||||
/>
|
||||
<Button onPress={() => navigation.popToTop()} title="Pop to top" />
|
||||
<Button onPress={() => navigation.pop()} title="Pop" />
|
||||
<Button onPress={() => popToTop()} title="Pop to top" />
|
||||
<Button onPress={() => pop()} title="Pop" />
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</ScrollView>
|
||||
|
||||
@@ -94,6 +94,19 @@ const TabNav = createBottomTabNavigator(
|
||||
}
|
||||
);
|
||||
|
||||
TabNav.navigationOptions = ({ navigation }) => {
|
||||
let { routeName } = navigation.state.routes[navigation.state.index];
|
||||
let title;
|
||||
if (routeName === 'SettingsTab') {
|
||||
title = 'Settings';
|
||||
} else if (routeName === 'MainTab') {
|
||||
title = 'Home';
|
||||
}
|
||||
return {
|
||||
title,
|
||||
};
|
||||
};
|
||||
|
||||
const StacksOverTabs = createStackNavigator({
|
||||
Root: {
|
||||
screen: TabNav,
|
||||
@@ -107,9 +120,9 @@ const StacksOverTabs = createStackNavigator({
|
||||
Profile: {
|
||||
screen: MyProfileScreen,
|
||||
path: '/people/:name',
|
||||
navigationOptions: ({ navigation }) => {
|
||||
title: `${navigation.state.params.name}'s Profile!`;
|
||||
},
|
||||
navigationOptions: ({ navigation }) => ({
|
||||
title: `${navigation.state.params.name}'s Profile!`,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
"test": "flow"
|
||||
},
|
||||
"dependencies": {
|
||||
"expo": "^26.0.0",
|
||||
"react": "16.3.0-alpha.1",
|
||||
"react-native": "^0.54.0",
|
||||
"expo": "^27.0.0",
|
||||
"invariant": "^2.2.4",
|
||||
"react": "16.3.1",
|
||||
"react-native": "^0.55.0",
|
||||
"react-native-iphone-x-helper": "^1.0.2",
|
||||
"react-navigation": "link:../..",
|
||||
"react-navigation-header-buttons": "^0.0.4",
|
||||
@@ -22,7 +23,7 @@
|
||||
"devDependencies": {
|
||||
"babel-jest": "^22.4.1",
|
||||
"babel-plugin-transform-remove-console": "^6.9.0",
|
||||
"flow-bin": "^0.61.0",
|
||||
"flow-bin": "^0.67.0",
|
||||
"jest": "^22.1.3",
|
||||
"jest-expo": "^26.0.0",
|
||||
"react-native-scripts": "^1.5.0",
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { StackNavigator } from 'react-navigation';
|
||||
import { createStackNavigator } from 'react-navigation';
|
||||
import { initializeListeners } from 'react-navigation-redux-helpers';
|
||||
|
||||
import LoginScreen from '../components/LoginScreen';
|
||||
import MainScreen from '../components/MainScreen';
|
||||
import ProfileScreen from '../components/ProfileScreen';
|
||||
import { addListener } from '../utils/redux';
|
||||
import { navigationPropConstructor } from '../utils/redux';
|
||||
|
||||
export const AppNavigator = StackNavigator({
|
||||
export const AppNavigator = createStackNavigator({
|
||||
Login: { screen: LoginScreen },
|
||||
Main: { screen: MainScreen },
|
||||
Profile: { screen: ProfileScreen },
|
||||
@@ -20,17 +21,14 @@ class AppWithNavigationState extends React.Component {
|
||||
nav: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
initializeListeners('root', this.props.nav);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { dispatch, nav } = this.props;
|
||||
return (
|
||||
<AppNavigator
|
||||
navigation={{
|
||||
dispatch,
|
||||
state: nav,
|
||||
addListener,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const navigation = navigationPropConstructor(dispatch, nav);
|
||||
return <AppNavigator navigation={navigation} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import {
|
||||
createReactNavigationReduxMiddleware,
|
||||
createReduxBoundAddListener,
|
||||
createNavigationPropConstructor,
|
||||
} from 'react-navigation-redux-helpers';
|
||||
|
||||
const middleware = createReactNavigationReduxMiddleware(
|
||||
"root",
|
||||
state => state.nav,
|
||||
'root',
|
||||
state => state.nav
|
||||
);
|
||||
const addListener = createReduxBoundAddListener("root");
|
||||
const navigationPropConstructor = createNavigationPropConstructor('root');
|
||||
|
||||
export {
|
||||
middleware,
|
||||
addListener,
|
||||
};
|
||||
export { middleware, navigationPropConstructor };
|
||||
|
||||
297
flow/react-navigation.js
vendored
@@ -69,6 +69,14 @@ declare module 'react-navigation' {
|
||||
[key: string]: mixed,
|
||||
};
|
||||
|
||||
declare export type NavigationBackAction = {|
|
||||
type: 'Navigation/BACK',
|
||||
key?: ?string,
|
||||
|};
|
||||
declare export type NavigationInitAction = {|
|
||||
type: 'Navigation/INIT',
|
||||
params?: NavigationParams,
|
||||
|};
|
||||
declare export type NavigationNavigateAction = {|
|
||||
type: 'Navigation/NAVIGATE',
|
||||
routeName: string,
|
||||
@@ -79,12 +87,6 @@ declare module 'react-navigation' {
|
||||
|
||||
key?: string,
|
||||
|};
|
||||
|
||||
declare export type NavigationBackAction = {|
|
||||
type: 'Navigation/BACK',
|
||||
key?: ?string,
|
||||
|};
|
||||
|
||||
declare export type NavigationSetParamsAction = {|
|
||||
type: 'Navigation/SET_PARAMS',
|
||||
|
||||
@@ -95,30 +97,6 @@ declare module 'react-navigation' {
|
||||
params: NavigationParams,
|
||||
|};
|
||||
|
||||
declare export type NavigationInitAction = {|
|
||||
type: 'Navigation/INIT',
|
||||
params?: NavigationParams,
|
||||
|};
|
||||
|
||||
declare export type NavigationResetAction = {|
|
||||
type: 'Navigation/RESET',
|
||||
index: number,
|
||||
key?: ?string,
|
||||
actions: Array<NavigationNavigateAction>,
|
||||
|};
|
||||
|
||||
declare export type NavigationUriAction = {|
|
||||
type: 'Navigation/URI',
|
||||
uri: string,
|
||||
|};
|
||||
|
||||
declare export type NavigationReplaceAction = {|
|
||||
+type: 'Navigation/REPLACE',
|
||||
+key: string,
|
||||
+routeName: string,
|
||||
+params?: NavigationParams,
|
||||
+action?: NavigationNavigateAction,
|
||||
|};
|
||||
declare export type NavigationPopAction = {|
|
||||
+type: 'Navigation/POP',
|
||||
+n?: number,
|
||||
@@ -135,17 +113,51 @@ declare module 'react-navigation' {
|
||||
+action?: NavigationNavigateAction,
|
||||
+key?: string,
|
||||
|};
|
||||
declare export type NavigationResetAction = {|
|
||||
type: 'Navigation/RESET',
|
||||
index: number,
|
||||
key?: ?string,
|
||||
actions: Array<NavigationNavigateAction>,
|
||||
|};
|
||||
declare export type NavigationReplaceAction = {|
|
||||
+type: 'Navigation/REPLACE',
|
||||
+key: string,
|
||||
+routeName: string,
|
||||
+params?: NavigationParams,
|
||||
+action?: NavigationNavigateAction,
|
||||
|};
|
||||
declare export type NavigationCompleteTransitionAction = {|
|
||||
+type: 'Navigation/COMPLETE_TRANSITION',
|
||||
+key?: string,
|
||||
|};
|
||||
|
||||
declare export type NavigationOpenDrawerAction = {|
|
||||
+type: 'Navigation/OPEN_DRAWER',
|
||||
+key?: string,
|
||||
|};
|
||||
declare export type NavigationCloseDrawerAction = {|
|
||||
+type: 'Navigation/CLOSE_DRAWER',
|
||||
+key?: string,
|
||||
|};
|
||||
declare export type NavigationToggleDrawerAction = {|
|
||||
+type: 'Navigation/TOGGLE_DRAWER',
|
||||
+key?: string,
|
||||
|};
|
||||
|
||||
declare export type NavigationAction =
|
||||
| NavigationBackAction
|
||||
| NavigationInitAction
|
||||
| NavigationNavigateAction
|
||||
| NavigationReplaceAction
|
||||
| NavigationSetParamsAction
|
||||
| NavigationPopAction
|
||||
| NavigationPopToTopAction
|
||||
| NavigationPushAction
|
||||
| NavigationBackAction
|
||||
| NavigationSetParamsAction
|
||||
| NavigationResetAction;
|
||||
| NavigationResetAction
|
||||
| NavigationReplaceAction
|
||||
| NavigationCompleteTransitionAction
|
||||
| NavigationOpenDrawerAction
|
||||
| NavigationCloseDrawerAction
|
||||
| NavigationToggleDrawerAction;
|
||||
|
||||
/**
|
||||
* NavigationState is a tree of routes for a single navigator, where each
|
||||
@@ -269,24 +281,33 @@ declare module 'react-navigation' {
|
||||
|
||||
declare export type NavigationComponent =
|
||||
| NavigationScreenComponent<NavigationRoute, *, *>
|
||||
| NavigationContainer<*, *, *>
|
||||
| any;
|
||||
| NavigationContainer<*, *, *>;
|
||||
|
||||
declare interface withOptionalNavigationOptions<Options> {
|
||||
navigationOptions?: NavigationScreenConfig<Options>,
|
||||
}
|
||||
|
||||
declare export type NavigationScreenComponent<
|
||||
Route: NavigationRoute,
|
||||
Options: {},
|
||||
Props: {}
|
||||
> = React$ComponentType<NavigationNavigatorProps<Options, Route> & Props> &
|
||||
({} | { navigationOptions: NavigationScreenConfig<Options> });
|
||||
> = React$ComponentType<{
|
||||
...Props,
|
||||
...NavigationNavigatorProps<Options, Route>,
|
||||
}> & withOptionalNavigationOptions<Options>;
|
||||
|
||||
declare interface withRouter<State, Options> {
|
||||
router: NavigationRouter<State, Options>,
|
||||
}
|
||||
|
||||
declare export type NavigationNavigator<
|
||||
State: NavigationState,
|
||||
Options: {},
|
||||
Props: {}
|
||||
> = React$ComponentType<NavigationNavigatorProps<Options, State> & Props> & {
|
||||
router: NavigationRouter<State, Options>,
|
||||
navigationOptions?: ?NavigationScreenConfig<Options>,
|
||||
};
|
||||
> = React$ComponentType<{
|
||||
...Props,
|
||||
...NavigationNavigatorProps<Options, State>,
|
||||
}> & withRouter<State, Options> & withOptionalNavigationOptions<Options>;
|
||||
|
||||
declare export type NavigationRouteConfig =
|
||||
| NavigationComponent
|
||||
@@ -426,10 +447,9 @@ declare module 'react-navigation' {
|
||||
| ((options: { tintColor: ?string, focused: boolean }) => ?React$Node),
|
||||
tabBarVisible?: boolean,
|
||||
tabBarTestIDProps?: { testID?: string, accessibilityLabel?: string },
|
||||
tabBarOnPress?: (
|
||||
scene: TabScene,
|
||||
jumpToIndex: (index: number) => void
|
||||
) => void,
|
||||
tabBarOnPress?: ({
|
||||
navigation: NavigationScreenProp<NavigationRoute>,
|
||||
}) => void,
|
||||
|};
|
||||
|
||||
/**
|
||||
@@ -483,41 +503,37 @@ declare module 'react-navigation' {
|
||||
};
|
||||
|
||||
declare export type NavigationScreenProp<+S> = {
|
||||
...$ObjMap<
|
||||
_DefaultActionCreators,
|
||||
<Args>((...args: Args) => *) => (...args: Args) => boolean
|
||||
>,
|
||||
+state: S,
|
||||
dispatch: NavigationDispatch,
|
||||
goBack: (routeKey?: ?string) => boolean,
|
||||
dismiss: () => boolean,
|
||||
navigate: (
|
||||
routeName:
|
||||
| string
|
||||
| {
|
||||
routeName: string,
|
||||
params?: NavigationParams,
|
||||
action?: NavigationNavigateAction,
|
||||
key?: string,
|
||||
},
|
||||
params?: NavigationParams,
|
||||
action?: NavigationNavigateAction
|
||||
) => boolean,
|
||||
setParams: (newParams: NavigationParams) => boolean,
|
||||
getParam: (paramName: string, fallback?: any) => any,
|
||||
addListener: (
|
||||
eventName: string,
|
||||
callback: NavigationEventCallback
|
||||
) => NavigationEventSubscription,
|
||||
push: (
|
||||
routeName: string,
|
||||
params?: NavigationParams,
|
||||
action?: NavigationNavigateAction
|
||||
) => boolean,
|
||||
replace: (
|
||||
routeName: string,
|
||||
params?: NavigationParams,
|
||||
action?: NavigationNavigateAction
|
||||
) => boolean,
|
||||
pop: (n?: number, params?: { immediate?: boolean }) => boolean,
|
||||
popToTop: (params?: { immediate?: boolean }) => boolean,
|
||||
getParam: (paramName: string, fallback?: any) => any,
|
||||
isFocused: () => boolean,
|
||||
// StackRouter action creators
|
||||
pop?: (n?: number, params?: { immediate?: boolean }) => boolean,
|
||||
popToTop?: (params?: { immediate?: boolean }) => boolean,
|
||||
push?: (
|
||||
routeName: string,
|
||||
params?: NavigationParams,
|
||||
action?: NavigationNavigateAction
|
||||
) => boolean,
|
||||
replace?: (
|
||||
routeName: string,
|
||||
params?: NavigationParams,
|
||||
action?: NavigationNavigateAction
|
||||
) => boolean,
|
||||
reset?: (actions: NavigationAction[], index: number) => boolean,
|
||||
dismiss?: () => boolean,
|
||||
// DrawerRouter action creators
|
||||
openDrawer?: () => boolean,
|
||||
closeDrawer?: () => boolean,
|
||||
toggleDrawer?: () => boolean,
|
||||
};
|
||||
|
||||
declare export type NavigationNavigatorProps<O: {}, S: {}> = $Shape<{
|
||||
@@ -534,10 +550,10 @@ declare module 'react-navigation' {
|
||||
State: NavigationState,
|
||||
Options: {},
|
||||
Props: {}
|
||||
> = React$ComponentType<NavigationContainerProps<State, Options> & Props> & {
|
||||
router: NavigationRouter<State, Options>,
|
||||
navigationOptions?: ?NavigationScreenConfig<Options>,
|
||||
};
|
||||
> = React$ComponentType<{
|
||||
...Props,
|
||||
...NavigationContainerProps<State, Options>,
|
||||
}> & withRouter<State, Options> & withOptionalNavigationOptions<Options>;
|
||||
|
||||
declare export type NavigationContainerProps<S: {}, O: {}> = $Shape<{
|
||||
uriPrefix?: string | RegExp,
|
||||
@@ -706,46 +722,95 @@ declare module 'react-navigation' {
|
||||
BACK: 'Navigation/BACK',
|
||||
INIT: 'Navigation/INIT',
|
||||
NAVIGATE: 'Navigation/NAVIGATE',
|
||||
RESET: 'Navigation/RESET',
|
||||
SET_PARAMS: 'Navigation/SET_PARAMS',
|
||||
URI: 'Navigation/URI',
|
||||
back: {
|
||||
(payload?: { key?: ?string }): NavigationBackAction,
|
||||
toString: () => string,
|
||||
},
|
||||
init: {
|
||||
(payload?: { params?: NavigationParams }): NavigationInitAction,
|
||||
toString: () => string,
|
||||
},
|
||||
navigate: {
|
||||
(payload: {
|
||||
routeName: string,
|
||||
params?: ?NavigationParams,
|
||||
action?: ?NavigationNavigateAction,
|
||||
}): NavigationNavigateAction,
|
||||
toString: () => string,
|
||||
},
|
||||
reset: {
|
||||
(payload: {
|
||||
index: number,
|
||||
key?: ?string,
|
||||
actions: Array<NavigationNavigateAction>,
|
||||
}): NavigationResetAction,
|
||||
toString: () => string,
|
||||
},
|
||||
setParams: {
|
||||
(payload: {
|
||||
key: string,
|
||||
params: NavigationParams,
|
||||
}): NavigationSetParamsAction,
|
||||
toString: () => string,
|
||||
},
|
||||
uri: {
|
||||
(payload: { uri: string }): NavigationUriAction,
|
||||
toString: () => string,
|
||||
},
|
||||
|
||||
back: (payload?: { key?: ?string }) => NavigationBackAction,
|
||||
init: (payload?: { params?: NavigationParams }) => NavigationInitAction,
|
||||
navigate: (payload: {
|
||||
routeName: string,
|
||||
params?: ?NavigationParams,
|
||||
action?: ?NavigationNavigateAction,
|
||||
key?: string,
|
||||
}) => NavigationNavigateAction,
|
||||
setParams: (payload: {
|
||||
key: string,
|
||||
params: NavigationParams,
|
||||
}) => NavigationSetParamsAction,
|
||||
};
|
||||
|
||||
declare export var StackActions: {
|
||||
POP: 'Navigation/POP',
|
||||
POP_TO_TOP: 'Navigation/POP_TO_TOP',
|
||||
PUSH: 'Navigation/PUSH',
|
||||
RESET: 'Navigation/RESET',
|
||||
REPLACE: 'Navigation/REPLACE',
|
||||
COMPLETE_TRANSITION: 'Navigation/COMPLETE_TRANSITION',
|
||||
|
||||
pop: (payload: {
|
||||
n?: number,
|
||||
immediate?: boolean,
|
||||
}) => NavigationPopAction,
|
||||
popToTop: (payload: {
|
||||
immediate?: boolean,
|
||||
}) => NavigationPopToTopAction,
|
||||
push: (payload: {
|
||||
routeName: string,
|
||||
params?: NavigationParams,
|
||||
action?: NavigationNavigateAction,
|
||||
key?: string,
|
||||
}) => NavigationPushAction,
|
||||
reset: (payload: {
|
||||
index: number,
|
||||
key?: ?string,
|
||||
actions: Array<NavigationNavigateAction>,
|
||||
}) => NavigationResetAction,
|
||||
replace: (payload: {
|
||||
key: string,
|
||||
routeName: string,
|
||||
params?: NavigationParams,
|
||||
action?: NavigationNavigateAction,
|
||||
}) => NavigationReplaceAction,
|
||||
completeTransition: (payload: {
|
||||
key?: string,
|
||||
}) => NavigationCompleteTransitionAction,
|
||||
};
|
||||
|
||||
declare export var DrawerActions: {
|
||||
OPEN_DRAWER: 'Navigation/OPEN_DRAWER',
|
||||
CLOSE_DRAWER: 'Navigation/CLOSE_DRAWER',
|
||||
TOGGLE_DRAWER: 'Navigation/TOGGLE_DRAWER',
|
||||
|
||||
openDrawer: (payload: {
|
||||
key?: string,
|
||||
}) => NavigationOpenDrawerAction,
|
||||
closeDrawer: (payload: {
|
||||
key?: string,
|
||||
}) => NavigationCloseDrawerAction,
|
||||
toggleDrawer: (payload: {
|
||||
key?: string,
|
||||
}) => NavigationToggleDrawerAction,
|
||||
};
|
||||
|
||||
declare type _DefaultActionCreators = {|
|
||||
goBack: (routeKey?: ?string) => NavigationBackAction,
|
||||
navigate: (
|
||||
routeName:
|
||||
| string
|
||||
| {
|
||||
routeName: string,
|
||||
params?: NavigationParams,
|
||||
action?: NavigationNavigateAction,
|
||||
key?: string,
|
||||
},
|
||||
params?: NavigationParams,
|
||||
action?: NavigationNavigateAction
|
||||
) => NavigationNavigateAction,
|
||||
setParams: (newParams: NavigationParams) => NavigationSetParamsAction,
|
||||
|};
|
||||
declare export function getNavigationActionCreators(
|
||||
route: NavigationRoute | NavigationState
|
||||
): _DefaultActionCreators;
|
||||
|
||||
declare type _RouterProp<S: NavigationState, O: {}> = {
|
||||
router: NavigationRouter<S, O>,
|
||||
};
|
||||
@@ -766,7 +831,7 @@ declare module 'react-navigation' {
|
||||
view: NavigationView<O, S>,
|
||||
router: NavigationRouter<S, O>,
|
||||
navigatorConfig?: NavigatorConfig
|
||||
): any;
|
||||
): NavigationNavigator<S, O, *>;
|
||||
|
||||
declare export function StackNavigator(
|
||||
routeConfigMap: NavigationRouteConfigMap,
|
||||
|
||||
10
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-navigation",
|
||||
"version": "2.0.2",
|
||||
"version": "2.2.3",
|
||||
"description": "Routing and navigation for your React Native apps",
|
||||
"main": "src/react-navigation.js",
|
||||
"repository": {
|
||||
@@ -35,10 +35,10 @@
|
||||
"path-to-regexp": "^1.7.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-lifecycles-compat": "^3",
|
||||
"react-native-drawer-layout-polyfill": "^1.3.2",
|
||||
"react-native-safe-area-view": "^0.7.0",
|
||||
"react-navigation-deprecated-tab-navigator": "1.2.0",
|
||||
"react-navigation-tabs": "0.2.0"
|
||||
"react-native-safe-area-view": "^0.8.0",
|
||||
"react-navigation-deprecated-tab-navigator": "1.3.0",
|
||||
"react-navigation-drawer": "0.2.1",
|
||||
"react-navigation-tabs": "0.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.24.1",
|
||||
|
||||
@@ -4,6 +4,6 @@ set -eo pipefail
|
||||
|
||||
case $CIRCLE_NODE_INDEX in
|
||||
0) yarn test && yarn codecov ;;
|
||||
1) cd examples/NavigationPlayground && yarn && yarn test ;;
|
||||
#1) cd examples/NavigationPlayground && yarn && yarn test ;;
|
||||
#2) cd examples/ReduxExample && yarn && yarn test ;;
|
||||
esac
|
||||
|
||||
@@ -208,7 +208,7 @@ describe('NavigationContainer', () => {
|
||||
let spy = {};
|
||||
|
||||
beforeEach(() => {
|
||||
spy.console = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
spy.console = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -285,6 +285,8 @@ export default function createNavigationContainer(Component) {
|
||||
'Uncaught exception while starting app from persisted navigation state! Trying to render again with a fresh navigation state..'
|
||||
);
|
||||
this.dispatch(NavigationActions.init());
|
||||
} else {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
import DrawerNavigator from '../createDrawerNavigator';
|
||||
|
||||
class HomeScreen extends Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
title: `Welcome ${
|
||||
navigation.state.params ? navigation.state.params.user : 'anonymous'
|
||||
}`,
|
||||
gesturesEnabled: true,
|
||||
});
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const routeConfig = {
|
||||
Home: {
|
||||
screen: HomeScreen,
|
||||
},
|
||||
};
|
||||
|
||||
describe('DrawerNavigator', () => {
|
||||
it('renders successfully', () => {
|
||||
const MyDrawerNavigator = DrawerNavigator(routeConfig);
|
||||
const rendered = renderer.create(<MyDrawerNavigator />).toJSON();
|
||||
|
||||
expect(rendered).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,243 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DrawerNavigator renders successfully 1`] = `
|
||||
<View
|
||||
onMoveShouldSetResponder={[Function]}
|
||||
onMoveShouldSetResponderCapture={[Function]}
|
||||
onResponderEnd={[Function]}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderMove={[Function]}
|
||||
onResponderReject={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderStart={[Function]}
|
||||
onResponderTerminate={[Function]}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponderCapture={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "transparent",
|
||||
"flex": 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
"zIndex": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<View
|
||||
accessibilityComponentType={undefined}
|
||||
accessibilityLabel={undefined}
|
||||
accessibilityTraits={undefined}
|
||||
accessible={true}
|
||||
collapsable={undefined}
|
||||
hitSlop={undefined}
|
||||
nativeID={undefined}
|
||||
onLayout={undefined}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderMove={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderTerminate={[Function]}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
pointerEvents="none"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#000",
|
||||
"bottom": 0,
|
||||
"left": 0,
|
||||
"opacity": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
"zIndex": 1000,
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
/>
|
||||
<View
|
||||
accessibilityViewIsModal={false}
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "white",
|
||||
"bottom": 0,
|
||||
"left": 0,
|
||||
"position": "absolute",
|
||||
"right": null,
|
||||
"top": 0,
|
||||
"transform": Array [
|
||||
Object {
|
||||
"translateX": -320,
|
||||
},
|
||||
],
|
||||
"width": 320,
|
||||
"zIndex": 1001,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"flex": 1,
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<RCTScrollView
|
||||
DEPRECATED_sendUpdatedChildFrames={false}
|
||||
alwaysBounceHorizontal={undefined}
|
||||
alwaysBounceVertical={false}
|
||||
onContentSizeChange={null}
|
||||
onMomentumScrollBegin={[Function]}
|
||||
onMomentumScrollEnd={[Function]}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderReject={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderTerminate={undefined}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onScroll={[Function]}
|
||||
onScrollBeginDrag={[Function]}
|
||||
onScrollEndDrag={[Function]}
|
||||
onScrollShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponderCapture={[Function]}
|
||||
onTouchCancel={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchMove={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
scrollEventThrottle={undefined}
|
||||
sendMomentumEvents={false}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"flexDirection": "column",
|
||||
"flexGrow": 1,
|
||||
"flexShrink": 1,
|
||||
"overflow": "scroll",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<RCTScrollContentView
|
||||
collapsable={false}
|
||||
removeClippedSubviews={undefined}
|
||||
style={
|
||||
Array [
|
||||
undefined,
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
onLayout={[Function]}
|
||||
pointerEvents="box-none"
|
||||
style={
|
||||
Object {
|
||||
"paddingBottom": 0,
|
||||
"paddingLeft": 0,
|
||||
"paddingRight": 0,
|
||||
"paddingTop": 20,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"paddingVertical": 4,
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
accessibilityComponentType={undefined}
|
||||
accessibilityLabel={undefined}
|
||||
accessibilityTraits={undefined}
|
||||
accessible={true}
|
||||
collapsable={undefined}
|
||||
hasTVPreferredFocus={undefined}
|
||||
hitSlop={undefined}
|
||||
isTVSelectable={true}
|
||||
nativeID={undefined}
|
||||
onLayout={undefined}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderMove={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderTerminate={[Function]}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"opacity": 1,
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
tvParallaxProperties={undefined}
|
||||
>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
onLayout={[Function]}
|
||||
pointerEvents="box-none"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "rgba(0, 0, 0, .04)",
|
||||
"paddingBottom": 0,
|
||||
"paddingLeft": 0,
|
||||
"paddingRight": 0,
|
||||
"paddingTop": 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"flexDirection": "row",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<Text
|
||||
accessible={true}
|
||||
allowFontScaling={true}
|
||||
ellipsizeMode="tail"
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"fontWeight": "bold",
|
||||
"margin": 16,
|
||||
},
|
||||
Object {
|
||||
"color": "#2196f3",
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
Welcome anonymous
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</RCTScrollContentView>
|
||||
</RCTScrollView>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
`;
|
||||
@@ -2,12 +2,7 @@
|
||||
|
||||
exports[`TabNavigator renders successfully 1`] = `
|
||||
<View
|
||||
loaded={
|
||||
Array [
|
||||
0,
|
||||
]
|
||||
}
|
||||
onLayout={[Function]}
|
||||
collapsable={false}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
@@ -21,56 +16,65 @@ exports[`TabNavigator renders successfully 1`] = `
|
||||
}
|
||||
>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
onMoveShouldSetResponder={[Function]}
|
||||
onMoveShouldSetResponderCapture={[Function]}
|
||||
onResponderEnd={[Function]}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderMove={[Function]}
|
||||
onResponderReject={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderStart={[Function]}
|
||||
onResponderTerminate={[Function]}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponderCapture={[Function]}
|
||||
onLayout={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "stretch",
|
||||
"flex": 1,
|
||||
"flexDirection": "row",
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
onMoveShouldSetResponder={[Function]}
|
||||
onMoveShouldSetResponderCapture={[Function]}
|
||||
onResponderEnd={[Function]}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderMove={[Function]}
|
||||
onResponderReject={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderStart={[Function]}
|
||||
onResponderTerminate={[Function]}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponderCapture={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
"left": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
"alignItems": "stretch",
|
||||
"flex": 1,
|
||||
"flexDirection": "row",
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
>
|
||||
<View
|
||||
collapsable={false}
|
||||
removeClippedSubviews={false}
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
"overflow": "hidden",
|
||||
"bottom": 0,
|
||||
"left": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
>
|
||||
<View
|
||||
collapsable={false}
|
||||
removeClippedSubviews={false}
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
"overflow": "hidden",
|
||||
}
|
||||
}
|
||||
/>
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Dimensions, Platform, ScrollView } from 'react-native';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
|
||||
import createNavigator from './createNavigator';
|
||||
import createNavigationContainer from '../createNavigationContainer';
|
||||
import DrawerRouter from '../routers/DrawerRouter';
|
||||
import DrawerScreen from '../views/Drawer/DrawerScreen';
|
||||
import DrawerView from '../views/Drawer/DrawerView';
|
||||
import DrawerItems from '../views/Drawer/DrawerNavigatorItems';
|
||||
|
||||
// A stack navigators props are the intersection between
|
||||
// the base navigator props (navgiation, screenProps, etc)
|
||||
// and the view's props
|
||||
|
||||
const defaultContentComponent = props => (
|
||||
<ScrollView alwaysBounceVertical={false}>
|
||||
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
|
||||
<DrawerItems {...props} />
|
||||
</SafeAreaView>
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
const DefaultDrawerConfig = {
|
||||
drawerWidth: () => {
|
||||
/*
|
||||
* Default drawer width is screen width - header height
|
||||
* with a max width of 280 on mobile and 320 on tablet
|
||||
* https://material.io/guidelines/patterns/navigation-drawer.html
|
||||
*/
|
||||
const { height, width } = Dimensions.get('window');
|
||||
const smallerAxisSize = Math.min(height, width);
|
||||
const isLandscape = width > height;
|
||||
const isTablet = smallerAxisSize >= 600;
|
||||
const appBarHeight = Platform.OS === 'ios' ? (isLandscape ? 32 : 44) : 56;
|
||||
const maxWidth = isTablet ? 320 : 280;
|
||||
|
||||
return Math.min(smallerAxisSize - appBarHeight, maxWidth);
|
||||
},
|
||||
contentComponent: defaultContentComponent,
|
||||
drawerPosition: 'left',
|
||||
drawerBackgroundColor: 'white',
|
||||
useNativeAnimations: true,
|
||||
};
|
||||
|
||||
const DrawerNavigator = (routeConfigs, config = {}) => {
|
||||
const mergedConfig = { ...DefaultDrawerConfig, ...config };
|
||||
|
||||
const {
|
||||
order,
|
||||
paths,
|
||||
initialRouteName,
|
||||
backBehavior,
|
||||
...drawerConfig
|
||||
} = mergedConfig;
|
||||
|
||||
const routerConfig = {
|
||||
order,
|
||||
paths,
|
||||
initialRouteName,
|
||||
backBehavior,
|
||||
};
|
||||
|
||||
const drawerRouter = DrawerRouter(routeConfigs, routerConfig);
|
||||
|
||||
const navigator = createNavigator(DrawerView, drawerRouter, drawerConfig);
|
||||
|
||||
return createNavigationContainer(navigator);
|
||||
};
|
||||
|
||||
export default DrawerNavigator;
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { polyfill } from 'react-lifecycles-compat';
|
||||
|
||||
import getChildEventSubscriber from '../getChildEventSubscriber';
|
||||
|
||||
@@ -7,21 +8,90 @@ function createNavigator(NavigatorView, router, navigationConfig) {
|
||||
static router = router;
|
||||
static navigationOptions = null;
|
||||
|
||||
childEventSubscribers = {};
|
||||
state = {
|
||||
descriptors: {},
|
||||
childEventSubscribers: {},
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
const { navigation, screenProps } = nextProps;
|
||||
const { dispatch, state, addListener } = navigation;
|
||||
const { routes } = state;
|
||||
|
||||
const descriptors = { ...prevState.descriptors };
|
||||
const childEventSubscribers = { ...prevState.childEventSubscribers };
|
||||
routes.forEach(route => {
|
||||
if (!descriptors[route.key] || descriptors[route.key].state !== route) {
|
||||
const getComponent = () =>
|
||||
router.getComponentForRouteName(route.routeName);
|
||||
|
||||
if (!childEventSubscribers[route.key]) {
|
||||
childEventSubscribers[route.key] = getChildEventSubscriber(
|
||||
addListener,
|
||||
route.key
|
||||
);
|
||||
}
|
||||
|
||||
const actionCreators = {
|
||||
...navigation.actions,
|
||||
...router.getActionCreators(route, state.key),
|
||||
};
|
||||
const actionHelpers = {};
|
||||
Object.keys(actionCreators).forEach(actionName => {
|
||||
actionHelpers[actionName] = (...args) => {
|
||||
const actionCreator = actionCreators[actionName];
|
||||
const action = actionCreator(...args);
|
||||
return dispatch(action);
|
||||
};
|
||||
});
|
||||
const childNavigation = {
|
||||
...actionHelpers,
|
||||
actions: actionCreators,
|
||||
dispatch,
|
||||
state: route,
|
||||
addListener: childEventSubscribers[route.key].addListener,
|
||||
getParam: (paramName, defaultValue) => {
|
||||
const params = route.params;
|
||||
|
||||
if (params && paramName in params) {
|
||||
return params[paramName];
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
},
|
||||
};
|
||||
|
||||
const options = router.getScreenOptions(childNavigation, screenProps);
|
||||
descriptors[route.key] = {
|
||||
key: route.key,
|
||||
getComponent,
|
||||
options,
|
||||
state: route,
|
||||
navigation: childNavigation,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
descriptors,
|
||||
childEventSubscribers,
|
||||
};
|
||||
}
|
||||
|
||||
// Cleanup subscriptions for routes that no longer exist
|
||||
componentDidUpdate() {
|
||||
const activeKeys = this.props.navigation.state.routes.map(r => r.key);
|
||||
Object.keys(this.childEventSubscribers).forEach(key => {
|
||||
let childEventSubscribers = { ...this.state.childEventSubscribers };
|
||||
Object.keys(childEventSubscribers).forEach(key => {
|
||||
if (!activeKeys.includes(key)) {
|
||||
delete this.childEventSubscribers[key];
|
||||
delete childEventSubscribers[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Remove all subscription references
|
||||
componentWillUnmount() {
|
||||
this.childEventSubscribers = {};
|
||||
if (
|
||||
childEventSubscribers.length !== this.state.childEventSubscribers.length
|
||||
) {
|
||||
this.setState({ childEventSubscribers });
|
||||
}
|
||||
}
|
||||
|
||||
_isRouteFocused = route => {
|
||||
@@ -35,75 +105,33 @@ function createNavigator(NavigatorView, router, navigationConfig) {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation, screenProps } = this.props;
|
||||
const { dispatch, state, addListener } = navigation;
|
||||
const { routes } = state;
|
||||
|
||||
const descriptors = {};
|
||||
routes.forEach(route => {
|
||||
const getComponent = () =>
|
||||
router.getComponentForRouteName(route.routeName);
|
||||
|
||||
if (!this.childEventSubscribers[route.key]) {
|
||||
this.childEventSubscribers[route.key] = getChildEventSubscriber(
|
||||
addListener,
|
||||
route.key
|
||||
);
|
||||
}
|
||||
|
||||
const actionCreators = {
|
||||
...navigation.actions,
|
||||
...router.getActionCreators(route, state.key),
|
||||
};
|
||||
const actionHelpers = {};
|
||||
Object.keys(actionCreators).forEach(actionName => {
|
||||
actionHelpers[actionName] = (...args) => {
|
||||
const actionCreator = actionCreators[actionName];
|
||||
const action = actionCreator(...args);
|
||||
dispatch(action);
|
||||
};
|
||||
});
|
||||
const childNavigation = {
|
||||
...actionHelpers,
|
||||
actions: actionCreators,
|
||||
dispatch,
|
||||
state: route,
|
||||
isFocused: () => this._isRouteFocused(route),
|
||||
dangerouslyGetParent: this._dangerouslyGetParent,
|
||||
addListener: this.childEventSubscribers[route.key].addListener,
|
||||
getParam: (paramName, defaultValue) => {
|
||||
const params = route.params;
|
||||
|
||||
if (params && paramName in params) {
|
||||
return params[paramName];
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
},
|
||||
};
|
||||
|
||||
const options = router.getScreenOptions(childNavigation, screenProps);
|
||||
descriptors[route.key] = {
|
||||
key: route.key,
|
||||
getComponent,
|
||||
options,
|
||||
state: route,
|
||||
navigation: childNavigation,
|
||||
};
|
||||
// Mutation in render 😩
|
||||
// The problem:
|
||||
// - We don't want to re-render each screen every time the parent navigator changes
|
||||
// - But we need to be able to access the parent navigator from callbacks
|
||||
// - These functions should only be used within callbacks, but they are passed in props,
|
||||
// which is what makes this awkward. What's a good way to pass in stuff that we don't
|
||||
// want people to depend on in render?
|
||||
let descriptors = { ...this.state.descriptors };
|
||||
Object.values(descriptors).forEach(descriptor => {
|
||||
descriptor.navigation.isFocused = () =>
|
||||
this._isRouteFocused(descriptor.state);
|
||||
descriptor.navigation.dangerouslyGetParent = this._dangerouslyGetParent;
|
||||
});
|
||||
|
||||
return (
|
||||
<NavigatorView
|
||||
{...this.props}
|
||||
screenProps={screenProps}
|
||||
navigation={navigation}
|
||||
screenProps={this.props.screenProps}
|
||||
navigation={this.props.navigation}
|
||||
navigationConfig={navigationConfig}
|
||||
descriptors={descriptors}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
return Navigator;
|
||||
|
||||
return polyfill(Navigator);
|
||||
}
|
||||
|
||||
export default createNavigator;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
import createNavigationContainer from '../createNavigationContainer';
|
||||
import createKeyboardAwareNavigator from './createKeyboardAwareNavigator';
|
||||
import createNavigator from './createNavigator';
|
||||
@@ -13,6 +13,7 @@ function createStackNavigator(routeConfigMap, stackConfig = {}) {
|
||||
paths,
|
||||
navigationOptions,
|
||||
disableKeyboardHandling,
|
||||
getCustomActionCreators,
|
||||
} = stackConfig;
|
||||
|
||||
const stackRouterConfig = {
|
||||
@@ -21,6 +22,7 @@ function createStackNavigator(routeConfigMap, stackConfig = {}) {
|
||||
initialRouteParams,
|
||||
paths,
|
||||
navigationOptions,
|
||||
getCustomActionCreators,
|
||||
};
|
||||
|
||||
const router = StackRouter(routeConfigMap, stackRouterConfig);
|
||||
|
||||
19
src/react-navigation.js
vendored
@@ -32,13 +32,13 @@ module.exports = {
|
||||
return require('./navigators/createSwitchNavigator').default;
|
||||
},
|
||||
get createDrawerNavigator() {
|
||||
return require('./navigators/createDrawerNavigator').default;
|
||||
return require('react-navigation-drawer').createDrawerNavigator;
|
||||
},
|
||||
get DrawerNavigator() {
|
||||
console.warn(
|
||||
'The DrawerNavigator function name is deprecated, please use createDrawerNavigator instead'
|
||||
);
|
||||
return require('./navigators/createDrawerNavigator').default;
|
||||
return require('react-navigation-drawer').createDrawerNavigator;
|
||||
},
|
||||
get createTabNavigator() {
|
||||
console.warn(
|
||||
@@ -69,7 +69,10 @@ module.exports = {
|
||||
return require('./routers/StackActions').default;
|
||||
},
|
||||
get DrawerActions() {
|
||||
return require('./routers/DrawerActions').default;
|
||||
return require('react-navigation-drawer').DrawerActions;
|
||||
},
|
||||
get getNavigationActionCreators() {
|
||||
return require('./routers/getNavigationActionCreators').default;
|
||||
},
|
||||
|
||||
// Routers
|
||||
@@ -79,6 +82,9 @@ module.exports = {
|
||||
get TabRouter() {
|
||||
return require('./routers/TabRouter').default;
|
||||
},
|
||||
get DrawerRouter() {
|
||||
return require('react-navigation-drawer').DrawerRouter;
|
||||
},
|
||||
get SwitchRouter() {
|
||||
return require('./routers/SwitchRouter').default;
|
||||
},
|
||||
@@ -116,10 +122,13 @@ module.exports = {
|
||||
|
||||
// DrawerView
|
||||
get DrawerView() {
|
||||
return require('./views/Drawer/DrawerView').default;
|
||||
return require('react-navigation-drawer').DrawerView;
|
||||
},
|
||||
get DrawerItems() {
|
||||
return require('./views/Drawer/DrawerNavigatorItems').default;
|
||||
return require('react-navigation-drawer').DrawerNavigatorItems;
|
||||
},
|
||||
get DrawerSidebar() {
|
||||
return require('react-navigation-drawer').DrawerSidebar;
|
||||
},
|
||||
|
||||
// TabView
|
||||
|
||||
@@ -24,6 +24,9 @@ module.exports = {
|
||||
get DrawerActions() {
|
||||
return require('./routers/DrawerActions').default;
|
||||
},
|
||||
get getNavigationActionCreators() {
|
||||
return require('./routers/getNavigationActionCreators').default;
|
||||
},
|
||||
|
||||
// Routers
|
||||
get StackRouter() {
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
const OPEN_DRAWER = 'Navigation/OPEN_DRAWER';
|
||||
const CLOSE_DRAWER = 'Navigation/CLOSE_DRAWER';
|
||||
const TOGGLE_DRAWER = 'Navigation/TOGGLE_DRAWER';
|
||||
|
||||
const openDrawer = payload => ({
|
||||
type: OPEN_DRAWER,
|
||||
...payload,
|
||||
});
|
||||
|
||||
const closeDrawer = payload => ({
|
||||
type: CLOSE_DRAWER,
|
||||
...payload,
|
||||
});
|
||||
|
||||
const toggleDrawer = payload => ({
|
||||
type: TOGGLE_DRAWER,
|
||||
...payload,
|
||||
});
|
||||
|
||||
export default {
|
||||
OPEN_DRAWER,
|
||||
CLOSE_DRAWER,
|
||||
TOGGLE_DRAWER,
|
||||
|
||||
openDrawer,
|
||||
closeDrawer,
|
||||
toggleDrawer,
|
||||
};
|
||||
@@ -1,85 +0,0 @@
|
||||
import SwitchRouter from './SwitchRouter';
|
||||
import NavigationActions from '../NavigationActions';
|
||||
|
||||
import invariant from '../utils/invariant';
|
||||
import withDefaultValue from '../utils/withDefaultValue';
|
||||
|
||||
import DrawerActions from './DrawerActions';
|
||||
|
||||
export default (routeConfigs, config = {}) => {
|
||||
config = { ...config };
|
||||
config = withDefaultValue(config, 'resetOnBlur', false);
|
||||
config = withDefaultValue(config, 'backBehavior', 'initialRoute');
|
||||
|
||||
const switchRouter = SwitchRouter(routeConfigs, config);
|
||||
|
||||
return {
|
||||
...switchRouter,
|
||||
|
||||
getActionCreators(route, navStateKey) {
|
||||
return {
|
||||
openDrawer: () => DrawerActions.openDrawer({ key: navStateKey }),
|
||||
closeDrawer: () => DrawerActions.closeDrawer({ key: navStateKey }),
|
||||
toggleDrawer: () => DrawerActions.toggleDrawer({ key: navStateKey }),
|
||||
...switchRouter.getActionCreators(route, navStateKey),
|
||||
};
|
||||
},
|
||||
|
||||
getStateForAction(action, lastState) {
|
||||
const state = lastState || {
|
||||
...switchRouter.getStateForAction(action, undefined),
|
||||
isDrawerOpen: false,
|
||||
};
|
||||
|
||||
const isRouterTargeted = action.key == null || action.key === state.key;
|
||||
|
||||
if (isRouterTargeted) {
|
||||
// Only handle actions that are meant for this drawer, as specified by action.key.
|
||||
|
||||
if (action.type === DrawerActions.CLOSE_DRAWER && state.isDrawerOpen) {
|
||||
return {
|
||||
...state,
|
||||
isDrawerOpen: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === DrawerActions.OPEN_DRAWER && !state.isDrawerOpen) {
|
||||
return {
|
||||
...state,
|
||||
isDrawerOpen: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === DrawerActions.TOGGLE_DRAWER) {
|
||||
return {
|
||||
...state,
|
||||
isDrawerOpen: !state.isDrawerOpen,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back on switch router for screen switching logic, and handling of child routers
|
||||
const switchedState = switchRouter.getStateForAction(action, state);
|
||||
|
||||
if (switchedState === null) {
|
||||
// The switch router or a child router is attempting to swallow this action. We return null to allow this.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (switchedState !== state) {
|
||||
if (switchedState.index !== state.index) {
|
||||
// If the tabs have changed, make sure to close the drawer
|
||||
return {
|
||||
...switchedState,
|
||||
isDrawerOpen: false,
|
||||
};
|
||||
}
|
||||
// Return the state new state, as returned by the switch router.
|
||||
// The index hasn't changed, so this most likely means that a child router has returned a new state
|
||||
return switchedState;
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -267,11 +267,18 @@ export default (routeConfigs, stackConfig = {}) => {
|
||||
);
|
||||
|
||||
if (nextRouteState === null || nextRouteState !== childRoute) {
|
||||
return StateUtils.replaceAndPrune(
|
||||
const newState = StateUtils.replaceAndPrune(
|
||||
state,
|
||||
nextRouteState ? nextRouteState.key : childRoute.key,
|
||||
nextRouteState ? nextRouteState : childRoute
|
||||
);
|
||||
return {
|
||||
...newState,
|
||||
isTransitioning:
|
||||
state.index !== newState.index
|
||||
? action.immediate !== true
|
||||
: state.isTransitioning,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
/* eslint react/display-name:0 */
|
||||
|
||||
import React from 'react';
|
||||
import DrawerRouter from '../DrawerRouter';
|
||||
|
||||
import NavigationActions from '../../NavigationActions';
|
||||
import DrawerActions from '../../routers/DrawerActions';
|
||||
|
||||
const INIT_ACTION = { type: NavigationActions.INIT };
|
||||
|
||||
describe('DrawerRouter', () => {
|
||||
test('Handles basic tab logic', () => {
|
||||
const ScreenA = () => <div />;
|
||||
const ScreenB = () => <div />;
|
||||
const router = DrawerRouter({
|
||||
Foo: { screen: ScreenA },
|
||||
Bar: { screen: ScreenB },
|
||||
});
|
||||
const state = router.getStateForAction(INIT_ACTION);
|
||||
const expectedState = {
|
||||
index: 0,
|
||||
isTransitioning: false,
|
||||
routes: [
|
||||
{ key: 'Foo', routeName: 'Foo', params: undefined },
|
||||
{ key: 'Bar', routeName: 'Bar', params: undefined },
|
||||
],
|
||||
isDrawerOpen: false,
|
||||
};
|
||||
expect(state).toEqual(expectedState);
|
||||
const state2 = router.getStateForAction(
|
||||
{ type: NavigationActions.NAVIGATE, routeName: 'Bar' },
|
||||
state
|
||||
);
|
||||
const expectedState2 = {
|
||||
index: 1,
|
||||
isTransitioning: false,
|
||||
routes: [
|
||||
{ key: 'Foo', routeName: 'Foo', params: undefined },
|
||||
{ key: 'Bar', routeName: 'Bar', params: undefined },
|
||||
],
|
||||
isDrawerOpen: false,
|
||||
};
|
||||
expect(state2).toEqual(expectedState2);
|
||||
expect(router.getComponentForState(expectedState)).toEqual(ScreenA);
|
||||
expect(router.getComponentForState(expectedState2)).toEqual(ScreenB);
|
||||
});
|
||||
|
||||
test('Drawer opens closes and toggles', () => {
|
||||
const ScreenA = () => <div />;
|
||||
const ScreenB = () => <div />;
|
||||
const router = DrawerRouter({
|
||||
Foo: { screen: ScreenA },
|
||||
Bar: { screen: ScreenB },
|
||||
});
|
||||
const state = router.getStateForAction(INIT_ACTION);
|
||||
expect(state.isDrawerOpen).toEqual(false);
|
||||
const state2 = router.getStateForAction(
|
||||
{ type: DrawerActions.OPEN_DRAWER },
|
||||
state
|
||||
);
|
||||
expect(state2.isDrawerOpen).toEqual(true);
|
||||
const state3 = router.getStateForAction(
|
||||
{ type: DrawerActions.CLOSE_DRAWER },
|
||||
state2
|
||||
);
|
||||
expect(state3.isDrawerOpen).toEqual(false);
|
||||
const state4 = router.getStateForAction(
|
||||
{ type: DrawerActions.TOGGLE_DRAWER },
|
||||
state3
|
||||
);
|
||||
expect(state4.isDrawerOpen).toEqual(true);
|
||||
});
|
||||
|
||||
test('Drawer opens closes with key targeted', () => {
|
||||
const ScreenA = () => <div />;
|
||||
const ScreenB = () => <div />;
|
||||
const router = DrawerRouter({
|
||||
Foo: { screen: ScreenA },
|
||||
Bar: { screen: ScreenB },
|
||||
});
|
||||
const state = router.getStateForAction(INIT_ACTION);
|
||||
const state2 = router.getStateForAction(
|
||||
{ type: DrawerActions.OPEN_DRAWER, key: 'wrong' },
|
||||
state
|
||||
);
|
||||
expect(state2.isDrawerOpen).toEqual(false);
|
||||
const state3 = router.getStateForAction(
|
||||
{ type: DrawerActions.OPEN_DRAWER, key: state.key },
|
||||
state2
|
||||
);
|
||||
expect(state3.isDrawerOpen).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
test('Nested routers bubble up blocked actions', () => {
|
||||
const ScreenA = () => <div />;
|
||||
ScreenA.router = {
|
||||
getStateForAction(action, lastState) {
|
||||
if (action.type === 'CHILD_ACTION') return null;
|
||||
return lastState;
|
||||
},
|
||||
};
|
||||
const ScreenB = () => <div />;
|
||||
const router = DrawerRouter({
|
||||
Foo: { screen: ScreenA },
|
||||
Bar: { screen: ScreenB },
|
||||
});
|
||||
const state = router.getStateForAction(INIT_ACTION);
|
||||
|
||||
const state2 = router.getStateForAction({ type: 'CHILD_ACTION' }, state);
|
||||
expect(state2).toEqual(null);
|
||||
});
|
||||
|
||||
test('Drawer stays open when child routers return new state', () => {
|
||||
const ScreenA = () => <div />;
|
||||
ScreenA.router = {
|
||||
getStateForAction(action, lastState = { changed: false }) {
|
||||
if (action.type === 'CHILD_ACTION')
|
||||
return { ...lastState, changed: true };
|
||||
return lastState;
|
||||
},
|
||||
};
|
||||
const router = DrawerRouter({
|
||||
Foo: { screen: ScreenA },
|
||||
});
|
||||
|
||||
const state = router.getStateForAction(INIT_ACTION);
|
||||
expect(state.isDrawerOpen).toEqual(false);
|
||||
|
||||
const state2 = router.getStateForAction(
|
||||
{ type: DrawerActions.OPEN_DRAWER, key: state.key },
|
||||
state
|
||||
);
|
||||
expect(state2.isDrawerOpen).toEqual(true);
|
||||
|
||||
const state3 = router.getStateForAction({ type: 'CHILD_ACTION' }, state2);
|
||||
expect(state3.isDrawerOpen).toEqual(true);
|
||||
expect(state3.routes[0].changed).toEqual(true);
|
||||
});
|
||||
@@ -16,6 +16,7 @@ beforeEach(() => {
|
||||
const ROUTERS = {
|
||||
TabRouter,
|
||||
StackRouter,
|
||||
SwitchRouter,
|
||||
};
|
||||
|
||||
const dummyEventSubscriber = (name, handler) => ({
|
||||
@@ -26,7 +27,7 @@ Object.keys(ROUTERS).forEach(routerName => {
|
||||
const Router = ROUTERS[routerName];
|
||||
|
||||
describe(`General router features - ${routerName}`, () => {
|
||||
test('title is configurable using navigationOptions and getScreenOptions', () => {
|
||||
test(`title is configurable using navigationOptions and getScreenOptions - ${routerName}`, () => {
|
||||
class FooView extends React.Component {
|
||||
render() {
|
||||
return <div />;
|
||||
@@ -87,6 +88,31 @@ Object.keys(ROUTERS).forEach(routerName => {
|
||||
).title
|
||||
).toEqual('Baz-123');
|
||||
});
|
||||
|
||||
test(`set params works in ${routerName}`, () => {
|
||||
class FooView extends React.Component {
|
||||
render() {
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
const router = Router({
|
||||
Foo: { screen: FooView },
|
||||
Bar: { screen: FooView },
|
||||
});
|
||||
|
||||
const initState = router.getStateForAction(NavigationActions.init());
|
||||
const initRoute = initState.routes[initState.index];
|
||||
expect(initRoute.params).toEqual(undefined);
|
||||
|
||||
const state0 = router.getStateForAction(
|
||||
NavigationActions.setParams({
|
||||
params: { foo: 42 },
|
||||
key: initRoute.key,
|
||||
}),
|
||||
initState
|
||||
);
|
||||
expect(state0.routes[state0.index].params.foo).toEqual(42);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1450,6 +1450,34 @@ describe('StackRouter', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test('Navigate action to previous nested StackRouter causes isTransitioning start', () => {
|
||||
const ChildNavigator = () => <div />;
|
||||
ChildNavigator.router = StackRouter({
|
||||
Baz: { screen: () => <div /> },
|
||||
});
|
||||
const router = StackRouter({
|
||||
Bar: { screen: ChildNavigator },
|
||||
Foo: { screen: () => <div /> },
|
||||
});
|
||||
const state = router.getStateForAction(
|
||||
{
|
||||
type: NavigationActions.NAVIGATE,
|
||||
immediate: true,
|
||||
routeName: 'Foo',
|
||||
},
|
||||
router.getStateForAction({ type: NavigationActions.INIT })
|
||||
);
|
||||
const state2 = router.getStateForAction(
|
||||
{
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'Baz',
|
||||
},
|
||||
state
|
||||
);
|
||||
expect(state2.index).toEqual(0);
|
||||
expect(state2.isTransitioning).toEqual(true);
|
||||
});
|
||||
|
||||
test('Handles the navigate action with params and nested StackRouter as a first action', () => {
|
||||
const state = TestStackRouter.getStateForAction({
|
||||
type: NavigationActions.NAVIGATE,
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
import React from 'react';
|
||||
import { View, Text, Platform, StyleSheet } from 'react-native';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
|
||||
import TouchableItem from '../TouchableItem';
|
||||
|
||||
/**
|
||||
* Component that renders the navigation list in the drawer.
|
||||
*/
|
||||
const DrawerNavigatorItems = ({
|
||||
navigation: { state, navigate },
|
||||
items,
|
||||
activeItemKey,
|
||||
activeTintColor,
|
||||
activeBackgroundColor,
|
||||
inactiveTintColor,
|
||||
inactiveBackgroundColor,
|
||||
getLabel,
|
||||
renderIcon,
|
||||
onItemPress,
|
||||
itemsContainerStyle,
|
||||
itemStyle,
|
||||
labelStyle,
|
||||
activeLabelStyle,
|
||||
inactiveLabelStyle,
|
||||
iconContainerStyle,
|
||||
drawerPosition,
|
||||
}) => (
|
||||
<View style={[styles.container, itemsContainerStyle]}>
|
||||
{items.map((route, index) => {
|
||||
const focused = activeItemKey === route.key;
|
||||
const color = focused ? activeTintColor : inactiveTintColor;
|
||||
const backgroundColor = focused
|
||||
? activeBackgroundColor
|
||||
: inactiveBackgroundColor;
|
||||
const scene = { route, index, focused, tintColor: color };
|
||||
const icon = renderIcon(scene);
|
||||
const label = getLabel(scene);
|
||||
const extraLabelStyle = focused ? activeLabelStyle : inactiveLabelStyle;
|
||||
return (
|
||||
<TouchableItem
|
||||
key={route.key}
|
||||
onPress={() => {
|
||||
onItemPress({ route, focused });
|
||||
}}
|
||||
delayPressIn={0}
|
||||
>
|
||||
<SafeAreaView
|
||||
style={{ backgroundColor }}
|
||||
forceInset={{
|
||||
[drawerPosition]: 'always',
|
||||
[drawerPosition === 'left' ? 'right' : 'left']: 'never',
|
||||
vertical: 'never',
|
||||
}}
|
||||
>
|
||||
<View style={[styles.item, itemStyle]}>
|
||||
{icon ? (
|
||||
<View
|
||||
style={[
|
||||
styles.icon,
|
||||
focused ? null : styles.inactiveIcon,
|
||||
iconContainerStyle,
|
||||
]}
|
||||
>
|
||||
{icon}
|
||||
</View>
|
||||
) : null}
|
||||
{typeof label === 'string' ? (
|
||||
<Text
|
||||
style={[styles.label, { color }, labelStyle, extraLabelStyle]}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
) : (
|
||||
label
|
||||
)}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</TouchableItem>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
|
||||
/* Material design specs - https://material.io/guidelines/patterns/navigation-drawer.html#navigation-drawer-specs */
|
||||
DrawerNavigatorItems.defaultProps = {
|
||||
activeTintColor: '#2196f3',
|
||||
activeBackgroundColor: 'rgba(0, 0, 0, .04)',
|
||||
inactiveTintColor: 'rgba(0, 0, 0, .87)',
|
||||
inactiveBackgroundColor: 'transparent',
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingVertical: 4,
|
||||
},
|
||||
item: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
icon: {
|
||||
marginHorizontal: 16,
|
||||
width: 24,
|
||||
alignItems: 'center',
|
||||
},
|
||||
inactiveIcon: {
|
||||
/*
|
||||
* Icons have 0.54 opacity according to guidelines
|
||||
* 100/87 * 54 ~= 62
|
||||
*/
|
||||
opacity: 0.62,
|
||||
},
|
||||
label: {
|
||||
margin: 16,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
});
|
||||
|
||||
export default DrawerNavigatorItems;
|
||||
@@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import SceneView from '../SceneView';
|
||||
|
||||
/**
|
||||
* Component that renders the child screen of the drawer.
|
||||
*/
|
||||
class DrawerScreen extends React.PureComponent {
|
||||
render() {
|
||||
const { descriptors, navigation, screenProps } = this.props;
|
||||
const { routes, index } = navigation.state;
|
||||
const descriptor = descriptors[routes[index].key];
|
||||
const Content = descriptor.getComponent();
|
||||
return (
|
||||
<SceneView
|
||||
screenProps={screenProps}
|
||||
component={Content}
|
||||
navigation={descriptor.navigation}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DrawerScreen;
|
||||
@@ -1,105 +0,0 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
import NavigationActions from '../../NavigationActions';
|
||||
import StackActions from '../../routers/StackActions';
|
||||
import invariant from '../../utils/invariant';
|
||||
|
||||
/**
|
||||
* Component that renders the sidebar screen of the drawer.
|
||||
*/
|
||||
|
||||
class DrawerSidebar extends React.PureComponent {
|
||||
_getScreenOptions = routeKey => {
|
||||
const descriptor = this.props.descriptors[routeKey];
|
||||
invariant(
|
||||
descriptor.options,
|
||||
'Cannot access screen descriptor options from drawer sidebar'
|
||||
);
|
||||
return descriptor.options;
|
||||
};
|
||||
|
||||
_getLabel = ({ focused, tintColor, route }) => {
|
||||
const { drawerLabel, title } = this._getScreenOptions(route.key);
|
||||
if (drawerLabel) {
|
||||
return typeof drawerLabel === 'function'
|
||||
? drawerLabel({ tintColor, focused })
|
||||
: drawerLabel;
|
||||
}
|
||||
|
||||
if (typeof title === 'string') {
|
||||
return title;
|
||||
}
|
||||
|
||||
return route.routeName;
|
||||
};
|
||||
|
||||
_renderIcon = ({ focused, tintColor, route }) => {
|
||||
const { drawerIcon } = this._getScreenOptions(route.key);
|
||||
if (drawerIcon) {
|
||||
return typeof drawerIcon === 'function'
|
||||
? drawerIcon({ tintColor, focused })
|
||||
: drawerIcon;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
_onItemPress = ({ route, focused }) => {
|
||||
if (!focused) {
|
||||
let subAction;
|
||||
// TODO (v3): Revisit and repeal this behavior:
|
||||
// if the child screen is a StackRouter then always navigate to its first screen (see #1914)
|
||||
if (route.index != null && route.index !== 0) {
|
||||
subAction = StackActions.reset({
|
||||
index: 0,
|
||||
actions: [
|
||||
NavigationActions.navigate({
|
||||
routeName: route.routes[0].routeName,
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
this.props.navigation.dispatch(
|
||||
NavigationActions.navigate({
|
||||
routeName: route.routeName,
|
||||
action: subAction,
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const ContentComponent = this.props.contentComponent;
|
||||
if (!ContentComponent) {
|
||||
return null;
|
||||
}
|
||||
const { state } = this.props.navigation;
|
||||
invariant(typeof state.index === 'number', 'should be set');
|
||||
return (
|
||||
<View style={[styles.container, this.props.style]}>
|
||||
<ContentComponent
|
||||
{...this.props.contentOptions}
|
||||
navigation={this.props.navigation}
|
||||
descriptors={this.props.descriptors}
|
||||
items={state.routes}
|
||||
activeItemKey={
|
||||
state.routes[state.index] ? state.routes[state.index].key : null
|
||||
}
|
||||
screenProps={this.props.screenProps}
|
||||
getLabel={this._getLabel}
|
||||
renderIcon={this._renderIcon}
|
||||
onItemPress={this._onItemPress}
|
||||
drawerPosition={this.props.drawerPosition}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DrawerSidebar;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
@@ -1,120 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Dimensions } from 'react-native';
|
||||
import DrawerLayout from 'react-native-drawer-layout-polyfill';
|
||||
|
||||
import DrawerSidebar from './DrawerSidebar';
|
||||
import NavigationActions from '../../NavigationActions';
|
||||
import DrawerActions from '../../routers/DrawerActions';
|
||||
|
||||
/**
|
||||
* Component that renders the drawer.
|
||||
*/
|
||||
export default class DrawerView extends React.PureComponent {
|
||||
state = {
|
||||
drawerWidth:
|
||||
typeof this.props.navigationConfig.drawerWidth === 'function'
|
||||
? this.props.navigationConfig.drawerWidth()
|
||||
: this.props.navigationConfig.drawerWidth,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
Dimensions.addEventListener('change', this._updateWidth);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
Dimensions.removeEventListener('change', this._updateWidth);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const { isDrawerOpen } = this.props.navigation.state;
|
||||
const wasDrawerOpen = prevProps.navigation.state.isDrawerOpen;
|
||||
|
||||
if (isDrawerOpen && !wasDrawerOpen) {
|
||||
this._drawer.openDrawer();
|
||||
} else if (wasDrawerOpen && !isDrawerOpen) {
|
||||
this._drawer.closeDrawer();
|
||||
}
|
||||
}
|
||||
|
||||
_handleDrawerOpen = () => {
|
||||
const { navigation } = this.props;
|
||||
const { isDrawerOpen } = navigation.state;
|
||||
if (!isDrawerOpen) {
|
||||
navigation.dispatch({ type: DrawerActions.OPEN_DRAWER });
|
||||
}
|
||||
};
|
||||
|
||||
_handleDrawerClose = () => {
|
||||
const { navigation } = this.props;
|
||||
const { isDrawerOpen } = navigation.state;
|
||||
if (isDrawerOpen) {
|
||||
navigation.dispatch({ type: DrawerActions.CLOSE_DRAWER });
|
||||
}
|
||||
};
|
||||
|
||||
_updateWidth = () => {
|
||||
const drawerWidth =
|
||||
typeof this.props.navigationConfig.drawerWidth === 'function'
|
||||
? this.props.navigationConfig.drawerWidth()
|
||||
: this.props.navigationConfig.drawerWidth;
|
||||
|
||||
if (this.state.drawerWidth !== drawerWidth) {
|
||||
this.setState({ drawerWidth });
|
||||
}
|
||||
};
|
||||
|
||||
_renderNavigationView = () => {
|
||||
return (
|
||||
<DrawerSidebar
|
||||
screenProps={this.props.screenProps}
|
||||
navigation={this.props.navigation}
|
||||
descriptors={this.props.descriptors}
|
||||
contentComponent={this.props.navigationConfig.contentComponent}
|
||||
contentOptions={this.props.navigationConfig.contentOptions}
|
||||
drawerPosition={this.props.navigationConfig.drawerPosition}
|
||||
style={this.props.navigationConfig.style}
|
||||
{...this.props.navigationConfig}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { state } = this.props.navigation;
|
||||
const activeKey = state.routes[state.index].key;
|
||||
const descriptor = this.props.descriptors[activeKey];
|
||||
|
||||
const DrawerScreen = descriptor.getComponent();
|
||||
|
||||
const { drawerLockMode } = descriptor.options;
|
||||
|
||||
return (
|
||||
<DrawerLayout
|
||||
ref={c => {
|
||||
this._drawer = c;
|
||||
}}
|
||||
drawerLockMode={
|
||||
(this.props.screenProps && this.props.screenProps.drawerLockMode) ||
|
||||
this.props.navigationConfig.drawerLockMode
|
||||
}
|
||||
drawerBackgroundColor={
|
||||
this.props.navigationConfig.drawerBackgroundColor
|
||||
}
|
||||
drawerWidth={this.state.drawerWidth}
|
||||
onDrawerOpen={this._handleDrawerOpen}
|
||||
onDrawerClose={this._handleDrawerClose}
|
||||
useNativeAnimations={this.props.navigationConfig.useNativeAnimations}
|
||||
renderNavigationView={this._renderNavigationView}
|
||||
drawerPosition={
|
||||
this.props.navigationConfig.drawerPosition === 'right'
|
||||
? DrawerLayout.positions.Right
|
||||
: DrawerLayout.positions.Left
|
||||
}
|
||||
>
|
||||
<DrawerScreen
|
||||
screenProps={this.props.screenProps}
|
||||
navigation={descriptor.navigation}
|
||||
/>
|
||||
</DrawerLayout>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
import { NativeModules } from 'react-native';
|
||||
|
||||
import StackViewLayout from './StackViewLayout';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import clamp from 'clamp';
|
||||
import {
|
||||
@@ -211,6 +211,8 @@ class StackViewLayout extends React.Component {
|
||||
|
||||
_panResponder = PanResponder.create({
|
||||
onPanResponderTerminate: () => {
|
||||
const { navigation } = this.props.transitionProps;
|
||||
const { index } = navigation.state;
|
||||
this._isResponding = false;
|
||||
this._reset(index, 0);
|
||||
this.props.onGestureCanceled && this.props.onGestureCanceled();
|
||||
@@ -518,15 +520,17 @@ class StackViewLayout extends React.Component {
|
||||
if (!hasHeader && headerMode === 'float') {
|
||||
const { isLandscape } = this.props;
|
||||
let headerHeight;
|
||||
if (Platform.OS === 'android') {
|
||||
// TODO: Need to handle translucent status bar.
|
||||
headerHeight = 56;
|
||||
} else if (isLandscape && !Platform.isPad) {
|
||||
headerHeight = 52;
|
||||
} else if (IS_IPHONE_X) {
|
||||
headerHeight = 88;
|
||||
if (Platform.OS === 'ios') {
|
||||
if (isLandscape && !Platform.isPad) {
|
||||
headerHeight = 52;
|
||||
} else if (IS_IPHONE_X) {
|
||||
headerHeight = 88;
|
||||
} else {
|
||||
headerHeight = 64;
|
||||
}
|
||||
} else {
|
||||
headerHeight = 64;
|
||||
headerHeight = 56;
|
||||
// TODO (Android only): Need to handle translucent status bar.
|
||||
}
|
||||
marginTop = -headerHeight;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,24 @@ class Transitioner extends React.Component {
|
||||
this._prevTransitionProps = this._transitionProps;
|
||||
this._transitionProps = buildTransitionProps(nextProps, nextState);
|
||||
|
||||
const toValue = nextProps.navigation.state.index;
|
||||
|
||||
if (!this._transitionProps.navigation.state.isTransitioning) {
|
||||
this.setState(nextState, async () => {
|
||||
const result = nextProps.onTransitionStart(
|
||||
this._transitionProps,
|
||||
this._prevTransitionProps
|
||||
);
|
||||
if (result instanceof Promise) {
|
||||
await result;
|
||||
}
|
||||
progress.setValue(1);
|
||||
position.setValue(toValue);
|
||||
this._onTransitionEnd();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// get the transition spec.
|
||||
const transitionUserSpec = nextProps.configureTransition
|
||||
? nextProps.configureTransition(
|
||||
@@ -106,7 +124,6 @@ class Transitioner extends React.Component {
|
||||
const { timing } = transitionSpec;
|
||||
delete transitionSpec.timing;
|
||||
|
||||
const toValue = nextProps.navigation.state.index;
|
||||
const positionHasChanged = position.__getValue() !== toValue;
|
||||
|
||||
// if swiped back, indexHasChanged == true && positionHasChanged == false
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint react/display-name:0 */
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import Transitioner from '../Transitioner';
|
||||
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
|
||||
exports[`TabBarBottom renders successfully 1`] = `
|
||||
<View
|
||||
loaded={
|
||||
Array [
|
||||
0,
|
||||
]
|
||||
}
|
||||
onLayout={[Function]}
|
||||
collapsable={false}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
@@ -20,73 +15,67 @@ exports[`TabBarBottom renders successfully 1`] = `
|
||||
]
|
||||
}
|
||||
>
|
||||
<RCTScrollView
|
||||
DEPRECATED_sendUpdatedChildFrames={false}
|
||||
alwaysBounceHorizontal={false}
|
||||
alwaysBounceVertical={false}
|
||||
automaticallyAdjustContentInsets={false}
|
||||
bounces={false}
|
||||
contentContainerStyle={
|
||||
<View
|
||||
onLayout={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
}
|
||||
}
|
||||
contentOffset={
|
||||
Object {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
}
|
||||
}
|
||||
directionalLockEnabled={true}
|
||||
horizontal={true}
|
||||
keyboardDismissMode="on-drag"
|
||||
keyboardShouldPersistTaps="always"
|
||||
onContentSizeChange={null}
|
||||
onMomentumScrollBegin={[Function]}
|
||||
onMomentumScrollEnd={[Function]}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderReject={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderTerminate={undefined}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onScroll={[Function]}
|
||||
onScrollBeginDrag={[Function]}
|
||||
onScrollEndDrag={[Function]}
|
||||
onScrollShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponderCapture={[Function]}
|
||||
onTouchCancel={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchMove={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
overScrollMode="never"
|
||||
pagingEnabled={true}
|
||||
scrollEnabled={undefined}
|
||||
scrollEventThrottle={1}
|
||||
scrollsToTop={false}
|
||||
sendMomentumEvents={true}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"flexGrow": 1,
|
||||
"flexShrink": 1,
|
||||
"overflow": "scroll",
|
||||
},
|
||||
>
|
||||
<RCTScrollView
|
||||
DEPRECATED_sendUpdatedChildFrames={false}
|
||||
alwaysBounceHorizontal={false}
|
||||
alwaysBounceVertical={false}
|
||||
automaticallyAdjustContentInsets={false}
|
||||
bounces={false}
|
||||
contentContainerStyle={
|
||||
Object {
|
||||
"flex": 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<RCTScrollContentView
|
||||
collapsable={false}
|
||||
removeClippedSubviews={undefined}
|
||||
}
|
||||
}
|
||||
contentOffset={
|
||||
Object {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
}
|
||||
}
|
||||
directionalLockEnabled={true}
|
||||
horizontal={true}
|
||||
keyboardDismissMode="on-drag"
|
||||
keyboardShouldPersistTaps="always"
|
||||
onContentSizeChange={null}
|
||||
onMomentumScrollBegin={[Function]}
|
||||
onMomentumScrollEnd={[Function]}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderReject={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderTerminate={undefined}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onScroll={[Function]}
|
||||
onScrollBeginDrag={[Function]}
|
||||
onScrollEndDrag={[Function]}
|
||||
onScrollShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponderCapture={[Function]}
|
||||
onTouchCancel={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchMove={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
overScrollMode="never"
|
||||
pagingEnabled={true}
|
||||
scrollEnabled={undefined}
|
||||
scrollEventThrottle={1}
|
||||
scrollsToTop={false}
|
||||
sendMomentumEvents={true}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"flexGrow": 1,
|
||||
"flexShrink": 1,
|
||||
"overflow": "scroll",
|
||||
},
|
||||
Object {
|
||||
"flex": 1,
|
||||
@@ -94,47 +83,62 @@ exports[`TabBarBottom renders successfully 1`] = `
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
<RCTScrollContentView
|
||||
collapsable={false}
|
||||
removeClippedSubviews={undefined}
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
"overflow": "hidden",
|
||||
}
|
||||
Array [
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
},
|
||||
Object {
|
||||
"flex": 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
testID={undefined}
|
||||
>
|
||||
<View
|
||||
collapsable={false}
|
||||
removeClippedSubviews={false}
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
"overflow": "hidden",
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
>
|
||||
<View
|
||||
collapsable={false}
|
||||
removeClippedSubviews={false}
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
"overflow": "hidden",
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
navigation={
|
||||
style={
|
||||
Object {
|
||||
"state": Object {
|
||||
"key": "s1",
|
||||
"routeName": "s1",
|
||||
},
|
||||
"flex": 1,
|
||||
}
|
||||
}
|
||||
screenProps={undefined}
|
||||
/>
|
||||
>
|
||||
<View
|
||||
navigation={
|
||||
Object {
|
||||
"state": Object {
|
||||
"key": "s1",
|
||||
"routeName": "s1",
|
||||
},
|
||||
}
|
||||
}
|
||||
screenProps={undefined}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</RCTScrollContentView>
|
||||
</RCTScrollView>
|
||||
</RCTScrollContentView>
|
||||
</RCTScrollView>
|
||||
</View>
|
||||
</View>
|
||||
`;
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 659 B |
|
Before Width: | Height: | Size: 491 B After Width: | Height: | Size: 290 B |
|
Before Width: | Height: | Size: 786 B After Width: | Height: | Size: 373 B |
|
Before Width: | Height: | Size: 491 B After Width: | Height: | Size: 290 B |
|
Before Width: | Height: | Size: 966 B After Width: | Height: | Size: 405 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 761 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 812 B |