Compare commits

...

32 Commits

Author SHA1 Message Date
Brent Vatne
6ac3bb90ed Bump version 2018-01-11 18:30:28 -08:00
Brent Vatne
627c487936 Revert "Issue #2794 - Fixing iPad iOS 11 Tab Bar Bottom Behavior (#3041)"
This reverts commit c7b73cd8b4.
2018-01-11 18:21:46 -08:00
Brent Vatne
f46bdff703 Bump version 2018-01-11 18:20:44 -08:00
Adam Miskiewicz
bc75a5b7b9 Use stiffness/damping/mass for card stack transition on React Native >= 50 (#3261) 2018-01-11 18:08:42 -08:00
混沌DM
50d5c8bc0a Set the default value of the DrawerNavigatorConfig correctly. (#3152)
* Set the default value of the DrawerNavigatorConfig correctly.

* update DrawerViewProps type
2018-01-09 14:58:27 +05:30
SteffeyDev
c7b73cd8b4 Issue #2794 - Fixing iPad iOS 11 Tab Bar Bottom Behavior (#3041)
* Fixing iPad iOS 11 Tab Bar Bottom Behavior with changing widths via Multitasking

* Updating snapshot tests

* Changes per discussion in !3041

* Additional changes per discussion in !3041

* Changing to test for constrained height

* Additional changes per discussion in !3041
2018-01-08 20:28:13 -06:00
rgovind92
e2e540c32d Fix drawer toggle (#3191)
* Fixed drawer toggle

* Fixed drawer toggle

* Update DrawerView.js
2018-01-06 10:40:56 -05:00
Brent Vatne
7a57c4e779 Update README, bump version 2018-01-04 14:10:08 -08:00
Jani Eväkallio
4373544257 If URL is just a scheme:// component without a path, default to root "/" URL (#3224) 2018-01-04 13:28:41 -08:00
Satyajit Sahoo
8329e269b6 Upgrade react-native-tab-view (#3064) 2018-01-04 14:15:35 +00:00
Lorenzo Sciandra
450a1e3ba5 removing react-addons-test-utils (#3221) 2018-01-04 14:08:58 +00:00
Brent Vatne
a83220b511 Update ISSUE_TEMPLATE.md 2017-12-27 13:24:36 -08:00
Brent Vatne
6af770d644 Fix example project 2017-12-20 13:35:35 -08:00
Spencer Carli
ef63b230b2 v1.0.0-beta.22 2017-12-18 15:53:48 -06:00
Axel Eirola
41b587ca65 Enable configuration of gesture direction (#3077)
* Enable configuration of gesture direction

* Fix documentation and code style

* Invert behaviour of I18nManager.isRTL instead of overriding
2017-12-18 16:25:16 -05:00
Stephen O'Brien
faed4731bc Safe area view: support animated style values (#3124)
* Use Animated.View instead of View in SafeAreaView

This allows passing animated style properties in certain contexts, as previously supported.

* Update some test snapshots
2017-12-17 17:20:08 -06:00
Nicolas Charpentier
7fe76fb7c6 Fix handling the Hardware Back Button link in Redux section (#3134) 2017-12-16 13:17:43 -06:00
Nicolas Charpentier
89a6668595 Update Contributors Guide link (#3133) 2017-12-15 16:37:31 +00:00
Denis Evgrafov
9cf9e25661 Update Navigation-Actions.md (#3126) 2017-12-15 00:37:22 +01:00
Axel Eirola
363f93fc4d Add support for custom header transitions (#3075)
* Add support for custom header transitions

* Use default props for header transition default values
2017-12-14 22:14:38 +01:00
Ashoat Tevosyan
928f632c89 Don't use params from unrelated action when initializing nav state (#3094)
`TabRouter.getStateForAction` has some code at the start to initialize an empty nav state before handling any action. This initialization is achieved by passing `INIT` actions to all child routes. However, the code strangely also passes these child routes the params that were given to the action. The initialization should be separate from the processing of the action.
2017-12-12 11:00:33 +00:00
Patrick Monteith
950d0c6877 Don't delegate inner action to child router, handle inner action when handling NAVIGATE 2017-12-07 23:25:27 +08:00
Sergei
5a26506595 Disable / enable swipe depending on screen. (#2906)
* Disable / enable swipe depending on screen.

react-community#1760

* Updated to master

* Revert "Updated to master"

This reverts commit a3aede19588cdbc7fc9148d148260f51d6316e6f.

* - Fixed CircleCI errors

* - Fixed CircleCI errors
2017-12-01 15:53:26 -06:00
James Reggio
5cb42bdf5d Await promise from Transitioner onTransitionStart (#2946)
* Await promise from onTransitionStart

* Review feedback

* Update docs for onTransitionEnd
2017-12-01 15:42:53 -06:00
Flo
d5618ebd41 Drawer Improvement, Let define a route key to open/close multiple dra… (#1803)
* Drawer Improvement, Let define a route key to open/close multiple drawer with no side effects

* fix lint issues

* fix flow issues
2017-11-29 09:01:35 -06:00
tab
368bc615c1 Set sdkVersion to 23.0.0 (#3037) 2017-11-25 16:12:51 -06:00
Ashoat Tevosyan
f332b6bdf7 Add NavigationContainer and NavigationContainerProps types (#3030)
Adding types for these fixes the errors we're seeing when using `TabNavigator` and `StackNavigator`.
2017-11-22 14:42:17 +00:00
Spencer Carli
b5700b9277 v1.0.0-beta.21 2017-11-21 09:25:24 -06:00
Spencer Carli
ad59d161db Fix #3020 (#3024) 2017-11-21 09:24:24 -06:00
Vojtech Novak
cc355dcee9 return null if it is passed (#3021) 2017-11-21 08:54:46 -06:00
mukunzidd
04c075c1bb Fix typo On "Getting Started 3." (#3022)
Browse the official example app, which will `demonstrates` various patterns with React Navigation. 
demonstrates should be `demonstrate`
2017-11-21 15:40:01 +01:00
londonoliver
7ae6908428 Update Guide-Quick-Start.md (#3015) 2017-11-21 08:34:39 +01:00
51 changed files with 1841 additions and 1441 deletions

View File

@@ -1,10 +1,10 @@
## The issue list is reserved for bugs and feature requests, not for questions.
## The issue tracker is reserved for bug reports only.
For usage questions, try to:
If you have a question or feature request, please try one of the following resources:
- [Read the docs](https://reactnavigation.org/)
- [Ask on the Reactiflux (#react-navigation)](https://discord.gg/reactiflux)
- [Look for / ask questions on StackOverflow](https://stackoverflow.com/questions/tagged/react-navigation)
- [Read the documentation](https://reactnavigation.org/)
- [Post a feature request to Canny](https://react-navigation.canny.io/feature-requests)
- [Get help on Discord chat (#react-navigation on Reactiflux)](https://discord.gg/4xEK3nD) or [on StackOverflow](https://stackoverflow.com/questions/tagged/react-navigation)
- Search for your issue - it may have already been answered or even fixed in the development branch. However, if you find that an old, closed issue still persists in the latest version, you should open a new issue.
---

View File

@@ -1,4 +1,6 @@
# React Navigation [![CircleCI](https://circleci.com/gh/react-community/react-navigation/tree/master.svg?style=shield&circle-token=622fcb1d78413084c2f44699ed2104246a177485)](https://circleci.com/gh/react-community/react-navigation/tree/master) [![npm version](https://badge.fury.io/js/react-navigation.svg)](https://badge.fury.io/js/react-navigation) [![codecov](https://codecov.io/gh/react-community/react-navigation/branch/master/graph/badge.svg)](https://codecov.io/gh/react-community/react-navigation) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://reactnavigation.org/docs/guides/contributors)
# React Navigation
[![npm version](https://badge.fury.io/js/react-navigation.svg)](https://badge.fury.io/js/react-navigation) [![codecov](https://codecov.io/gh/react-community/react-navigation/branch/master/graph/badge.svg)](https://codecov.io/gh/react-community/react-navigation) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://reactnavigation.org/docs/guides/contributors)
*Learn once, navigate anywhere.*

View File

@@ -158,6 +158,10 @@ Object to override the distance of touch start from the edge of the screen to re
- `horizontal` - *number* - Distance for horizontal direction. Defaults to 25.
- `vertical` - *number* - Distance for vertical direction. Defaults to 135.
#### `gestureDirection`
String to override the direction for dismiss gesture. `default` for normal behaviour or `inverted` for right-to-left swipes.
### Navigator Props
The navigator component created by `StackNavigator(...)` takes the following props:
@@ -222,3 +226,5 @@ const ModalNavigator = StackNavigator(
}
);
```
Header transitions can also be configured using `headerLeftInterpolator`, `headerTitleInterpolator` and `headerRightInterpolator` fields under `transitionConfig`.

View File

@@ -88,7 +88,6 @@ The route configs object is a mapping from route name to a route config, which t
- `swipeEnabled` - Whether to allow swiping between tabs.
- `animationEnabled` - Whether to animate when changing tabs.
- `configureTransition` - a function that, given `currentTransitionProps` and `nextTransitionProps`, returns a configuration object that describes the animation between tabs.
- `lazy` - Whether to lazily render tabs as needed as opposed to rendering them upfront.
- `initialLayout` - Optional object containing the initial `height` and `width`, can be passed to prevent the one frame delay in [react-native-tab-view](https://github.com/react-native-community/react-native-tab-view#avoid-one-frame-delay) rendering.
- `tabBarOptions` - Configure the tab bar, see below.
@@ -168,6 +167,10 @@ Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel`
True or false to show or hide the tab bar, if not set then defaults to true.
#### `swipeEnabled`
True or false to enable or disable swiping between tabs, if not set then defaults to TabNavigatorConfig option swipeEnabled.
#### `tabBarIcon`
React Element or a function that given `{ focused: boolean, tintColor: string }` returns a React.Node, to display in tab bar.

View File

@@ -166,20 +166,24 @@ render: (transitionProps: NavigationTransitionProps, prevTransitionProps: ?Navig
### `onTransitionStart` function
Invoked when the transition animation is about to start.
If you return a promise from `onTransitionStart`, the transition animation will begin after the promise is resolved.
#### Flow definition
```js
onTransitionStart: (transitionProps: NavigationTransitionProps, prevTransitionProps: ?NavigationTransitionProps) => void,
onTransitionStart: (transitionProps: NavigationTransitionProps, prevTransitionProps: ?NavigationTransitionProps) => (Promise | void),
```
#### Parameters
- `transitionProps`: the current [NavigationTransitionProps](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js#L273) created from the current state and props
- `prevTransitionProps`: the previous [NavigationTransitionProps](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js#L273) created from the previous state and props
#### Returns
- none.
- `Promise` to delay the start of the transition animation, or none to begin the transition animation immediately.
### `onTransitionEnd` function
Invoked once the transition animation completes.
If you return a promise from `onTransitionEnd`, any queued transition animations will begin after the promise is resolved.
#### Flow definition
```js
onTransitionEnd: () => void

View File

@@ -17,7 +17,7 @@ Quickly get a grasp on the React Navigation API with demonstrations of the Stack
Dive into the basics of React Navigation by creating a new React Native project, installing React Navigation, creating your first navigator, and learning how to interact with it.
3. [Navigation Playground](https://github.com/react-community/react-navigation/tree/master/examples/NavigationPlayground)
Curious of the various capabilities of React Navigation? Browse the official example app, which will demonstrates various patterns with React Navigation.
Curious of the various capabilities of React Navigation? Browse the official example app, which will demonstrate various patterns with React Navigation.
4. [Community Contributions](https://github.com/react-community/react-navigation#community-contributions)
With the flexibility of React Navigation we won't be able to cover every possible situation, but another developer may have! Browse our list of community contributions to find topics that may answer your questions.

View File

@@ -88,7 +88,7 @@ const RootNavigator = StackNavigator({
export default RootNavigator;
```
Finally, we should be able to navigate from the home screen to the details screen. When you register a component with a navigator that component will then have a `navigation` prop added to it. This `navigation` prop drives how we use move between different screens.
Finally, we should be able to navigate from the home screen to the details screen. When you register a component with a navigator that component will then have a `navigation` prop added to it. This `navigation` prop drives how we move between different screens.
To move from the home screen to the details screen we'll want to use `navigation.navigate`, like so:

View File

@@ -6,7 +6,7 @@ Note that if you want to dispatch react-navigation actions you should use the ac
The following actions are supported:
* [Navigate](#Navigate) - Navigate to another route
* [Reset](#Reset) - Replace current state with a new state
* [Reset](#reset) - Replace current state with a new state
* [Back](#Back) - Go back to previous state
* [Set Params](#SetParams) - Set Params for given route
* [Init](#Init) - Used to initialize first state if state is undefined

View File

@@ -61,7 +61,7 @@ class Root extends React.Component {
Once you do this, your navigation state is stored within your redux store, at which point you can fire navigation actions using your redux dispatch function.
Keep in mind that when a navigator is given a `navigation` prop, it relinquishes control of its internal state. That means you are now responsible for persisting its state, handling any deep linking, [Handling the Hardware Back Button in Android](#handling-the-hardware-back-button-in-android), etc.
Keep in mind that when a navigator is given a `navigation` prop, it relinquishes control of its internal state. That means you are now responsible for persisting its state, handling any deep linking, [Handling the Hardware Back Button in Android](#Handling-the-Hardware-Back-Button-in-Android), etc.
Navigation state is automatically passed down from one navigator to another when you nest them. Note that in order for a child navigator to receive the state from a parent navigator, it should be defined as a `screen`.

View File

@@ -4,6 +4,6 @@ A playground for experimenting with react-navigation in a pure-JS React Native a
## Usage
Please see the [Contributors Guide](https://github.com/react-community/react-navigation/blob/master/docs/guides/Contributors.md#development) for instructions on running these example apps.
Please see the [Contributors Guide](https://reactnavigation.org/docs/guides/contributors#Run-the-Example-App) for instructions on running these example apps.
You can view this example application directly on your phone by visiting [our expo demo](https://exp.host/@react-navigation/NavigationPlayground).

View File

@@ -12,7 +12,7 @@
"icon": "./assets/icons/react-navigation.png",
"hideExponentText": false
},
"sdkVersion": "23.0.0",
"sdkVersion": "24.0.0",
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
"packagerOpts": {
"assetExts": [

View File

@@ -1,7 +1,7 @@
/* @flow */
import React from 'react';
import { ScreenOrientation } from 'expo';
import { Constants, ScreenOrientation } from 'expo';
ScreenOrientation.allow(ScreenOrientation.Orientation.ALL);
@@ -11,6 +11,7 @@ import {
StyleSheet,
TouchableOpacity,
Text,
StatusBar,
View,
} from 'react-native';
import { SafeAreaView, StackNavigator } from 'react-navigation';
@@ -19,6 +20,7 @@ import Banner from './Banner';
import CustomTabs from './CustomTabs';
import CustomTransitioner from './CustomTransitioner';
import Drawer from './Drawer';
import MultipleDrawer from './MultipleDrawer';
import TabsInDrawer from './TabsInDrawer';
import ModalStack from './ModalStack';
import StacksInTabs from './StacksInTabs';
@@ -43,6 +45,11 @@ const ExampleRoutes = {
description: 'Android-style drawer navigation',
screen: Drawer,
},
// MultipleDrawer: {
// name: 'Multiple Drawer Example',
// description: 'Add any drawer you need',
// screen: MultipleDrawer,
// },
TabsInDrawer: {
name: 'Drawer + Tabs Example',
description: 'A drawer combined with tabs',
@@ -98,34 +105,47 @@ const ExampleRoutes = {
},
};
const MainScreen = ({ navigation }) => (
<ScrollView style={{ flex: 1 }} contentInsetAdjustmentBehavior="automatic">
<Banner />
{Object.keys(ExampleRoutes).map((routeName: string) => (
<TouchableOpacity
key={routeName}
onPress={() => {
const { path, params, screen } = ExampleRoutes[routeName];
const { router } = screen;
const action = path && router.getActionForPathAndParams(path, params);
navigation.navigate(routeName, {}, action);
}}
>
<SafeAreaView
style={styles.itemContainer}
forceInset={{ vertical: 'never' }}
>
<View style={styles.item}>
<Text style={styles.title}>{ExampleRoutes[routeName].name}</Text>
<Text style={styles.description}>
{ExampleRoutes[routeName].description}
</Text>
</View>
</SafeAreaView>
</TouchableOpacity>
))}
</ScrollView>
);
class MainScreen extends React.Component<*> {
render() {
const { navigation } = this.props;
return (
<View style={{ flex: 1 }}>
<ScrollView style={{ flex: 1 }}>
<Banner />
{Object.keys(ExampleRoutes).map((routeName: string) => (
<TouchableOpacity
key={routeName}
onPress={() => {
const { path, params, screen } = ExampleRoutes[routeName];
const { router } = screen;
const action =
path && router.getActionForPathAndParams(path, params);
navigation.navigate(routeName, {}, action);
}}
>
<SafeAreaView
style={styles.itemContainer}
forceInset={{ vertical: 'never' }}
>
<View style={styles.item}>
<Text style={styles.title}>
{ExampleRoutes[routeName].name}
</Text>
<Text style={styles.description}>
{ExampleRoutes[routeName].description}
</Text>
</View>
</SafeAreaView>
</TouchableOpacity>
))}
</ScrollView>
<StatusBar barStyle="light-content" />
<View style={styles.statusBarUnderlay} />
</View>
);
}
}
const AppNavigator = StackNavigator(
{
@@ -165,6 +185,14 @@ const styles = StyleSheet.create({
marginBottom: 20,
resizeMode: 'contain',
},
statusBarUnderlay: {
backgroundColor: '#673ab7',
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: Constants.statusBarHeight,
},
title: {
fontSize: 16,
fontWeight: 'bold',

View File

@@ -22,6 +22,7 @@ export default Banner;
const styles = StyleSheet.create({
bannerContainer: {
backgroundColor: '#673ab7',
paddingTop: 20,
},
banner: {
flexDirection: 'row',

View File

@@ -8,6 +8,7 @@ import {
Platform,
ScrollView,
StyleSheet,
StatusBar,
Text,
TouchableOpacity,
View,
@@ -32,6 +33,7 @@ const MyNavScreen = ({ navigation, banner }) => (
title="Go back"
/>
</SafeAreaView>
<StatusBar barStyle="default" />
</ScrollView>
);

View File

@@ -1,12 +1,13 @@
import React, { Component, PropTypes } from 'react';
import {
StyleSheet,
Platform,
Easing,
View,
Animated,
Image,
Button,
Easing,
Image,
Platform,
StatusBar,
StyleSheet,
View,
} from 'react-native';
import {
Transitioner,
@@ -30,6 +31,7 @@ const MyNavScreen = ({ navigation, banner }) => (
)}
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
);

View File

@@ -3,7 +3,7 @@
*/
import React from 'react';
import { Button, Platform, ScrollView } from 'react-native';
import { Button, Platform, ScrollView, StatusBar } from 'react-native';
import { DrawerNavigator, SafeAreaView } from 'react-navigation';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import SampleText from './SampleText';
@@ -18,6 +18,7 @@ const MyNavScreen = ({ navigation, banner }) => (
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</SafeAreaView>
<StatusBar barStyle="default" />
</ScrollView>
);
@@ -57,6 +58,9 @@ const DrawerExample = DrawerNavigator(
},
},
{
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
initialRouteName: 'Drafts',
contentOptions: {
activeTintColor: '#e91e63',

View File

@@ -3,7 +3,7 @@
*/
import React from 'react';
import { Button, ScrollView, Text } from 'react-native';
import { Button, ScrollView, StatusBar, Text } from 'react-native';
import { SafeAreaView, StackNavigator } from 'react-navigation';
import SampleText from './SampleText';
@@ -36,6 +36,7 @@ const MyNavScreen = ({ navigation, banner }) => (
)}
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</SafeAreaView>
<StatusBar barStyle="default" />
</ScrollView>
);

View File

@@ -0,0 +1,84 @@
/**
* @flow
*/
import React from 'react';
import { Button, Platform, ScrollView, StyleSheet } from 'react-native';
import { DrawerNavigator } from 'react-navigation';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import SampleText from './SampleText';
const MyNavScreen = ({ navigation, banner }) => (
<ScrollView style={styles.container}>
<SampleText>{banner}</SampleText>
<Button
onPress={() => navigation.navigate('DrawerOpen')}
title="Open drawer"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</ScrollView>
);
const InboxScreen = ({ navigation }) => (
<MyNavScreen banner={'Inbox Screen'} navigation={navigation} />
);
InboxScreen.navigationOptions = {
drawerLabel: 'Inbox',
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="move-to-inbox"
size={24}
style={{ color: tintColor }}
/>
),
};
const DraftsScreen = ({ navigation }) => (
<MyNavScreen banner={'Drafts Screen'} navigation={navigation} />
);
DraftsScreen.navigationOptions = {
drawerLabel: 'Drafts',
drawerIcon: ({ tintColor }) => (
<MaterialIcons name="drafts" size={24} style={{ color: tintColor }} />
),
};
const DrawerExample = DrawerNavigator(
{
Inbox: {
path: '/',
screen: InboxScreen,
},
Drafts: {
path: '/sent',
screen: DraftsScreen,
},
},
{
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
initialRouteName: 'Drafts',
contentOptions: {
activeTintColor: '#e91e63',
},
}
);
const MainDrawerExample = DrawerNavigator({
Drafts: {
screen: DrawerExample,
},
}, {
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
});
const styles = StyleSheet.create({
container: {
marginTop: Platform.OS === 'ios' ? 20 : 0,
},
});
export default MainDrawerExample;

View File

@@ -3,7 +3,7 @@
*/
import React from 'react';
import { Button, ScrollView } from 'react-native';
import { Button, ScrollView, StatusBar } from 'react-native';
import { StackNavigator, SafeAreaView } from 'react-navigation';
import SampleText from './SampleText';
@@ -19,6 +19,7 @@ const MyNavScreen = ({ navigation, banner }) => (
title="Go to a photos screen"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
);

View File

@@ -3,7 +3,7 @@
*/
import React from 'react';
import { Button, Platform, ScrollView, View } from 'react-native';
import { Button, Platform, ScrollView, StatusBar, View } from 'react-native';
import { SafeAreaView, TabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import SampleText from './SampleText';
@@ -20,6 +20,7 @@ const MyNavScreen = ({ navigation, banner }) => (
title="Go to settings tab"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
);

View File

@@ -3,7 +3,7 @@
*/
import React from 'react';
import { Button, ScrollView } from 'react-native';
import { Button, ScrollView, StatusBar } from 'react-native';
import { SafeAreaView, StackNavigator, TabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
@@ -27,6 +27,8 @@ const MyNavScreen = ({ navigation, banner }) => (
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</SafeAreaView>
<StatusBar barStyle="default" />
</ScrollView>
);

View File

@@ -3,7 +3,7 @@
*/
import React from 'react';
import { Button, ScrollView } from 'react-native';
import { Button, ScrollView, StatusBar } from 'react-native';
import { SafeAreaView, StackNavigator, TabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
@@ -27,6 +27,7 @@ const MyNavScreen = ({ navigation, banner }) => (
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</SafeAreaView>
<StatusBar barStyle="default" />
</ScrollView>
);

View File

@@ -3,7 +3,7 @@
*/
import React from 'react';
import { Button, ScrollView, Animated } from 'react-native';
import { Animated, Button, ScrollView, StatusBar } from 'react-native';
import { StackNavigator, TabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
@@ -25,6 +25,7 @@ const MyNavScreen = ({ navigation, banner }) => (
title="Go to settings tab"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</ScrollView>
);

View File

@@ -4,7 +4,8 @@
"private": true,
"main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
"scripts": {
"postinstall": "rm -rf node_modules/react-navigation/{node_modules,examples}",
"postinstall":
"rm -rf node_modules/react-navigation/{node_modules,examples}",
"start": "react-native-scripts start",
"eject": "react-native-scripts eject",
"android": "react-native-scripts android",
@@ -12,29 +13,22 @@
"test": "node node_modules/jest/bin/jest.js"
},
"dependencies": {
"expo": "^23.0.0",
"expo": "^24.0.2",
"react": "16.0.0",
"react-native": "^0.50.3",
"react-native": "^0.51.0",
"react-navigation": "file:../.."
},
"devDependencies": {
"babel-jest": "^21.0.0",
"flow-bin": "^0.56.0",
"jest": "^21.0.1",
"jest-expo": "^23.0.0",
"react-addons-test-utils": "16.0.0-alpha.3",
"jest-expo": "^24.0.0",
"react-native-scripts": "^1.5.0",
"react-test-renderer": "16.0.0-alpha.12"
"react-test-renderer": "16.0.0"
},
"jest": {
"preset": "jest-expo",
"moduleFileExtensions": [
"web.js",
"js",
"json",
"jsx",
"node"
],
"moduleFileExtensions": ["web.js", "js", "json", "jsx", "node"],
"modulePathIgnorePatterns": [
"/node_modules/.*/react-native/",
"/node_modules/.*/react/"

File diff suppressed because it is too large Load Diff

View File

@@ -2,4 +2,4 @@
## Usage
Please see the [Contributors Guide](https://github.com/react-community/react-navigation/blob/master/docs/guides/Contributors.md#development) for instructions on running these example apps.
Please see the [Contributors Guide](https://reactnavigation.org/docs/guides/contributors#Run-the-Example-App) for instructions on running these example apps.

View File

@@ -2,4 +2,4 @@
## Usage
Please see the [Contributors Guide](https://github.com/react-community/react-navigation/blob/master/docs/guides/Contributors.md#development) for instructions on running these example apps.
Please see the [Contributors Guide](https://reactnavigation.org/docs/guides/contributors#Run-the-Example-App) for instructions on running these example apps.

View File

@@ -12,7 +12,7 @@
"icon": "./assets/icons/react-navigation.png",
"hideExponentText": false
},
"sdkVersion": "22.0.0",
"sdkVersion": "23.0.0",
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
"packagerOpts": {
"assetExts": [

View File

@@ -4,7 +4,8 @@
"private": true,
"main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
"scripts": {
"postinstall": "rm -rf node_modules/react-navigation/{node_modules,examples}",
"postinstall":
"rm -rf node_modules/react-navigation/{node_modules,examples}",
"start": "react-native-scripts start",
"eject": "react-native-scripts eject",
"android": "react-native-scripts android",
@@ -35,6 +36,6 @@
"jest-expo": "^23.0.0",
"react-native-scripts": "^1.3.1",
"react-navigation": "file:../..",
"react-test-renderer": "16.0.0-alpha.12"
"react-test-renderer": "16.0.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "react-navigation",
"version": "1.0.0-beta.20",
"version": "1.0.0-beta.25",
"description": "React Navigation",
"main": "src/react-navigation.js",
"sources": {
@@ -55,7 +55,7 @@
"path-to-regexp": "^1.7.0",
"prop-types": "^15.5.10",
"react-native-drawer-layout-polyfill": "^1.3.2",
"react-native-tab-view": "^0.0.70"
"react-native-tab-view": "^0.0.74"
},
"devDependencies": {
"babel-cli": "^6.24.1",

View File

@@ -228,9 +228,9 @@ export type NavigationScreenDetails<T> = {
navigation: NavigationScreenProp<NavigationRoute>,
};
export type NavigationScreenOptions = {|
export type NavigationScreenOptions = {
title?: string,
|};
};
export type NavigationScreenConfigProps = {
navigation: NavigationScreenProp<NavigationRoute>,
@@ -300,6 +300,9 @@ export type HeaderProps = NavigationSceneRendererProps & {
getScreenDetails: NavigationScene => NavigationScreenDetails<
NavigationStackScreenOptions
>,
leftInterpolator: (props: NavigationSceneRendererProps) => {},
titleInterpolator: (props: NavigationSceneRendererProps) => {},
rightInterpolator: (props: NavigationSceneRendererProps) => {},
};
/**
@@ -321,6 +324,7 @@ export type NavigationStackScreenOptions = NavigationScreenOptions & {
headerStyle?: ViewStyleProp,
gesturesEnabled?: boolean,
gestureResponseDistance?: { vertical?: number, horizontal?: number },
gestureDirection?: 'default' | 'inverted',
};
export type NavigationStackRouterConfig = {
@@ -421,6 +425,31 @@ export type NavigationNavigatorProps<O: {}, S: {}> = {
navigationOptions?: O,
};
/**
* Navigation container
*/
export type NavigationContainer<
State: NavigationState,
Options: {},
Props: {}
> = React.ComponentType<NavigationContainerProps<State, Options> & Props> & {
router: NavigationRouter<State, Options>,
navigationOptions?: ?NavigationScreenConfig<Options>,
};
export type NavigationContainerProps<S: {}, O: {}> = {
uriPrefix?: string | RegExp,
onNavigationStateChange?: (
NavigationState,
NavigationState,
NavigationAction
) => void,
navigation?: NavigationScreenProp<S>,
screenProps?: *,
navigationOptions?: O,
};
/**
* Gestures, Animations, and Interpolators
*/
@@ -496,6 +525,11 @@ export type TransitionConfig = {
// How to animate position and opacity of the screen
// based on the value generated by the transitionSpec
screenInterpolator?: (props: NavigationSceneRendererProps) => {},
// How to animate position and opacity of the header componetns
// based on the value generated by the transitionSpec
headerLeftInterpolator?: (props: NavigationSceneRendererProps) => {},
headerTitleInterpolator?: (props: NavigationSceneRendererProps) => {},
headerRightInterpolator?: (props: NavigationSceneRendererProps) => {},
// The style of the container. Useful when a scene doesn't have
// 100% opacity and the underlying container is visible.
containerStyle?: ViewStyleProp,

View File

@@ -13,20 +13,10 @@ import type {
NavigationNavigator,
PossiblyDeprecatedNavigationAction,
NavigationInitAction,
NavigationContainerProps,
NavigationContainer,
} from './TypeDefinition';
type Props<S, O> = {
uriPrefix?: string | RegExp,
onNavigationStateChange?: (
NavigationState,
NavigationState,
NavigationAction
) => void,
navigation?: NavigationScreenProp<S>,
screenProps?: *,
navigationOptions?: O,
};
type State<NavState> = {
nav: ?NavState,
};
@@ -40,15 +30,19 @@ type State<NavState> = {
export default function createNavigationContainer<S: NavigationState, O: {}>(
// Let the NavigationNavigator props flowwwww
Component: NavigationNavigator<S, O, *>
) {
class NavigationContainer extends React.Component<Props<S, O>, State<S>> {
): NavigationContainer<S, O, *> {
class NavigationContainer extends React.Component<
NavigationContainerProps<S, O>,
State<S>
> {
subs: ?{
remove: () => void,
} = null;
static router = Component.router;
static navigationOptions = null;
constructor(props: Props<S, O>) {
constructor(props: NavigationContainerProps<S, O>) {
super(props);
this._validateProps(props);
@@ -64,7 +58,7 @@ export default function createNavigationContainer<S: NavigationState, O: {}>(
return !this.props.navigation;
}
_validateProps(props: Props<S, O>) {
_validateProps(props: NavigationContainerProps<S, O>) {
if (this._isStateful()) {
return;
}
@@ -91,6 +85,8 @@ export default function createNavigationContainer<S: NavigationState, O: {}>(
let path = url.split(delimiter)[1];
if (typeof path === 'undefined') {
path = url;
} else if (path === '') {
path = '/';
}
return {
path,
@@ -142,7 +138,7 @@ export default function createNavigationContainer<S: NavigationState, O: {}>(
}
}
componentWillReceiveProps(nextProps: Props<S, O>) {
componentWillReceiveProps(nextProps: NavigationContainerProps<S, O>) {
this._validateProps(nextProps);
}

View File

@@ -63,6 +63,9 @@ const DefaultDrawerConfig = {
return Math.min(smallerAxisSize - appBarHeight, maxWidth);
},
contentComponent: defaultContentComponent,
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
drawerPosition: 'left',
drawerBackgroundColor: 'white',
useNativeAnimations: true,
@@ -82,6 +85,9 @@ const DrawerNavigator = (
drawerPosition,
useNativeAnimations,
drawerBackgroundColor,
drawerOpenRoute,
drawerCloseRoute,
drawerToggleRoute,
...tabsConfig
} = mergedConfig;
@@ -89,7 +95,7 @@ const DrawerNavigator = (
const drawerRouter = TabRouter(
{
DrawerClose: {
[drawerCloseRoute]: {
screen: createNavigator(
contentRouter,
routeConfigs,
@@ -99,15 +105,15 @@ const DrawerNavigator = (
<DrawerScreen {...props} />
)),
},
DrawerOpen: {
[drawerOpenRoute]: {
screen: () => null,
},
DrawerToggle: {
[drawerToggleRoute]: {
screen: () => null,
},
},
{
initialRouteName: 'DrawerClose',
initialRouteName: drawerCloseRoute,
}
);
@@ -126,6 +132,9 @@ const DrawerNavigator = (
contentComponent={contentComponent}
contentOptions={contentOptions}
drawerPosition={drawerPosition}
drawerOpenRoute={drawerOpenRoute}
drawerCloseRoute={drawerCloseRoute}
drawerToggleRoute={drawerToggleRoute}
/>
));

View File

@@ -49,7 +49,6 @@ const TabNavigator = (
swipeEnabled,
animationEnabled,
configureTransition,
lazy,
initialLayout,
...tabsConfig
} = mergedConfig;
@@ -70,7 +69,6 @@ const TabNavigator = (
swipeEnabled={swipeEnabled}
animationEnabled={animationEnabled}
configureTransition={configureTransition}
lazy={lazy}
initialLayout={initialLayout}
/>
));
@@ -84,7 +82,6 @@ const Presets = {
tabBarPosition: 'bottom',
swipeEnabled: false,
animationEnabled: false,
lazy: false,
initialLayout: undefined,
},
AndroidTopTabs: {
@@ -92,7 +89,6 @@ const Presets = {
tabBarPosition: 'top',
swipeEnabled: true,
animationEnabled: true,
lazy: false,
initialLayout: undefined,
},
};

View File

@@ -137,6 +137,7 @@ exports[`DrawerNavigator renders successfully 1`] = `
}
>
<View
collapsable={undefined}
onLayout={[Function]}
style={
Object {
@@ -182,6 +183,7 @@ exports[`DrawerNavigator renders successfully 1`] = `
tvParallaxProperties={undefined}
>
<View
collapsable={undefined}
onLayout={[Function]}
style={
Object {

View File

@@ -89,6 +89,7 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
"width": 0,
}
}
leftInterpolator={[Function]}
mode="float"
navigation={
Object {
@@ -107,6 +108,7 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
},
}
}
rightInterpolator={[Function]}
router={
Object {
"getActionForPathAndParams": [Function],
@@ -118,9 +120,11 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
"getStateForAction": [Function],
}
}
titleInterpolator={[Function]}
transitionConfig={undefined}
>
<View
collapsable={undefined}
onLayout={[Function]}
style={
Object {
@@ -316,6 +320,7 @@ exports[`StackNavigator renders successfully 1`] = `
"width": 0,
}
}
leftInterpolator={[Function]}
mode="float"
navigation={
Object {
@@ -334,6 +339,7 @@ exports[`StackNavigator renders successfully 1`] = `
},
}
}
rightInterpolator={[Function]}
router={
Object {
"getActionForPathAndParams": [Function],
@@ -345,9 +351,11 @@ exports[`StackNavigator renders successfully 1`] = `
"getStateForAction": [Function],
}
}
titleInterpolator={[Function]}
transitionConfig={undefined}
>
<View
collapsable={undefined}
onLayout={[Function]}
style={
Object {

View File

@@ -69,6 +69,7 @@ exports[`TabNavigator renders successfully 1`] = `
style={undefined}
>
<View
collapsable={undefined}
onLayout={[Function]}
style={
Object {

View File

@@ -61,11 +61,7 @@ export default (
const routes = order.map((routeName: string) => {
const tabRouter = tabRouters[routeName];
if (tabRouter) {
const childAction =
action.action ||
NavigationActions.init({
...(action.params ? { params: action.params } : {}),
});
const childAction = NavigationActions.init();
return {
...tabRouter.getStateForAction(childAction),
key: routeName,
@@ -106,7 +102,7 @@ export default (
const activeTabRouter = tabRouters[order[state.index]];
if (activeTabRouter) {
const activeTabState = activeTabRouter.getStateForAction(
action.action || action,
action,
activeTabLastState
);
if (!activeTabState && inputState) {

View File

@@ -3,9 +3,12 @@
import React from 'react';
import TabRouter from '../TabRouter';
import StackRouter from '../StackRouter';
import NavigationActions from '../../NavigationActions';
import type { NavigationRoute, NavigationState } from '../../TypeDefinition';
const INIT_ACTION = { type: NavigationActions.INIT };
const BareLeafRouteConfig = {
@@ -212,7 +215,6 @@ describe('TabRouter', () => {
const navAction = {
type: NavigationActions.NAVIGATE,
routeName: 'Baz',
params: { foo: '42', bar: '43' },
};
let state = router.getStateForAction(navAction);
expect(state).toEqual({
@@ -224,8 +226,8 @@ describe('TabRouter', () => {
key: 'Baz',
routeName: 'Baz',
routes: [
{ key: 'Boo', routeName: 'Boo', params: { foo: '42', bar: '43' } },
{ key: 'Bar', routeName: 'Bar', params: { foo: '42', bar: '43' } },
{ key: 'Boo', routeName: 'Boo' },
{ key: 'Bar', routeName: 'Bar' },
],
},
],
@@ -245,8 +247,8 @@ describe('TabRouter', () => {
key: 'Baz',
routeName: 'Baz',
routes: [
{ key: 'Boo', routeName: 'Boo', params: { foo: '42', bar: '43' } },
{ key: 'Bar', routeName: 'Bar', params: { foo: '42', bar: '43' } },
{ key: 'Boo', routeName: 'Boo' },
{ key: 'Bar', routeName: 'Bar' },
],
});
});
@@ -604,4 +606,71 @@ describe('TabRouter', () => {
],
});
});
test('Inner actions are only unpacked if the current tab matches', () => {
const PlainScreen = () => <div />;
const ScreenA = () => <div />;
const ScreenB = () => <div />;
ScreenB.router = StackRouter({
Baz: { screen: PlainScreen },
Zoo: { screen: PlainScreen },
});
ScreenA.router = StackRouter({
Bar: { screen: PlainScreen },
Boo: { screen: ScreenB },
});
const router = TabRouter({
Foo: { screen: ScreenA },
});
const screenApreState = {
index: 0,
key: 'Init',
routeName: 'Foo',
routes: [{ key: 'Init', routeName: 'Bar' }],
};
const preState = {
index: 0,
routes: [screenApreState],
};
type ComparableRoute = {
routeName?: string,
routes?: Array<ComparableRoute>,
};
type RouteOrState =
| NavigationRoute
| NavigationState
| (NavigationRoute & NavigationState);
const comparable = (state: RouteOrState): ComparableRoute => {
let result = {};
if (typeof state.routeName === 'string') {
result = { ...result, routeName: state.routeName };
}
if (state.routes instanceof Array) {
result = {
...result,
routes: state.routes.map(comparable),
};
}
return result;
};
const action = NavigationActions.navigate({
routeName: 'Boo',
action: NavigationActions.navigate({ routeName: 'Zoo' }),
});
const expectedState = ScreenA.router.getStateForAction(
action,
screenApreState
);
const state = router.getStateForAction(action, preState);
const innerState = state ? state.routes[0] : state;
expect(expectedState && comparable(expectedState)).toEqual(
innerState && comparable(innerState)
);
});
});

View File

@@ -0,0 +1,12 @@
/* @flow */
import { NativeModules } from 'react-native';
const { PlatformConstants } = NativeModules;
export const supportsImprovedSpringAnimation = () => {
if (PlatformConstants && PlatformConstants.reactNativeVersion) {
const { major, minor } = PlatformConstants.reactNativeVersion;
return minor >= 50 || (major === 0 && minor === 0); // `master` has major + minor set to 0
}
return false;
};

View File

@@ -163,6 +163,11 @@ class CardStack extends React.Component<Props> {
}
const renderHeader = header || ((props: *) => <Header {...props} />);
const {
headerLeftInterpolator,
headerTitleInterpolator,
headerRightInterpolator,
} = this._getTransitionConfig();
// We need to explicitly exclude `mode` since Flow doesn't see
// mode: headerMode override below and reports prop mismatch
@@ -173,6 +178,9 @@ class CardStack extends React.Component<Props> {
scene,
mode: headerMode,
getScreenDetails: this._getScreenDetails,
leftInterpolator: headerLeftInterpolator,
titleInterpolator: headerTitleInterpolator,
rightInterpolator: headerRightInterpolator,
});
}
@@ -232,6 +240,8 @@ class CardStack extends React.Component<Props> {
const { navigation, position, layout, scene, scenes, mode } = this.props;
const { index } = navigation.state;
const isVertical = mode === 'modal';
const { options } = this._getScreenDetails(scene);
const gestureDirectionInverted = options.gestureDirection === 'inverted';
const responder = PanResponder.create({
onPanResponderTerminate: () => {
@@ -262,7 +272,9 @@ class CardStack extends React.Component<Props> {
const axisHasBeenMeasured = !!axisLength;
// Measure the distance from the touch to the edge of the screen
const screenEdgeDistance = currentDragPosition - currentDragDistance;
const screenEdgeDistance = gestureDirectionInverted
? axisLength - (currentDragPosition - currentDragDistance)
: currentDragPosition - currentDragDistance;
// Compare to the gesture distance relavant to card or modal
const {
gestureResponseDistance: userGestureResponseDistance = {},
@@ -294,7 +306,7 @@ class CardStack extends React.Component<Props> {
? layout.height.__getValue()
: layout.width.__getValue();
const currentValue =
I18nManager.isRTL && axis === 'dx'
(I18nManager.isRTL && axis === 'dx') !== gestureDirectionInverted
? startValue + gesture[axis] / axisDistance
: startValue - gesture[axis] / axisDistance;
const value = clamp(index - 1, currentValue, index);
@@ -317,12 +329,19 @@ class CardStack extends React.Component<Props> {
const axisDistance = isVertical
? layout.height.__getValue()
: layout.width.__getValue();
const movedDistance = gesture[isVertical ? 'dy' : 'dx'];
const gestureVelocity = gesture[isVertical ? 'vy' : 'vx'];
const movementDirection = gestureDirectionInverted ? -1 : 1;
const movedDistance =
movementDirection * gesture[isVertical ? 'dy' : 'dx'];
const gestureVelocity =
movementDirection * gesture[isVertical ? 'vy' : 'vx'];
const defaultVelocity = axisDistance / ANIMATION_DURATION;
const velocity = Math.max(Math.abs(gestureVelocity), defaultVelocity);
const resetDuration = movedDistance / velocity;
const goBackDuration = (axisDistance - movedDistance) / velocity;
const resetDuration = gestureDirectionInverted
? (axisDistance - movedDistance) / velocity
: movedDistance / velocity;
const goBackDuration = gestureDirectionInverted
? movedDistance / velocity
: (axisDistance - movedDistance) / velocity;
// To asyncronously get the current animated value, we need to run stopAnimation:
position.stopAnimation((value: number) => {
@@ -348,7 +367,6 @@ class CardStack extends React.Component<Props> {
},
});
const { options } = this._getScreenDetails(scene);
const gesturesEnabled =
typeof options.gesturesEnabled === 'boolean'
? options.gesturesEnabled

View File

@@ -9,12 +9,25 @@ import type {
} from '../../TypeDefinition';
import CardStackStyleInterpolator from './CardStackStyleInterpolator';
import * as ReactNativeFeatures from '../../utils/ReactNativeFeatures';
const IOSTransitionSpec = ({
duration: 500,
easing: Easing.bezier(0.2833, 0.99, 0.31833, 0.99),
timing: Animated.timing,
}: NavigationTransitionSpec);
let IOSTransitionSpec;
if (ReactNativeFeatures.supportsImprovedSpringAnimation()) {
// These are the exact values from UINavigationController's animation configuration
IOSTransitionSpec = ({
timing: Animated.spring,
stiffness: 1000,
damping: 500,
mass: 3,
}: NavigationTransitionSpec);
} else {
// This is an approximation of the IOS spring animation using a derived bezier curve
IOSTransitionSpec = ({
duration: 500,
easing: Easing.bezier(0.2833, 0.99, 0.31833, 0.99),
timing: Animated.timing,
}: NavigationTransitionSpec);
}
// Standard iOS navigation transition
const SlideFromRightIOS = ({

View File

@@ -33,6 +33,9 @@ export type DrawerViewConfig = {
drawerLockMode?: 'unlocked' | 'locked-closed' | 'locked-open',
drawerWidth?: number | (() => number),
drawerPosition?: 'left' | 'right',
drawerOpenRoute?: string,
drawerCloseRoute?: string,
drawerToggleRoute?: string,
contentComponent?: React.ComponentType<*>,
contentOptions?: {},
style?: ViewStyleProp,
@@ -41,11 +44,21 @@ export type DrawerViewConfig = {
screenProps?: {},
};
export type DrawerViewPropsExceptRouter = DrawerViewConfig & {
navigation: NavigationScreenProp<NavigationState>,
};
export type DrawerViewProps = {
drawerLockMode?: 'unlocked' | 'locked-closed' | 'locked-open',
drawerWidth: number | (() => number),
drawerPosition: 'left' | 'right',
drawerOpenRoute: string,
drawerCloseRoute: string,
drawerToggleRoute: string,
contentComponent: React.ComponentType<*>,
contentOptions?: {},
style?: ViewStyleProp,
useNativeAnimations: boolean,
drawerBackgroundColor: string,
screenProps?: {},
export type DrawerViewProps = DrawerViewPropsExceptRouter & {
navigation: NavigationScreenProp<NavigationState>,
router: NavigationRouter<NavigationState, NavigationDrawerScreenOptions>,
};
@@ -81,14 +94,19 @@ export default class DrawerView extends React.PureComponent<
if (
this.props.navigation.state.index !== nextProps.navigation.state.index
) {
const {
drawerOpenRoute,
drawerCloseRoute,
drawerToggleRoute,
} = this.props;
const { routes, index } = nextProps.navigation.state;
if (routes[index].routeName === 'DrawerOpen') {
if (routes[index].routeName === drawerOpenRoute) {
this._drawer.openDrawer();
} else if (routes[index].routeName === 'DrawerToggle') {
if (this._drawer.state.drawerShown) {
this.props.navigation.navigate('DrawerClose');
} else if (routes[index].routeName === drawerToggleRoute) {
if (this.props.navigation.state.index === 0) {
this.props.navigation.navigate(drawerOpenRoute);
} else {
this.props.navigation.navigate('DrawerOpen');
this.props.navigation.navigate(drawerCloseRoute);
}
} else {
this._drawer.closeDrawer();
@@ -100,27 +118,28 @@ export default class DrawerView extends React.PureComponent<
_screenNavigationProp: NavigationScreenProp<NavigationStateRoute>;
_handleDrawerOpen = () => {
const { navigation } = this.props;
const { navigation, drawerOpenRoute } = this.props;
const { routes, index } = navigation.state;
if (routes[index].routeName !== 'DrawerOpen') {
this.props.navigation.navigate('DrawerOpen');
if (routes[index].routeName !== drawerOpenRoute) {
this.props.navigation.navigate(drawerOpenRoute);
}
};
_handleDrawerClose = () => {
const { navigation } = this.props;
const { navigation, drawerCloseRoute } = this.props;
const { routes, index } = navigation.state;
if (routes[index].routeName !== 'DrawerClose') {
this.props.navigation.navigate('DrawerClose');
if (routes[index].routeName !== drawerCloseRoute) {
this.props.navigation.navigate(drawerCloseRoute);
}
};
_updateScreenNavigation = (
navigation: NavigationScreenProp<NavigationState>
) => {
const { drawerCloseRoute } = this.props;
// $FlowFixMe there's no way type the specific shape of the nav state
const navigationState: NavigationStateRoute = navigation.state.routes.find(
(route: *) => route.routeName === 'DrawerClose'
(route: *) => route.routeName === drawerCloseRoute
);
if (
this._screenNavigationProp &&
@@ -146,8 +165,9 @@ export default class DrawerView extends React.PureComponent<
};
_getNavigationState = (navigation: NavigationScreenProp<NavigationState>) => {
const { drawerCloseRoute } = this.props;
const navigationState = navigation.state.routes.find(
(route: *) => route.routeName === 'DrawerClose'
(route: *) => route.routeName === drawerCloseRoute
);
return navigationState;
};
@@ -168,7 +188,7 @@ export default class DrawerView extends React.PureComponent<
render() {
const DrawerScreen = this.props.router.getComponentForRouteName(
'DrawerClose'
this.props.drawerCloseRoute
);
const screenNavigation = addNavigationHelpers({

View File

@@ -49,6 +49,12 @@ const TITLE_OFFSET = Platform.OS === 'ios' ? 70 : 56;
type Props = HeaderProps & { isLandscape: boolean };
class Header extends React.PureComponent<Props, State> {
static defaultProps = {
leftInterpolator: HeaderStyleInterpolator.forLeft,
titleInterpolator: HeaderStyleInterpolator.forCenter,
rightInterpolator: HeaderStyleInterpolator.forRight,
};
static get HEIGHT() {
console.warn(
'Header.HEIGHT is deprecated and will be removed before react-navigation comes out of beta.'
@@ -142,7 +148,10 @@ class Header extends React.PureComponent<Props, State> {
_renderLeftComponent = (props: SceneProps): ?React.Node => {
// $FlowFixMe
const { options } = this.props.getScreenDetails(props.scene);
if (React.isValidElement(options.headerLeft)) {
if (
React.isValidElement(options.headerLeft) ||
options.headerLeft === null
) {
return options.headerLeft;
}
if (props.scene.index === 0) {
@@ -180,7 +189,7 @@ class Header extends React.PureComponent<Props, State> {
props,
'left',
this._renderLeftComponent,
HeaderStyleInterpolator.forLeft
this.props.leftInterpolator
);
}
@@ -207,7 +216,7 @@ class Header extends React.PureComponent<Props, State> {
{ ...props, style },
'title',
this._renderTitleComponent,
HeaderStyleInterpolator.forCenter
this.props.titleInterpolator
);
}
@@ -216,7 +225,7 @@ class Header extends React.PureComponent<Props, State> {
props,
'right',
this._renderRightComponent,
HeaderStyleInterpolator.forRight
this.props.rightInterpolator
);
}

View File

@@ -7,7 +7,7 @@ import {
Platform,
SafeAreaView,
StyleSheet,
View,
Animated,
} from 'react-native';
import withOrientation from './withOrientation';
@@ -101,19 +101,19 @@ class SafeView extends Component {
const { forceInset = false, isLandscape, children, style } = this.props;
if (Platform.OS !== 'ios') {
return <View style={style}>{this.props.children}</View>;
return <Animated.View style={style}>{this.props.children}</Animated.View>;
}
const safeAreaStyle = this._getSafeAreaStyle();
return (
<View
<Animated.View
ref={c => (this.view = c)}
onLayout={this._onLayout}
style={safeAreaStyle}
>
{this.props.children}
</View>
</Animated.View>
);
}
@@ -130,7 +130,7 @@ class SafeView extends Component {
const WIDTH = isLandscape ? X_HEIGHT : X_WIDTH;
const HEIGHT = isLandscape ? X_WIDTH : X_HEIGHT;
this.view.measureInWindow((winX, winY, winWidth, winHeight) => {
this.view._component.measureInWindow((winX, winY, winWidth, winHeight) => {
let realY = winY;
let realX = winX;

View File

@@ -122,8 +122,9 @@ export default class TabBarTop extends React.PureComponent<Props> {
);
};
_handleOnPress = (previousScene: NavigationRoute, scene: TabScene) => {
const { getOnPress, jumpToIndex }: Props = this.props;
_handleOnPress = (scene: TabScene) => {
const { getOnPress, jumpToIndex, navigation }: Props = this.props;
const previousScene = navigation.state.routes[navigation.state.index];
const onPress = getOnPress(previousScene, scene);
if (onPress) {
@@ -136,8 +137,6 @@ export default class TabBarTop extends React.PureComponent<Props> {
render() {
// TODO: Define full proptypes
const props: any = this.props;
const { state } = props.navigation;
const previousScene = state.routes[state.index];
return (
<TabBar

View File

@@ -26,7 +26,6 @@ export type TabViewConfig = {
currentTransitionProps: Object,
nextTransitionProps: Object
) => Object,
lazy?: boolean,
initialLayout?: Layout,
};
@@ -47,7 +46,6 @@ type Props = {
currentTransitionProps: Object,
nextTransitionProps: Object
) => Object,
lazy?: boolean,
initialLayout: Layout,
screenProps?: {},
@@ -171,8 +169,6 @@ class TabView extends React.PureComponent<Props> {
tabBarPosition,
animationEnabled,
configureTransition,
swipeEnabled,
lazy,
initialLayout,
screenProps,
} = this.props;
@@ -190,6 +186,11 @@ class TabView extends React.PureComponent<Props> {
const tabBarVisible =
options.tabBarVisible == null ? true : options.tabBarVisible;
const swipeEnabled =
options.swipeEnabled == null
? this.props.swipeEnabled
: options.swipeEnabled;
if (tabBarComponent !== undefined && tabBarVisible) {
if (tabBarPosition === 'bottom') {
renderFooter = this._renderTabBar;
@@ -206,7 +207,6 @@ class TabView extends React.PureComponent<Props> {
}
const props = {
lazy,
initialLayout,
animationEnabled,
configureTransition,
@@ -221,7 +221,6 @@ class TabView extends React.PureComponent<Props> {
style: styles.container,
};
// $FlowFixMe: mismatch with react-native-tab-view type
return <TabViewAnimated {...props} />;
}
}

View File

@@ -172,12 +172,17 @@ class Transitioner extends React.Component<Props, State> {
// update scenes and play the transition
this._isTransitionRunning = true;
this.setState(nextState, () => {
nextProps.onTransitionStart &&
nextProps.onTransitionStart(
this.setState(nextState, async () => {
if (nextProps.onTransitionStart) {
const result = nextProps.onTransitionStart(
this._transitionProps,
this._prevTransitionProps
);
if (result instanceof Promise) {
await result;
}
}
Animated.parallel(animations).start(this._onTransitionEnd);
});
}
@@ -231,9 +236,18 @@ class Transitioner extends React.Component<Props, State> {
this._transitionProps = buildTransitionProps(this.props, nextState);
this.setState(nextState, () => {
this.props.onTransitionEnd &&
this.props.onTransitionEnd(this._transitionProps, prevTransitionProps);
this.setState(nextState, async () => {
if (this.props.onTransitionEnd) {
const result = this.props.onTransitionEnd(
this._transitionProps,
prevTransitionProps
);
if (result instanceof Promise) {
await result;
}
}
if (this._queuedTransition) {
this._startTransition(
this._queuedTransition.nextProps,

View File

@@ -25,6 +25,7 @@ exports[`TabBarBottom renders successfully 1`] = `
style={undefined}
>
<View
collapsable={undefined}
onLayout={[Function]}
style={
Object {
@@ -133,7 +134,7 @@ exports[`TabBarBottom renders successfully 1`] = `
bounces={false}
contentContainerStyle={
Object {
"flexGrow": 1,
"flex": 1,
}
}
contentOffset={
@@ -163,9 +164,10 @@ exports[`TabBarBottom renders successfully 1`] = `
onTouchEnd={[Function]}
onTouchMove={[Function]}
onTouchStart={[Function]}
overScrollMode="never"
pagingEnabled={true}
scrollEnabled={undefined}
scrollEventThrottle={16}
scrollEventThrottle={1}
scrollsToTop={false}
sendMomentumEvents={true}
showsHorizontalScrollIndicator={false}
@@ -178,7 +180,7 @@ exports[`TabBarBottom renders successfully 1`] = `
"overflow": "scroll",
},
Object {
"flexGrow": 1,
"flex": 1,
},
]
}
@@ -192,7 +194,7 @@ exports[`TabBarBottom renders successfully 1`] = `
"flexDirection": "row",
},
Object {
"flexGrow": 1,
"flex": 1,
},
]
}

View File

@@ -4488,11 +4488,11 @@ react-native-drawer-layout@1.3.2:
dependencies:
react-native-dismiss-keyboard "1.0.0"
react-native-tab-view@^0.0.70:
version "0.0.70"
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-0.0.70.tgz#1dd2ded32acd0cb6bfef38d26e53675db733b37b"
react-native-tab-view@^0.0.74:
version "0.0.74"
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-0.0.74.tgz#62c0c882d9232b461ce181d440d683b4f99d1bd8"
dependencies:
prop-types "^15.5.10"
prop-types "^15.6.0"
react-native-vector-icons@^4.2.0:
version "4.4.2"