mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-26 05:25:30 +08:00
Compare commits
20 Commits
v1.0.0-bet
...
v1.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29e451193d | ||
|
|
36ffc4f31a | ||
|
|
82c2cdbe09 | ||
|
|
3ae4b31a9d | ||
|
|
f84fe15272 | ||
|
|
5576b84d8a | ||
|
|
09e396002f | ||
|
|
2dca5b2135 | ||
|
|
27d496c268 | ||
|
|
df788fd9ac | ||
|
|
e4a7b7e073 | ||
|
|
c08be7fb43 | ||
|
|
81d8d91085 | ||
|
|
5e001155fb | ||
|
|
c1d181eccd | ||
|
|
a8556b0df2 | ||
|
|
c4541f44af | ||
|
|
ef82f1b5ff | ||
|
|
1a62bf7955 | ||
|
|
a79d86b152 |
10
.github/ISSUE_TEMPLATE.md
vendored
10
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,17 +1,16 @@
|
||||
## Before You Start...
|
||||
The issue list is reserved exclusively for bug reports and feature requests. That means we do not accept usage questions.
|
||||
## The issue list is reserved for bugs and feature requests, not for questions.
|
||||
|
||||
For usage questions, please use the following resources:
|
||||
For usage questions, try to:
|
||||
|
||||
- [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)
|
||||
- Also try to 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.
|
||||
- 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.
|
||||
|
||||
---
|
||||
|
||||
### Current Behavior
|
||||
- _If describing a bug, tell us what happens. Provide a screenshot when possible and full code sample_
|
||||
- _If describing a bug, tell us what happens. Please provide a repository with code and steps to reproduce the bug. **Not providing code that other people can run makes is significantly harder to fix your bug.** Provide a screenshot when possible_
|
||||
- _If suggesting a change/improvement, explain the difference from current behavior_
|
||||
|
||||
### Expected Behavior
|
||||
@@ -19,7 +18,6 @@ For usage questions, please use the following resources:
|
||||
- _If you're suggesting a change/improvement, tell us how it should work_
|
||||
|
||||
### Your Environment
|
||||
- _Include as many relevant details about the environment you experienced the bug in_
|
||||
|
||||
| software | version
|
||||
| ---------------- | -------
|
||||
|
||||
162
README.md
162
README.md
@@ -1,63 +1,143 @@
|
||||
# React Navigation [](https://circleci.com/gh/react-community/react-navigation/tree/master) [](https://badge.fury.io/js/react-navigation) [](https://codecov.io/gh/react-community/react-navigation)
|
||||
|
||||
# React Navigation [](https://circleci.com/gh/react-community/react-navigation/tree/master) [](https://badge.fury.io/js/react-navigation) [](https://codecov.io/gh/react-community/react-navigation) [](https://reactnavigation.org/docs/guides/contributors)
|
||||
|
||||
*Learn once, navigate anywhere.*
|
||||
|
||||
Browse the docs on [reactnavigation.org](https://reactnavigation.org/) or try it out on [our expo demo](https://exp.host/@react-navigation/NavigationPlayground).
|
||||
React Navigation is born from the React Native community's need for an extensible yet easy-to-use navigation solution based on Javascript.
|
||||
|
||||
## Motivation
|
||||
React Navigation is the result of a collaboration between developers from Facebook, Expo and the React community at large: it replaces and improves upon several navigation libraries in the ecosystem, including Ex-Navigation, React Native's Navigator and NavigationExperimental components.
|
||||
|
||||
React Navigation is born from the React Native community's need for an
|
||||
extensible yet easy-to-use navigation solution. It replaces and improves
|
||||
upon several navigation libraries in the ecosystem, including Ex-Navigation,
|
||||
React Native's Navigator and NavigationExperimental components. React
|
||||
Navigation can also be used across React and React Native projects allowing
|
||||
for a higher degree of shared code.
|
||||
* [Installation](#installation)
|
||||
* [Community contributions](#community-contributions)
|
||||
* [Introduction to the library](#introduction-to-the-library)
|
||||
* [Basic Tutorials](#basic-tutorials)
|
||||
* [Intermediate Concepts](#intermediate-concepts)
|
||||
* [Advanced Topics](#advanced-topics)
|
||||
* [Comparisons and Discussion](##comparisons-and-discussion)
|
||||
* [Example Projects](#example-projects)
|
||||
* [Libraries](#libraries)
|
||||
* [FAQs](#faqs)
|
||||
* [When is version 1.0.0 going to be released?](#when-is-version-100-going-to-be-released)
|
||||
* [I'm having troubles using the library, what can I do?](#im-having-troubles-using-the-library-what-can-i-do)
|
||||
* [How can I help?](#how-can-i-help)
|
||||
* [Is this the only library available for navigation?](#is-this-the-only-library-available-for-navigation)
|
||||
* [Can I use this library for web?](#can-i-use-this-library-for-web)
|
||||
* [Code of conduct](#code-of-conduct)
|
||||
* [License](#license)
|
||||
|
||||
Once stable, NavigationExperimental will be deprecated in favor of React
|
||||
Navigation. React Navigation is a collaboration between people from
|
||||
Facebook, Exponent and the React community at large.
|
||||
## Installation
|
||||
|
||||
## [Getting started](https://reactnavigation.org/docs/intro/)
|
||||
Since the library is a JS-based solution, to install the latest version of react-navigation you only need to run:
|
||||
|
||||
1. Create a new React Native App
|
||||
```
|
||||
react-native init SimpleApp
|
||||
cd SimpleApp
|
||||
```
|
||||
|
||||
2. Install the latest version of react-navigation from npm
|
||||
```
|
||||
```bash
|
||||
yarn add react-navigation
|
||||
```
|
||||
|
||||
or
|
||||
```
|
||||
|
||||
```bash
|
||||
npm install --save react-navigation
|
||||
```
|
||||
|
||||
3. Run the new app
|
||||
```
|
||||
react-native run-android # or:
|
||||
react-native run-ios
|
||||
```
|
||||
## Get Started
|
||||
|
||||
## Community
|
||||
To learn how the library work, head to the [introduction](https://reactnavigation.org/docs/intro/) on the website for a quick tutorial that will cover all the basics - or try it out [our expo demo](https://exp.host/@react-navigation/NavigationPlayground).
|
||||
|
||||
We have an active channel on the [Reactiflux](https://www.reactiflux.com/) community. It's the best place to show off things you've made with the library, ask for help, or just hang out and discuss the project. This also helps keep the [issues](https://github.com/react-community/react-navigation/issues) manageable.
|
||||
#### Advanced guides
|
||||
|
||||
## Advanced guide
|
||||
* [Redux integration](https://reactnavigation.org/docs/guides/redux)
|
||||
* [Deep linking](https://reactnavigation.org/docs/guides/linking)
|
||||
|
||||
- [Redux integration](https://reactnavigation.org/docs/guides/redux)
|
||||
- [Web integration](https://reactnavigation.org/docs/guides/web)
|
||||
- [Deep linking](https://reactnavigation.org/docs/guides/linking)
|
||||
- [Contributors guide](https://reactnavigation.org/docs/guides/contributors)
|
||||
#### React Navigation API
|
||||
|
||||
## React Navigation API
|
||||
* [Navigators](https://reactnavigation.org/docs/navigators/)
|
||||
* [Routers](https://reactnavigation.org/docs/routers/)
|
||||
* [Views](https://reactnavigation.org/docs/views/)
|
||||
|
||||
- [Navigators](https://reactnavigation.org/docs/navigators/)
|
||||
- [Routers](https://reactnavigation.org/docs/routers/)
|
||||
- [Views](https://reactnavigation.org/docs/views/)
|
||||
## Community contributions
|
||||
|
||||
## Helpful Resources
|
||||
A lot of developers poured their knowledge in blog posts, and other repos - we will try to keep here a list of tutorials and resources to help someone who wants to learn about React Navigation and techniques to handle navigation effectively.
|
||||
|
||||
- [React Navigation Links](https://github.com/react-navigation/react-navigation-links)
|
||||
#### Introduction to the library
|
||||
|
||||
* [Getting Started with React Navigation](https://hackernoon.com/getting-started-with-react-navigation-the-navigation-solution-for-react-native-ea3f4bd786a4)
|
||||
|
||||
#### Basic Tutorials
|
||||
|
||||
* [Basic ReactNavigation Example App and Tutorial](http://docs.nativebase.io/docs/examples/navigation/StackNavigationExample.html)
|
||||
* [Understanding Navigation in React Native](https://www.codementor.io/blessingoraz/understanding-navigation-in-react-native-a3wlcxmzu?published=1#.WXfDlvk_ooE.twitter)
|
||||
* [Comprehensive routing and navigation in React Native made easy](https://medium.com/@kevinle/comprehensive-routing-and-navigation-in-react-native-made-easy-6383e6cdc293)
|
||||
* [Replace a Screen Using React Navigation](https://medium.com/handlebar-labs/replace-a-screen-using-react-navigation-a503eab207eb)
|
||||
|
||||
#### Intermediate Concepts
|
||||
|
||||
* [Using React Navigation and Redux in your React Native Application](https://medium.com/modus-create-front-end-development/using-react-navigation-and-redux-in-your-react-native-application-efac33265138)
|
||||
* [React-Navigation, complete Redux state management, tab-bar, and multiple navigators](https://medium.com/@parkerdan/react-navigation-with-complete-redux-state-management-tab-bar-and-multiple-navigators-ed30a69d9a4d)
|
||||
* [Custom Drawer with React-Navigation in React-Native](http://www.skywardsoftwares.co.in/react-native/custom-drawer-with-react-navigation-in-react-native/)
|
||||
* [React Navigation Drawer - a tutorial series](https://shift.infinite.red/react-navigation-drawer-tutorial-a802fc3ee6dc)
|
||||
|
||||
#### Advanced Topics
|
||||
|
||||
* [Full Stack React Native Development using GraphCool and Apollo Subscriptions + React Navigation](https://medium.com/react-native-training/full-stack-react-native-development-using-graphcool-and-apollo-subscriptions-react-navigation-cdb3e1374c05)
|
||||
|
||||
#### Comparisons and Discussion
|
||||
|
||||
* [Migrate from ExNavigation to React Navigation](https://hackernoon.com/migrate-from-exnavigation-to-react-navigation-1af661ec5082)
|
||||
* [Playing with React Navigation and Airbnb's Native Navigation](https://medium.com/@ericvicenti/playing-with-react-navigation-and-airbnbs-native-navigation-4e49fc765489)
|
||||
* [How we restructured our app with React Navigation](https://m.oursky.com/how-we-restructured-our-app-with-react-navigation-98a89e219c26)
|
||||
* [What’s Happening with Navigation in React Native?](https://blog.revisify.com/whats-happening-with-navigation-in-react-native-c193535888c3)
|
||||
|
||||
#### Example Projects
|
||||
|
||||
* [Yaba-Social](https://github.com/allpwrfulroot/yaba-social)
|
||||
* [React Native Boilerplate with React Navigation and Redux integration](https://github.com/verybluebot/react-native-boilerplate)
|
||||
|
||||
#### Libraries
|
||||
|
||||
* [react-navigation-addons](https://github.com/satya164/react-navigation-addons)
|
||||
* [react-navigation-props-mapper](https://github.com/vonovak/react-navigation-props-mapper)
|
||||
|
||||
## FAQs
|
||||
|
||||
#### When is version 1.0.0 going to be released?
|
||||
|
||||
As soon as all the tasks [here](https://github.com/react-community/react-navigation/issues/2585) have been completed. You can read more about it in the [blog](https://reactnavigation.org/blog/2017/9/Renewed-v1).
|
||||
|
||||
(in the meantime, you can find the changelog for every release [here](https://github.com/react-community/react-navigation/releases))
|
||||
|
||||
#### I'm having troubles using the library, what can I do?
|
||||
|
||||
Head to the [issues](https://github.com/react-community/react-navigation/issues) and do a quick search: if you think you are experiencing a bug chances are somebody already opened an issue for it. If instead you are having more general problems, use [Stack Overflow](https://stackoverflow.com/search?q=react-navigation) - which is better suited and helps keeping the Issues section of the repo clean. Alternatively you could join the [Reactiflux](https://www.reactiflux.com/) community on Discord where there are React Native and React Navigation channels with helpful people who might be able to answer you.
|
||||
|
||||
You should **only** open a new issue if you believe that you are experiencing a bug or have a feature request, and please **follow** the dedicated template - it will help everyone helping you (and may get closed if it doesn't).
|
||||
|
||||
#### How can I help?
|
||||
|
||||
Glad you ask! This library is a community effort: it can only be great if we all help out in one way or another 😄 . If you feel like you aren't experienced enough using react navigation to contribute, you can still make an impact by:
|
||||
|
||||
1. Responding to one of the open [issues](https://github.com/react-community/react-navigation/issues). Even if you can't resolve or fully answer a question, asking for more information or clarity on an issue is extremely beneficial for someone to come after you to resolve the issue.
|
||||
|
||||
1. Creating public example repos of navigation problems you have solved.
|
||||
|
||||
1. Answering questions on [Stack Overflow](https://stackoverflow.com/search?q=react-navigation). Alternatively, asking questions on Stack Overflow instead of opening an issue.
|
||||
|
||||
1. Answering questions in our [Reactiflux](https://www.reactiflux.com/) channel.
|
||||
|
||||
1. Providing feedback on the open [PRs](https://github.com/react-community/react-navigation/pulls).
|
||||
|
||||
If you feel brave enough you can submit a PR: follow the [Contributors guide](https://reactnavigation.org/docs/guides/contributors) to find out how. If you don't know where to start, check the ones with the label [`Type: Good First Task`](https://github.com/react-community/react-navigation/labels/Type%3A%20Good%20First%20Task) - even [fixing a typo in the documentation](https://github.com/react-community/react-navigation/pull/2727) is a worthy contribution!
|
||||
|
||||
#### Is this the only library available for navigation?
|
||||
|
||||
No: there are some other libraries - which, depending on your project, can be better or worse suited for your project. They differ in the approach and implementation from `react-navigation`, but share the common goal of helping you create a good React Native application; you can find a general round up in the [React Native docs](http://facebook.github.io/react-native/docs/navigation.html).
|
||||
|
||||
#### Can I use this library for web?
|
||||
|
||||
This library originally planned to support web too - but at the moment [it is not a priority](https://github.com/react-community/react-navigation/issues/2585#issuecomment-330338793) for v1.0; a lot of work is necessary to reach it as-is and we had to freeze this support (consider it ["experimental"](https://reactnavigation.org/docs/guides/web)).
|
||||
|
||||
## Code of conduct
|
||||
|
||||
This library has adopted a Code of Conduct that we expect project participants to adhere to. Please read the [full text](https://github.com/react-community/react-navigation/blob/master/CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated.
|
||||
|
||||
## License
|
||||
|
||||
React-navigation is licensed under the [BSD 2-clause "Simplified" License](https://github.com/react-community/react-navigation/blob/master/LICENSE).
|
||||
@@ -87,11 +87,12 @@ The route configs object is a mapping from route name to a route config, which t
|
||||
|
||||
|
||||
### DrawerNavigatorConfig
|
||||
- `drawerWidth` - Width of the drawer
|
||||
- `drawerWidth` - Width of the drawer.
|
||||
- `drawerPosition` - Options are `left` or `right`. Default is `left` position.
|
||||
- `contentComponent` - Component used to render the content of the drawer, for example, navigation items. Receives the `navigation` prop for the drawer. Defaults to `DrawerItems`. For more information, see below.
|
||||
- `contentOptions` - Configure the drawer content, see below.
|
||||
- `useNativeAnimations` - Enable native animations. Default is `true`.
|
||||
- `drawerBackgroundColor` - Use the Drawer background for some color. The Default is `white`.
|
||||
|
||||
#### Example:
|
||||
|
||||
@@ -103,7 +104,8 @@ as you can see in the example below.
|
||||
{
|
||||
drawerWidth: 200,
|
||||
drawerPosition: 'right',
|
||||
contentComponent: props => <ScrollView><DrawerItems {...props} /></ScrollView>
|
||||
contentComponent: props => <ScrollView><DrawerItems {...props} /></ScrollView>,
|
||||
drawerBackgroundColor: 'transparent'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -173,7 +175,7 @@ React Element or a function, that given `{ focused: boolean, tintColor: string }
|
||||
|
||||
#### `drawerLockMode`
|
||||
|
||||
Specifies the [lock mode](https://facebook.github.io/react-native/docs/drawerlayoutandroid.html#drawerlockmode) of the drawer. This can also update dynamically by using screenProps.lockMode on your top level router.
|
||||
Specifies the [lock mode](https://facebook.github.io/react-native/docs/drawerlayoutandroid.html#drawerlockmode) of the drawer. This can also update dynamically by using screenProps.drawerLockMode on your top level router.
|
||||
|
||||
### Navigator Props
|
||||
|
||||
|
||||
@@ -104,6 +104,10 @@ React Element or a function that given `HeaderProps` returns a React Element, to
|
||||
|
||||
String or React Element used by the header. Defaults to scene `title`
|
||||
|
||||
#### `headerTitleAllowFontScaling`
|
||||
|
||||
Whether header title font should scale to respect Text Size accessibility settings. Defaults to true
|
||||
|
||||
#### `headerBackTitle`
|
||||
|
||||
Title string used by the back button on iOS, or `null` to disable label. Defaults to the previous scene's `headerTitle`
|
||||
@@ -173,3 +177,45 @@ The navigator component created by `StackNavigator(...)` takes the following pro
|
||||
See the examples [SimpleStack.js](https://github.com/react-community/react-navigation/tree/master/examples/NavigationPlayground/js/SimpleStack.js) and [ModalStack.js](https://github.com/react-community/react-navigation/tree/master/examples/NavigationPlayground/js/ModalStack.js) which you can run locally as part of the [NavigationPlayground](https://github.com/react-community/react-navigation/tree/master/examples/NavigationPlayground) app.
|
||||
|
||||
You can view these examples directly on your phone by visiting [our expo demo](https://exp.host/@react-navigation/NavigationPlayground).
|
||||
|
||||
#### Modal StackNavigator with Custom Screen Transitions
|
||||
|
||||
```js
|
||||
const ModalNavigator = StackNavigator(
|
||||
{
|
||||
Main: { screen: Main },
|
||||
Login: { screen: Login },
|
||||
},
|
||||
{
|
||||
headerMode: 'none',
|
||||
mode: 'modal',
|
||||
navigationOptions: {
|
||||
gesturesEnabled: false,
|
||||
},
|
||||
transitionConfig: () => ({
|
||||
transitionSpec: {
|
||||
duration: 300,
|
||||
easing: Easing.out(Easing.poly(4)),
|
||||
timing: Animated.timing,
|
||||
},
|
||||
screenInterpolator: sceneProps => {
|
||||
const { layout, position, scene } = sceneProps;
|
||||
const { index } = scene;
|
||||
|
||||
const height = layout.initHeight;
|
||||
const translateY = position.interpolate({
|
||||
inputRange: [index - 1, index, index + 1],
|
||||
outputRange: [height, 0, 0],
|
||||
});
|
||||
|
||||
const opacity = position.interpolate({
|
||||
inputRange: [index - 1, index - 0.99, index],
|
||||
outputRange: [0, 1, 1],
|
||||
});
|
||||
|
||||
return { opacity, transform: [{ translateY }] };
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
@@ -107,6 +107,7 @@ Several options get passed to the underlying router to modify navigation logic:
|
||||
- `style` - style object for the tab bar
|
||||
- `labelStyle` - style object for the tab label
|
||||
- `tabStyle` - style object for the tab
|
||||
- `allowFontScaling` - whether label font should scale to respect Text Size accessibility settings, default is true
|
||||
|
||||
Example:
|
||||
|
||||
@@ -137,6 +138,7 @@ tabBarOptions: {
|
||||
- `labelStyle` - style object for the tab label
|
||||
- `iconStyle` - style object for the tab icon
|
||||
- `style` - style object for the tab bar
|
||||
- `allowFontScaling` - whether label font should scale to respect Text Size accessibility settings, default is true
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ MyApp.router.getStateForAction = (action, state) => {
|
||||
Sometimes you may want to prevent some navigation activity, depending on your route.
|
||||
|
||||
```js
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
const MyStackRouter = StackRouter({
|
||||
Home: { screen: HomeScreen },
|
||||
Profile: { screen: ProfileScreen },
|
||||
|
||||
@@ -6,7 +6,6 @@ Let's use React Navigation to build a simple chat application for Android and iO
|
||||
|
||||
First, make sure you're [all set up to use React Native](http://facebook.github.io/react-native/docs/getting-started.html). Next, create a new project and add `react-navigation`:
|
||||
|
||||
|
||||
```sh
|
||||
# Create a new React Native App
|
||||
react-native init SimpleApp
|
||||
@@ -16,11 +15,13 @@ cd SimpleApp
|
||||
npm install --save react-navigation
|
||||
|
||||
# Run the new app
|
||||
react-native run-android # or:
|
||||
react-native run-android
|
||||
# or:
|
||||
react-native run-ios
|
||||
```
|
||||
|
||||
If you are using `create-react-native-app` instead of `react-native init`, then:
|
||||
|
||||
```sh
|
||||
# Create a new React Native App
|
||||
create-react-native-app SimpleApp
|
||||
@@ -41,13 +42,11 @@ Verify that you can successfully see the bare sample app run on iOS and/or Andro
|
||||
bare-project
|
||||
```
|
||||
|
||||
We want to share code on iOS and Android, so lets delete the contents of `index.ios.js` and `index.android.js` and replace it with `import './App';`.
|
||||
|
||||
Now lets create the new file for our app implementation, `App.js`.
|
||||
We want to share code on iOS and Android, so let's delete the contents of `index.ios.js` and `index.android.js` and replace it with `import './App';` - after which, we need to create the new file for our app implementation, `App.js` (if you used `create-react-native-app` this has been already done)
|
||||
|
||||
## Introducing Stack Navigator
|
||||
|
||||
For our app, we want to use the `StackNavigator` because we want a conceptual 'stack' navigation, where each new screen is put on the top of the stack and going back removes a screen from the top of the stack. Let's start with just one screen:
|
||||
For our app, we want to use the `StackNavigator` because conceptually we want to obtain a 'card stack' effect of movement, where each new screen is put on the top of the stack and going back removes a screen from the top of the stack. Let's start with just one screen:
|
||||
|
||||
```js
|
||||
import React from 'react';
|
||||
@@ -66,14 +65,50 @@ class HomeScreen extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default const SimpleApp = StackNavigator({
|
||||
export const SimpleApp = StackNavigator({
|
||||
Home: { screen: HomeScreen },
|
||||
});
|
||||
|
||||
// if you are using create-react-native-app you don't need this line
|
||||
AppRegistry.registerComponent('SimpleApp', () => SimpleApp);
|
||||
```
|
||||
|
||||
If you used `create-react-native-app` the already existing `App.js` will be modified to
|
||||
|
||||
```js
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { StackNavigator } from 'react-navigation';
|
||||
|
||||
class HomeScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Welcome'
|
||||
};
|
||||
render() {
|
||||
return <Text>Hello, Navigation!</Text>;
|
||||
}
|
||||
}
|
||||
|
||||
const SimpleApp = StackNavigator({
|
||||
Home: { screen: HomeScreen }
|
||||
});
|
||||
|
||||
export default class App extends React.Component {
|
||||
render() {
|
||||
return <SimpleApp />;
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
The `title` of the screen is configurable on the [static `navigationOptions`](/docs/navigators/navigation-options), where many options can be set to configure the presentation of the screen in the navigator.
|
||||
|
||||
Now the same screen should appear on both iPhone and Android apps:
|
||||
@@ -84,9 +119,15 @@ first-screen
|
||||
|
||||
## Adding a New Screen
|
||||
|
||||
In our `App.js` file, let's add a new screen called `ChatScreen`:
|
||||
In our `App.js` file, let's add a new screen called `ChatScreen`, defining it under `HomeScreen`:
|
||||
|
||||
```js
|
||||
// ...
|
||||
|
||||
class HomeScreen extends React.Component {
|
||||
//...
|
||||
}
|
||||
|
||||
class ChatScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Chat with Lucy',
|
||||
@@ -99,9 +140,10 @@ class ChatScreen extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
We can then add a button to our `HomeScreen` component that links to `ChatScreen` using the `routeName` `Chat`.
|
||||
We can then add a button to our `HomeScreen` component that links to `ChatScreen`: we need to use the provided method `navigate` (from the [screen navigation prop](/docs/navigators/navigation-prop)) by giving it the `routeName` of the screen we want to reach, in this case `Chat`.
|
||||
|
||||
```js
|
||||
class HomeScreen extends React.Component {
|
||||
@@ -123,10 +165,12 @@ class HomeScreen extends React.Component {
|
||||
}
|
||||
```
|
||||
|
||||
We're using the navigate function from the [screen navigation prop](/docs/navigators/navigation-prop) to go to `ChatScreen`. But that won't work until we add this to our `StackNavigator` like so:
|
||||
(*don't forget to import View and Button from react-native: * `import { AppRegistry, Text, View, Button } from 'react-native';`)
|
||||
|
||||
But that won't work until we say to our `StackNavigator` of the existence of the `Chat` screen, like so:
|
||||
|
||||
```js
|
||||
export default const SimpleApp = StackNavigator({
|
||||
export const SimpleApp = StackNavigator({
|
||||
Home: { screen: HomeScreen },
|
||||
Chat: { screen: ChatScreen },
|
||||
});
|
||||
|
||||
@@ -90,6 +90,8 @@ const SimpleApp = StackNavigator({
|
||||
```
|
||||
In this case, the NavigatorWrappingScreen is not a navigator, but it renders a navigator as part of its output.
|
||||
|
||||
If this navigator renders blank then change `<View>` to `<View style={{flex: 1}}>`.
|
||||
|
||||
```js
|
||||
class NavigatorWrappingScreen extends React.Component {
|
||||
render() {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"icon": "./assets/icons/react-navigation.png",
|
||||
"hideExponentText": false
|
||||
},
|
||||
"sdkVersion": "20.0.0",
|
||||
"sdkVersion": "21.0.0",
|
||||
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||
"packagerOpts": {
|
||||
"assetExts": [
|
||||
|
||||
@@ -28,6 +28,10 @@ const MyHomeScreen = ({ navigation }) => (
|
||||
);
|
||||
|
||||
MyHomeScreen.navigationOptions = {
|
||||
tabBarTestIDProps: {
|
||||
testID: 'TEST_ID_HOME',
|
||||
accessibilityLabel: 'TEST_ID_HOME_ACLBL',
|
||||
},
|
||||
tabBarLabel: 'Home',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"test": "node node_modules/jest/bin/jest.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"expo": "^20.1.2",
|
||||
"expo": "^21.0.1",
|
||||
"react": "16.0.0-alpha.12",
|
||||
"react-native": "~0.48.4",
|
||||
"react-navigation": "file:../.."
|
||||
@@ -21,7 +21,7 @@
|
||||
"babel-jest": "^21.0.0",
|
||||
"flow-bin": "^0.51.0",
|
||||
"jest": "^21.0.1",
|
||||
"jest-expo": "^20.0.0",
|
||||
"jest-expo": "^21.0.0",
|
||||
"react-addons-test-utils": "16.0.0-alpha.3",
|
||||
"react-native-scripts": "^1.3.1",
|
||||
"react-test-renderer": "16.0.0-alpha.12"
|
||||
|
||||
@@ -1904,25 +1904,26 @@ expect@^21.0.0:
|
||||
jest-message-util "^21.0.0"
|
||||
jest-regex-util "^21.0.0"
|
||||
|
||||
expo@^20.1.2:
|
||||
version "20.1.2"
|
||||
resolved "https://registry.yarnpkg.com/expo/-/expo-20.1.2.tgz#bac5723693bdfdd30aa003df7b05d06ee5459d5f"
|
||||
expo@^21.0.1:
|
||||
version "21.0.2"
|
||||
resolved "https://registry.yarnpkg.com/expo/-/expo-21.0.2.tgz#8420b9f4b95503c464575a31fd9c820363caef9d"
|
||||
dependencies:
|
||||
"@expo/vector-icons" "^5.0.0"
|
||||
babel-preset-expo "^3.0.0"
|
||||
fbemitter "^2.1.1"
|
||||
lodash.map "^4.6.0"
|
||||
lodash.zipobject "^4.1.3"
|
||||
lottie-react-native "1.1.1"
|
||||
lottie-react-native "2.2.0"
|
||||
md5-file "^3.1.1"
|
||||
pretty-format "^20.0.3"
|
||||
prop-types "^15.5.10"
|
||||
qs "^6.5.0"
|
||||
react-native-branch "2.0.0-beta.3"
|
||||
react-native-gesture-handler "^1.0.0-alpha.14"
|
||||
react-native-gesture-handler "1.0.0-alpha.22"
|
||||
react-native-maps "0.15.3"
|
||||
react-native-svg "5.3.0"
|
||||
uuid-js "^0.7.5"
|
||||
websql expo/node-websql#18.0.0
|
||||
websql "https://github.com/expo/node-websql/archive/18.0.0.tar.gz"
|
||||
|
||||
express-session@~1.11.3:
|
||||
version "1.11.3"
|
||||
@@ -3066,9 +3067,9 @@ jest-environment-node@^21.0.0:
|
||||
jest-mock "^21.0.0"
|
||||
jest-util "^21.0.0"
|
||||
|
||||
jest-expo@^20.0.0:
|
||||
version "20.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-expo/-/jest-expo-20.0.0.tgz#fc925bb8ecca56b410b5129d70407aa743e311b6"
|
||||
jest-expo@^21.0.0:
|
||||
version "21.0.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-expo/-/jest-expo-21.0.2.tgz#87c60deda29a9c67d5c59f24e7104aff6ce0aaee"
|
||||
dependencies:
|
||||
babel-jest "^20.0.3"
|
||||
jest "^20.0.4"
|
||||
@@ -3720,16 +3721,17 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
|
||||
dependencies:
|
||||
js-tokens "^3.0.0"
|
||||
|
||||
lottie-ios@^1.5.2:
|
||||
version "1.5.2"
|
||||
resolved "https://registry.yarnpkg.com/lottie-ios/-/lottie-ios-1.5.2.tgz#c188f1baa1c308a291538fc585a76e0cfc060711"
|
||||
lottie-ios@^2.0.5:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/lottie-ios/-/lottie-ios-2.1.3.tgz#57b2328511a26606dc6de7a74bbdbf77f92c6aa0"
|
||||
|
||||
lottie-react-native@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lottie-react-native/-/lottie-react-native-1.1.1.tgz#1c87a3afca96edfa0869227140a2cff9bcc62c9b"
|
||||
lottie-react-native@2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lottie-react-native/-/lottie-react-native-2.2.0.tgz#18196806ef6546cd3e01b24fc5a5974f02e4f017"
|
||||
dependencies:
|
||||
invariant "^2.2.2"
|
||||
lottie-ios "^1.5.2"
|
||||
lottie-ios "^2.0.5"
|
||||
prop-types "^15.5.10"
|
||||
react-native-safe-module "^1.1.0"
|
||||
|
||||
lower-case-first@^1.0.0:
|
||||
@@ -4534,6 +4536,10 @@ qs@6.5.0, qs@^6.2.1, qs@^6.4.0:
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49"
|
||||
|
||||
qs@^6.5.0:
|
||||
version "6.5.1"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
|
||||
|
||||
querystring@0.2.0, querystring@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
|
||||
@@ -4648,9 +4654,11 @@ react-native-drawer-layout@1.3.2:
|
||||
dependencies:
|
||||
react-native-dismiss-keyboard "1.0.0"
|
||||
|
||||
react-native-gesture-handler@^1.0.0-alpha.14:
|
||||
version "1.0.0-alpha.17"
|
||||
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.0.0-alpha.17.tgz#1ae4412e1b208d175b34a14931d0635064a92e7b"
|
||||
react-native-gesture-handler@1.0.0-alpha.22:
|
||||
version "1.0.0-alpha.22"
|
||||
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.0.0-alpha.22.tgz#96e5ae08b26a9e99d115f6e16f63d7487ef995fc"
|
||||
dependencies:
|
||||
prop-types "^15.5.10"
|
||||
|
||||
react-native-maps@0.15.3:
|
||||
version "0.15.3"
|
||||
@@ -4791,7 +4799,7 @@ react-native@~0.48.4:
|
||||
yargs "^6.4.0"
|
||||
|
||||
"react-navigation@file:../..":
|
||||
version "1.0.0-beta.12"
|
||||
version "1.0.0-beta.13"
|
||||
dependencies:
|
||||
babel-plugin-transform-define "^1.3.0"
|
||||
clamp "^1.0.1"
|
||||
@@ -5914,9 +5922,9 @@ webidl-conversions@^4.0.0:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||
|
||||
websql@expo/node-websql#18.0.0:
|
||||
"websql@https://github.com/expo/node-websql/archive/18.0.0.tar.gz":
|
||||
version "0.4.4"
|
||||
resolved "https://codeload.github.com/expo/node-websql/tar.gz/e364fa65146a9e2157a19e5c719e7702c2b6b87a"
|
||||
resolved "https://github.com/expo/node-websql/archive/18.0.0.tar.gz#39b12a08b0180495de1412d8a64a529e21ad554e"
|
||||
dependencies:
|
||||
argsarray "^0.0.1"
|
||||
immediate "^3.2.2"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"icon": "./assets/icons/react-navigation.png",
|
||||
"hideExponentText": false
|
||||
},
|
||||
"sdkVersion": "20.0.0",
|
||||
"sdkVersion": "21.0.0",
|
||||
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||
"packagerOpts": {
|
||||
"assetExts": [
|
||||
|
||||
@@ -22,17 +22,17 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"expo": "^20.1.2",
|
||||
"expo": "^21.0.1",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "16.0.0-alpha.12",
|
||||
"react-native": "~0.47.2",
|
||||
"react-native": "~0.48.4",
|
||||
"react-redux": "^5.0.6",
|
||||
"redux": "^3.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-jest": "^21.0.0",
|
||||
"jest": "^21.0.1",
|
||||
"jest-expo": "^20.0.0",
|
||||
"jest-expo": "^21.0.0",
|
||||
"react-native-scripts": "^1.3.1",
|
||||
"react-navigation": "file:../..",
|
||||
"react-test-renderer": "16.0.0-alpha.12"
|
||||
|
||||
@@ -898,7 +898,7 @@ babel-preset-fbjs@^1.0.0:
|
||||
babel-plugin-transform-object-rest-spread "^6.6.5"
|
||||
object-assign "^4.0.1"
|
||||
|
||||
babel-preset-fbjs@^2.1.0, babel-preset-fbjs@^2.1.4:
|
||||
babel-preset-fbjs@^2.1.4:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-2.1.4.tgz#22f358e6654073acf61e47a052a777d7bccf03af"
|
||||
dependencies:
|
||||
@@ -949,40 +949,6 @@ babel-preset-jest@^21.0.0:
|
||||
dependencies:
|
||||
babel-plugin-jest-hoist "^21.0.0"
|
||||
|
||||
babel-preset-react-native@^1.9.1:
|
||||
version "1.9.2"
|
||||
resolved "https://registry.yarnpkg.com/babel-preset-react-native/-/babel-preset-react-native-1.9.2.tgz#b22addd2e355ff3b39671b79be807e52dfa145f2"
|
||||
dependencies:
|
||||
babel-plugin-check-es2015-constants "^6.5.0"
|
||||
babel-plugin-react-transform "2.0.2"
|
||||
babel-plugin-syntax-async-functions "^6.5.0"
|
||||
babel-plugin-syntax-class-properties "^6.5.0"
|
||||
babel-plugin-syntax-flow "^6.5.0"
|
||||
babel-plugin-syntax-jsx "^6.5.0"
|
||||
babel-plugin-syntax-trailing-function-commas "^6.5.0"
|
||||
babel-plugin-transform-class-properties "^6.5.0"
|
||||
babel-plugin-transform-es2015-arrow-functions "^6.5.0"
|
||||
babel-plugin-transform-es2015-block-scoping "^6.5.0"
|
||||
babel-plugin-transform-es2015-classes "^6.5.0"
|
||||
babel-plugin-transform-es2015-computed-properties "^6.5.0"
|
||||
babel-plugin-transform-es2015-destructuring "^6.5.0"
|
||||
babel-plugin-transform-es2015-for-of "^6.5.0"
|
||||
babel-plugin-transform-es2015-function-name "^6.5.0"
|
||||
babel-plugin-transform-es2015-literals "^6.5.0"
|
||||
babel-plugin-transform-es2015-modules-commonjs "^6.5.0"
|
||||
babel-plugin-transform-es2015-parameters "^6.5.0"
|
||||
babel-plugin-transform-es2015-shorthand-properties "^6.5.0"
|
||||
babel-plugin-transform-es2015-spread "^6.5.0"
|
||||
babel-plugin-transform-es2015-template-literals "^6.5.0"
|
||||
babel-plugin-transform-flow-strip-types "^6.5.0"
|
||||
babel-plugin-transform-object-assign "^6.5.0"
|
||||
babel-plugin-transform-object-rest-spread "^6.5.0"
|
||||
babel-plugin-transform-react-display-name "^6.5.0"
|
||||
babel-plugin-transform-react-jsx "^6.5.0"
|
||||
babel-plugin-transform-react-jsx-source "^6.5.0"
|
||||
babel-plugin-transform-regenerator "^6.5.0"
|
||||
react-transform-hmr "^1.0.4"
|
||||
|
||||
babel-preset-react-native@^2.0.0, babel-preset-react-native@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-preset-react-native/-/babel-preset-react-native-2.1.0.tgz#9013ebd82da1c88102bf588810ff59e209ca2b8a"
|
||||
@@ -1805,6 +1771,14 @@ encoding@^0.1.11:
|
||||
dependencies:
|
||||
iconv-lite "~0.4.13"
|
||||
|
||||
envinfo@^3.0.0:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-3.4.1.tgz#8c80e9f2eec2cd4e2adb2c5d0127ce07a2aaa2ae"
|
||||
dependencies:
|
||||
minimist "^1.2.0"
|
||||
os-name "^2.0.1"
|
||||
which "^1.2.14"
|
||||
|
||||
"errno@>=0.1.1 <0.2.0-0", errno@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
|
||||
@@ -1930,25 +1904,26 @@ expect@^21.0.0:
|
||||
jest-message-util "^21.0.0"
|
||||
jest-regex-util "^21.0.0"
|
||||
|
||||
expo@^20.1.2:
|
||||
version "20.1.2"
|
||||
resolved "https://registry.yarnpkg.com/expo/-/expo-20.1.2.tgz#bac5723693bdfdd30aa003df7b05d06ee5459d5f"
|
||||
expo@^21.0.1:
|
||||
version "21.0.1"
|
||||
resolved "https://registry.yarnpkg.com/expo/-/expo-21.0.1.tgz#c0e9da91041cf974a9157db6a4d9e8ac95755bc7"
|
||||
dependencies:
|
||||
"@expo/vector-icons" "^5.0.0"
|
||||
babel-preset-expo "^3.0.0"
|
||||
fbemitter "^2.1.1"
|
||||
lodash.map "^4.6.0"
|
||||
lodash.zipobject "^4.1.3"
|
||||
lottie-react-native "1.1.1"
|
||||
lottie-react-native "2.2.0"
|
||||
md5-file "^3.1.1"
|
||||
pretty-format "^20.0.3"
|
||||
prop-types "^15.5.10"
|
||||
qs "^6.5.0"
|
||||
react-native-branch "2.0.0-beta.3"
|
||||
react-native-gesture-handler "^1.0.0-alpha.14"
|
||||
react-native-gesture-handler "1.0.0-alpha.22"
|
||||
react-native-maps "0.15.3"
|
||||
react-native-svg "5.3.0"
|
||||
uuid-js "^0.7.5"
|
||||
websql expo/node-websql#18.0.0
|
||||
websql "https://github.com/expo/node-websql/archive/18.0.0.tar.gz"
|
||||
|
||||
express-session@~1.11.3:
|
||||
version "1.11.3"
|
||||
@@ -2603,9 +2578,9 @@ iconv-lite@0.4.18, iconv-lite@^0.4.17, iconv-lite@~0.4.13:
|
||||
version "0.4.18"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2"
|
||||
|
||||
image-size@^0.3.5:
|
||||
version "0.3.5"
|
||||
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.3.5.tgz#83240eab2fb5b00b04aab8c74b0471e9cba7ad8c"
|
||||
image-size@^0.6.0:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.6.1.tgz#98122a562d59dcc097ef1b2c8191866eb8f5d663"
|
||||
|
||||
immediate@^3.2.2:
|
||||
version "3.2.3"
|
||||
@@ -3038,11 +3013,19 @@ jest-diff@^21.0.0:
|
||||
jest-get-type "^21.0.0"
|
||||
pretty-format "^21.0.0"
|
||||
|
||||
jest-docblock@20.1.0-chi.1:
|
||||
version "20.1.0-chi.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-20.1.0-chi.1.tgz#06981ab0e59498a2492333b0c5502a82e4603207"
|
||||
|
||||
jest-docblock@20.1.0-delta.4:
|
||||
version "20.1.0-delta.4"
|
||||
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-20.1.0-delta.4.tgz#360d4f5fb702730c4136c4e71e5706188a694682"
|
||||
|
||||
jest-docblock@^20.0.3:
|
||||
version "20.0.3"
|
||||
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-20.0.3.tgz#17bea984342cc33d83c50fbe1545ea0efaa44712"
|
||||
|
||||
jest-docblock@^20.1.0-alpha.3:
|
||||
jest-docblock@^20.1.0-chi.1:
|
||||
version "20.1.0-echo.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-20.1.0-echo.1.tgz#be02f43ee019f97e6b83267c746ac7b40d290fe8"
|
||||
|
||||
@@ -3080,9 +3063,9 @@ jest-environment-node@^21.0.0:
|
||||
jest-mock "^21.0.0"
|
||||
jest-util "^21.0.0"
|
||||
|
||||
jest-expo@^20.0.0:
|
||||
version "20.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-expo/-/jest-expo-20.0.0.tgz#fc925bb8ecca56b410b5129d70407aa743e311b6"
|
||||
jest-expo@^21.0.0:
|
||||
version "21.0.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-expo/-/jest-expo-21.0.2.tgz#87c60deda29a9c67d5c59f24e7104aff6ce0aaee"
|
||||
dependencies:
|
||||
babel-jest "^20.0.3"
|
||||
jest "^20.0.4"
|
||||
@@ -3092,13 +3075,24 @@ jest-get-type@^21.0.0:
|
||||
version "21.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-21.0.0.tgz#ed8667533c0a24a4feebbf492661f23abac3620b"
|
||||
|
||||
jest-haste-map@20.1.0-alpha.3:
|
||||
version "20.1.0-alpha.3"
|
||||
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-20.1.0-alpha.3.tgz#37a1eea267cd770b99114a39c049a287501edf72"
|
||||
jest-haste-map@20.1.0-chi.1:
|
||||
version "20.1.0-chi.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-20.1.0-chi.1.tgz#db5f5f31362c76e242b40ea9a3ccfa364719cee3"
|
||||
dependencies:
|
||||
fb-watchman "^2.0.0"
|
||||
graceful-fs "^4.1.11"
|
||||
jest-docblock "^20.1.0-alpha.3"
|
||||
jest-docblock "^20.1.0-chi.1"
|
||||
micromatch "^2.3.11"
|
||||
sane "^2.0.0"
|
||||
worker-farm "^1.3.1"
|
||||
|
||||
jest-haste-map@20.1.0-delta.4:
|
||||
version "20.1.0-delta.4"
|
||||
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-20.1.0-delta.4.tgz#12e32b297a6dd49705cacde938029fc158834006"
|
||||
dependencies:
|
||||
fb-watchman "^2.0.0"
|
||||
graceful-fs "^4.1.11"
|
||||
jest-docblock "20.1.0-delta.4"
|
||||
micromatch "^2.3.11"
|
||||
sane "^2.0.0"
|
||||
worker-farm "^1.3.1"
|
||||
@@ -3723,16 +3717,17 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
|
||||
dependencies:
|
||||
js-tokens "^3.0.0"
|
||||
|
||||
lottie-ios@^1.5.2:
|
||||
version "1.5.2"
|
||||
resolved "https://registry.yarnpkg.com/lottie-ios/-/lottie-ios-1.5.2.tgz#c188f1baa1c308a291538fc585a76e0cfc060711"
|
||||
lottie-ios@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/lottie-ios/-/lottie-ios-2.0.5.tgz#3da0871e981f5621c633296eab0d9cf2340c0bcd"
|
||||
|
||||
lottie-react-native@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lottie-react-native/-/lottie-react-native-1.1.1.tgz#1c87a3afca96edfa0869227140a2cff9bcc62c9b"
|
||||
lottie-react-native@2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lottie-react-native/-/lottie-react-native-2.2.0.tgz#18196806ef6546cd3e01b24fc5a5974f02e4f017"
|
||||
dependencies:
|
||||
invariant "^2.2.2"
|
||||
lottie-ios "^1.5.2"
|
||||
lottie-ios "^2.0.5"
|
||||
prop-types "^15.5.10"
|
||||
react-native-safe-module "^1.1.0"
|
||||
|
||||
lower-case-first@^1.0.0:
|
||||
@@ -3764,6 +3759,10 @@ lsmod@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lsmod/-/lsmod-1.0.0.tgz#9a00f76dca36eb23fa05350afe1b585d4299e64b"
|
||||
|
||||
macos-release@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-1.1.0.tgz#831945e29365b470aa8724b0ab36c8f8959d10fb"
|
||||
|
||||
makeerror@1.0.x:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
|
||||
@@ -3817,9 +3816,9 @@ methods@^1.1.1, methods@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
||||
|
||||
metro-bundler@^0.9.0:
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/metro-bundler/-/metro-bundler-0.9.2.tgz#a23c1e0c28fc920f4280980dc7c3bb54e51d0240"
|
||||
metro-bundler@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/metro-bundler/-/metro-bundler-0.11.0.tgz#ba5d2ae34943da28a37c2098047ad265c16fddf4"
|
||||
dependencies:
|
||||
absolute-path "^0.0.0"
|
||||
async "^2.4.0"
|
||||
@@ -3827,8 +3826,8 @@ metro-bundler@^0.9.0:
|
||||
babel-generator "^6.24.1"
|
||||
babel-plugin-external-helpers "^6.18.0"
|
||||
babel-preset-es2015-node "^6.1.1"
|
||||
babel-preset-fbjs "^2.1.0"
|
||||
babel-preset-react-native "^1.9.1"
|
||||
babel-preset-fbjs "^2.1.4"
|
||||
babel-preset-react-native "^2.0.0"
|
||||
babel-register "^6.24.1"
|
||||
babylon "^6.17.0"
|
||||
chalk "^1.1.1"
|
||||
@@ -3838,8 +3837,9 @@ metro-bundler@^0.9.0:
|
||||
denodeify "^1.2.1"
|
||||
fbjs "0.8.12"
|
||||
graceful-fs "^4.1.3"
|
||||
image-size "^0.3.5"
|
||||
jest-haste-map "^20.0.4"
|
||||
image-size "^0.6.0"
|
||||
jest-docblock "20.1.0-chi.1"
|
||||
jest-haste-map "20.1.0-chi.1"
|
||||
json-stable-stringify "^1.0.1"
|
||||
json5 "^0.4.0"
|
||||
left-pad "^1.1.3"
|
||||
@@ -3851,7 +3851,7 @@ metro-bundler@^0.9.0:
|
||||
rimraf "^2.5.4"
|
||||
source-map "^0.5.6"
|
||||
temp "0.8.3"
|
||||
throat "^3.0.0"
|
||||
throat "^4.1.0"
|
||||
uglify-js "2.7.5"
|
||||
write-file-atomic "^1.2.0"
|
||||
xpipe "^1.0.5"
|
||||
@@ -4212,6 +4212,13 @@ os-locale@^1.4.0:
|
||||
dependencies:
|
||||
lcid "^1.0.0"
|
||||
|
||||
os-name@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/os-name/-/os-name-2.0.1.tgz#b9a386361c17ae3a21736ef0599405c9a8c5dc5e"
|
||||
dependencies:
|
||||
macos-release "^1.0.0"
|
||||
win-release "^1.0.0"
|
||||
|
||||
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||
@@ -4525,6 +4532,10 @@ qs@6.5.0, qs@^6.2.1, qs@^6.4.0:
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49"
|
||||
|
||||
qs@^6.5.0:
|
||||
version "6.5.1"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
|
||||
|
||||
querystring@0.2.0, querystring@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
|
||||
@@ -4605,9 +4616,9 @@ react-deep-force-update@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-1.1.1.tgz#bcd31478027b64b3339f108921ab520b4313dc2c"
|
||||
|
||||
react-devtools-core@2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-2.3.1.tgz#dc83aba85735effe5e1dc386a1614cb5e8d0047d"
|
||||
react-devtools-core@^2.5.0:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-2.5.1.tgz#81ef30e0ac35c670d96b436d1f7510eaebe6c08b"
|
||||
dependencies:
|
||||
shell-quote "^1.6.1"
|
||||
ws "^2.0.3"
|
||||
@@ -4632,9 +4643,11 @@ react-native-drawer-layout@1.3.2:
|
||||
dependencies:
|
||||
react-native-dismiss-keyboard "1.0.0"
|
||||
|
||||
react-native-gesture-handler@^1.0.0-alpha.14:
|
||||
version "1.0.0-alpha.17"
|
||||
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.0.0-alpha.17.tgz#1ae4412e1b208d175b34a14931d0635064a92e7b"
|
||||
react-native-gesture-handler@1.0.0-alpha.22:
|
||||
version "1.0.0-alpha.22"
|
||||
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.0.0-alpha.22.tgz#96e5ae08b26a9e99d115f6e16f63d7487ef995fc"
|
||||
dependencies:
|
||||
prop-types "^15.5.10"
|
||||
|
||||
react-native-maps@0.15.3:
|
||||
version "0.15.3"
|
||||
@@ -4686,9 +4699,9 @@ react-native-vector-icons@4.1.1:
|
||||
prop-types "^15.5.8"
|
||||
yargs "^6.3.0"
|
||||
|
||||
react-native@~0.47.2:
|
||||
version "0.47.2"
|
||||
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.47.2.tgz#5e55cd84e4947123c86d36ea6f95ab9ed2d0cb19"
|
||||
react-native@~0.48.4:
|
||||
version "0.48.4"
|
||||
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.48.4.tgz#f305e9fef069a5b3f6a7250ddd50f603cf30ab2d"
|
||||
dependencies:
|
||||
absolute-path "^0.0.0"
|
||||
art "^0.10.0"
|
||||
@@ -4720,6 +4733,7 @@ react-native@~0.47.2:
|
||||
create-react-class "^15.5.2"
|
||||
debug "^2.2.0"
|
||||
denodeify "^1.2.1"
|
||||
envinfo "^3.0.0"
|
||||
errno ">=0.1.1 <0.2.0-0"
|
||||
event-target-shim "^1.0.5"
|
||||
fbjs "0.8.12"
|
||||
@@ -4729,13 +4743,13 @@ react-native@~0.47.2:
|
||||
glob "^7.1.1"
|
||||
graceful-fs "^4.1.3"
|
||||
inquirer "^3.0.6"
|
||||
jest-haste-map "20.1.0-alpha.3"
|
||||
jest-haste-map "20.1.0-delta.4"
|
||||
json-stable-stringify "^1.0.1"
|
||||
json5 "^0.4.0"
|
||||
left-pad "^1.1.3"
|
||||
lodash "^4.16.6"
|
||||
merge-stream "^1.0.1"
|
||||
metro-bundler "^0.9.0"
|
||||
metro-bundler "^0.11.0"
|
||||
mime "^1.3.4"
|
||||
mime-types "2.1.11"
|
||||
minimist "^1.2.0"
|
||||
@@ -4749,7 +4763,7 @@ react-native@~0.47.2:
|
||||
promise "^7.1.1"
|
||||
prop-types "^15.5.8"
|
||||
react-clone-referenced-element "^1.0.1"
|
||||
react-devtools-core "2.3.1"
|
||||
react-devtools-core "^2.5.0"
|
||||
react-timer-mixin "^0.13.2"
|
||||
react-transform-hmr "^1.0.4"
|
||||
rebound "^0.0.13"
|
||||
@@ -4762,7 +4776,7 @@ react-native@~0.47.2:
|
||||
source-map "^0.5.6"
|
||||
stacktrace-parser "^0.1.3"
|
||||
temp "0.8.3"
|
||||
throat "^3.0.0"
|
||||
throat "^4.1.0"
|
||||
whatwg-fetch "^1.0.0"
|
||||
wordwrap "^1.0.0"
|
||||
write-file-atomic "^1.2.0"
|
||||
@@ -4774,7 +4788,7 @@ react-native@~0.47.2:
|
||||
yargs "^6.4.0"
|
||||
|
||||
"react-navigation@file:../..":
|
||||
version "1.0.0-beta.12"
|
||||
version "1.0.0-beta.13"
|
||||
dependencies:
|
||||
babel-plugin-transform-define "^1.3.0"
|
||||
clamp "^1.0.1"
|
||||
@@ -5144,7 +5158,7 @@ sax@~1.1.1:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.6.tgz#5d616be8a5e607d54e114afae55b7eaf2fcc3240"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@5.x, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0:
|
||||
"semver@2 || 3 || 4 || 5", semver@5.x, semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0:
|
||||
version "5.4.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
|
||||
|
||||
@@ -5606,7 +5620,7 @@ throat@^3.0.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/throat/-/throat-3.2.0.tgz#50cb0670edbc40237b9e347d7e1f88e4620af836"
|
||||
|
||||
throat@^4.0.0:
|
||||
throat@^4.0.0, throat@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a"
|
||||
|
||||
@@ -5897,9 +5911,9 @@ webidl-conversions@^4.0.0:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||
|
||||
websql@expo/node-websql#18.0.0:
|
||||
"websql@https://github.com/expo/node-websql/archive/18.0.0.tar.gz":
|
||||
version "0.4.4"
|
||||
resolved "https://codeload.github.com/expo/node-websql/tar.gz/e364fa65146a9e2157a19e5c719e7702c2b6b87a"
|
||||
resolved "https://github.com/expo/node-websql/archive/18.0.0.tar.gz#39b12a08b0180495de1412d8a64a529e21ad554e"
|
||||
dependencies:
|
||||
argsarray "^0.0.1"
|
||||
immediate "^3.2.2"
|
||||
@@ -5932,7 +5946,7 @@ which-module@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
|
||||
|
||||
which@^1.2.12, which@^1.2.9:
|
||||
which@^1.2.12, which@^1.2.14, which@^1.2.9:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
|
||||
dependencies:
|
||||
@@ -5944,6 +5958,12 @@ wide-align@^1.1.0:
|
||||
dependencies:
|
||||
string-width "^1.0.2"
|
||||
|
||||
win-release@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/win-release/-/win-release-1.1.1.tgz#5fa55e02be7ca934edfc12665632e849b72e5209"
|
||||
dependencies:
|
||||
semver "^5.0.1"
|
||||
|
||||
winchan@0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/winchan/-/winchan-0.1.4.tgz#88fa12411cd542eb626018c38a196bcbb17993bb"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-navigation",
|
||||
"version": "1.0.0-beta.13",
|
||||
"version": "1.0.0-beta.14",
|
||||
"description": "React Navigation",
|
||||
"main": "src/react-navigation.js",
|
||||
"sources": {
|
||||
@@ -83,7 +83,7 @@
|
||||
"react": "16.0.0-alpha.12",
|
||||
"react-native": "^0.48.4",
|
||||
"react-native-vector-icons": "^4.2.0",
|
||||
"react-test-renderer": "^15.6.1"
|
||||
"react-test-renderer": "^16.0.0"
|
||||
},
|
||||
"jest": {
|
||||
"notify": true,
|
||||
|
||||
@@ -262,6 +262,7 @@ export type HeaderProps = {
|
||||
NavigationStackScreenOptions
|
||||
>,
|
||||
style: ViewStyleProp,
|
||||
isLandscape?: boolean,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -273,6 +274,7 @@ export type NavigationStackScreenOptions = {
|
||||
header?: ?(React.Element<*> | (HeaderProps => React.Element<*>)),
|
||||
headerTitle?: string | React.Element<*>,
|
||||
headerTitleStyle?: AnimatedTextStyleProp,
|
||||
headerTitleAllowFontScaling?: boolean,
|
||||
headerTintColor?: string,
|
||||
headerLeft?: React.Element<*>,
|
||||
headerBackTitle?: string,
|
||||
@@ -334,6 +336,7 @@ export type NavigationTabScreenOptions = {
|
||||
*
|
||||
>),
|
||||
tabBarVisible?: boolean,
|
||||
tabBarTestIDProps?: { testID?: string, accessibilityLabel?: string },
|
||||
tabBarOnPress?: (
|
||||
scene: TabScene,
|
||||
jumpToIndex: (index: number) => void
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* @flow */
|
||||
|
||||
import React from 'react';
|
||||
import invariant from './utils/invariant';
|
||||
import { BackHandler, Linking } from './PlatformHelpers';
|
||||
import NavigationActions from './NavigationActions';
|
||||
import addNavigationHelpers from './addNavigationHelpers';
|
||||
@@ -74,15 +73,16 @@ export default function createNavigationContainer<S: *, O>(
|
||||
|
||||
const keys = Object.keys(containerProps);
|
||||
|
||||
invariant(
|
||||
keys.length === 0,
|
||||
'This navigator has both navigation and container props, so it is ' +
|
||||
`unclear if it should own its own state. Remove props: "${keys.join(
|
||||
', '
|
||||
)}" ` +
|
||||
'if the navigator should get its state from the navigation prop. If the ' +
|
||||
'navigator should maintain its own state, do not pass a navigation prop.'
|
||||
);
|
||||
if (keys.length !== 0) {
|
||||
throw new Error(
|
||||
'This navigator has both navigation and container props, so it is ' +
|
||||
`unclear if it should own its own state. Remove props: "${keys.join(
|
||||
', '
|
||||
)}" ` +
|
||||
'if the navigator should get its state from the navigation prop. If the ' +
|
||||
'navigator should maintain its own state, do not pass a navigation prop.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_urlToPathAndParams(url: string) {
|
||||
|
||||
@@ -32,6 +32,7 @@ const DefaultDrawerConfig = {
|
||||
Dimensions.get('window').width - (Platform.OS === 'android' ? 56 : 64),
|
||||
contentComponent: DrawerItems,
|
||||
drawerPosition: 'left',
|
||||
drawerBackgroundColor: 'white',
|
||||
useNativeAnimations: true,
|
||||
};
|
||||
|
||||
@@ -48,6 +49,7 @@ const DrawerNavigator = (
|
||||
contentOptions,
|
||||
drawerPosition,
|
||||
useNativeAnimations,
|
||||
drawerBackgroundColor,
|
||||
...tabsConfig
|
||||
} = mergedConfig;
|
||||
|
||||
@@ -83,6 +85,7 @@ const DrawerNavigator = (
|
||||
)((props: *) => (
|
||||
<DrawerView
|
||||
{...props}
|
||||
drawerBackgroundColor={drawerBackgroundColor}
|
||||
drawerLockMode={drawerLockMode}
|
||||
useNativeAnimations={useNativeAnimations}
|
||||
drawerWidth={drawerWidth}
|
||||
|
||||
@@ -357,10 +357,11 @@ export default (
|
||||
// get the action for the path AFTER the matched path for this
|
||||
// router
|
||||
let nestedAction;
|
||||
let nestedQueryString = queryString ? '?' + queryString : '';
|
||||
if (childRouters[matchedRouteName]) {
|
||||
nestedAction = childRouters[matchedRouteName].getActionForPathAndParams(
|
||||
/* $FlowFixMe */
|
||||
pathMatch.slice(pathMatchKeys.length).join('/')
|
||||
pathMatch.slice(pathMatchKeys.length).join('/') + nestedQueryString
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,11 +45,12 @@ export default (
|
||||
tabRouters[routeName] = routeConfig.screen.router;
|
||||
}
|
||||
});
|
||||
invariant(
|
||||
initialRouteIndex !== -1,
|
||||
`Invalid initialRouteName '${initialRouteName}' for TabRouter. ` +
|
||||
`Should be one of ${order.map((n: *) => `"${n}"`).join(', ')}`
|
||||
);
|
||||
if (initialRouteIndex === -1) {
|
||||
throw new Error(
|
||||
`Invalid initialRouteName '${initialRouteName}' for TabRouter. ` +
|
||||
`Should be one of ${order.map((n: *) => `"${n}"`).join(', ')}`
|
||||
);
|
||||
}
|
||||
return {
|
||||
getStateForAction(
|
||||
action: NavigationAction | { action: NavigationAction },
|
||||
|
||||
@@ -902,4 +902,66 @@ describe('StackRouter', () => {
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
test('Querystring params get passed to nested deep link', () => {
|
||||
// uri with two non-empty query param values
|
||||
const uri = 'main/p/4/list/10259959195?code=test&foo=bar';
|
||||
const action = TestStackRouter.getActionForPathAndParams(uri);
|
||||
expect(action).toEqual({
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'main',
|
||||
params: {
|
||||
code: 'test',
|
||||
foo: 'bar',
|
||||
},
|
||||
action: {
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'profile',
|
||||
params: {
|
||||
id: '4',
|
||||
code: 'test',
|
||||
foo: 'bar',
|
||||
},
|
||||
action: {
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'list',
|
||||
params: {
|
||||
id: '10259959195',
|
||||
code: 'test',
|
||||
foo: 'bar',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// uri with one empty and one non-empty query param value
|
||||
const uri2 = 'main/p/4/list/10259959195?code=&foo=bar';
|
||||
const action2 = TestStackRouter.getActionForPathAndParams(uri2);
|
||||
expect(action2).toEqual({
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'main',
|
||||
params: {
|
||||
code: '',
|
||||
foo: 'bar',
|
||||
},
|
||||
action: {
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'profile',
|
||||
params: {
|
||||
id: '4',
|
||||
code: '',
|
||||
foo: 'bar',
|
||||
},
|
||||
action: {
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'list',
|
||||
params: {
|
||||
id: '10259959195',
|
||||
code: '',
|
||||
foo: 'bar',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -63,10 +63,11 @@ export default (
|
||||
let outputConfig = {};
|
||||
|
||||
if (Component.router) {
|
||||
invariant(
|
||||
route && routes && index != null,
|
||||
`Expect nav state to have routes and index, ${JSON.stringify(route)}`
|
||||
);
|
||||
if (!route || !routes || index == null) {
|
||||
throw new Error(
|
||||
`Expect nav state to have routes and index, ${JSON.stringify(route)}`
|
||||
);
|
||||
}
|
||||
const childRoute = routes[index];
|
||||
const childNavigation = addNavigationHelpers({
|
||||
state: childRoute,
|
||||
|
||||
@@ -17,13 +17,14 @@ export default function getScreenForRouteName( // eslint-disable-line consistent
|
||||
): NavigationComponent {
|
||||
const routeConfig = routeConfigs[routeName];
|
||||
|
||||
invariant(
|
||||
routeConfig,
|
||||
`There is no route defined for key ${routeName}.\n` +
|
||||
`Must be one of: ${Object.keys(routeConfigs)
|
||||
.map((a: string) => `'${a}'`)
|
||||
.join(',')}`
|
||||
);
|
||||
if (!routeConfig) {
|
||||
throw new Error(
|
||||
`There is no route defined for key ${routeName}.\n` +
|
||||
`Must be one of: ${Object.keys(routeConfigs)
|
||||
.map((a: string) => `'${a}'`)
|
||||
.join(',')}`
|
||||
);
|
||||
}
|
||||
|
||||
if (routeConfig.screen) {
|
||||
return routeConfig.screen;
|
||||
@@ -41,5 +42,5 @@ export default function getScreenForRouteName( // eslint-disable-line consistent
|
||||
return screen;
|
||||
}
|
||||
|
||||
invariant(false, `Route ${routeName} must define a screen or a getScreen.`);
|
||||
throw new Error(`Route ${routeName} must define a screen or a getScreen.`);
|
||||
}
|
||||
|
||||
@@ -18,28 +18,25 @@ function validateRouteConfigMap(routeConfigs: NavigationRouteConfigMap) {
|
||||
routeNames.forEach((routeName: string) => {
|
||||
const routeConfig = routeConfigs[routeName];
|
||||
|
||||
invariant(
|
||||
routeConfig.screen || routeConfig.getScreen,
|
||||
`Route '${routeName}' should declare a screen. ` +
|
||||
'For example:\n\n' +
|
||||
"import MyScreen from './MyScreen';\n" +
|
||||
'...\n' +
|
||||
`${routeName}: {\n` +
|
||||
' screen: MyScreen,\n' +
|
||||
'}'
|
||||
);
|
||||
|
||||
if (routeConfig.screen && routeConfig.getScreen) {
|
||||
invariant(
|
||||
false,
|
||||
if (!routeConfig.screen && !routeConfig.getScreen) {
|
||||
throw new Error(
|
||||
`Route '${routeName}' should declare a screen. ` +
|
||||
'For example:\n\n' +
|
||||
"import MyScreen from './MyScreen';\n" +
|
||||
'...\n' +
|
||||
`${routeName}: {\n` +
|
||||
' screen: MyScreen,\n' +
|
||||
'}'
|
||||
);
|
||||
} else if (routeConfig.screen && routeConfig.getScreen) {
|
||||
throw new Error(
|
||||
`Route '${routeName}' should declare a screen or ` +
|
||||
'a getScreen, not both.'
|
||||
);
|
||||
}
|
||||
|
||||
if (routeConfig.screen) {
|
||||
invariant(
|
||||
typeof routeConfig.screen === 'function',
|
||||
if (routeConfig.screen && typeof routeConfig.screen !== 'function') {
|
||||
throw new Error(
|
||||
`The component for route '${routeName}' must be a ` +
|
||||
'React component. For example:\n\n' +
|
||||
"import MyScreen from './MyScreen';\n" +
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* @flow */
|
||||
import invariant from '../utils/invariant';
|
||||
|
||||
import type { NavigationRoute } from '../TypeDefinition';
|
||||
|
||||
@@ -15,8 +14,7 @@ export default (screenOptions: *, route: NavigationRoute) => {
|
||||
const deprecatedKey = keys.find((key: *) => deprecatedKeys.includes(key));
|
||||
|
||||
if (typeof screenOptions.title === 'function') {
|
||||
invariant(
|
||||
false,
|
||||
throw new Error(
|
||||
[
|
||||
`\`title\` cannot be defined as a function in navigation options for \`${route.routeName}\` screen. \n`,
|
||||
'Try replacing the following:',
|
||||
@@ -33,8 +31,7 @@ export default (screenOptions: *, route: NavigationRoute) => {
|
||||
}
|
||||
|
||||
if (deprecatedKey && typeof screenOptions[deprecatedKey] === 'function') {
|
||||
invariant(
|
||||
false,
|
||||
throw new Error(
|
||||
[
|
||||
`\`${deprecatedKey}\` cannot be defined as a function in navigation options for \`${route.routeName}\` screen. \n`,
|
||||
'Try replacing the following:',
|
||||
@@ -53,8 +50,7 @@ export default (screenOptions: *, route: NavigationRoute) => {
|
||||
}
|
||||
|
||||
if (deprecatedKey && typeof screenOptions[deprecatedKey] === 'object') {
|
||||
invariant(
|
||||
false,
|
||||
throw new Error(
|
||||
[
|
||||
`Invalid key \`${deprecatedKey}\` defined in navigation options for \`${route.routeName}\` screen.`,
|
||||
'\n',
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule invariant
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule shallowEqual
|
||||
* @typechecks
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -125,6 +125,5 @@ export default withCachedChildNavigation(DrawerSidebar);
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -36,6 +36,7 @@ export type DrawerViewConfig = {
|
||||
contentOptions?: {},
|
||||
style?: ViewStyleProp,
|
||||
useNativeAnimations?: boolean,
|
||||
drawerBackgroundColor?: String,
|
||||
};
|
||||
|
||||
type Props = DrawerViewConfig & {
|
||||
@@ -160,6 +161,7 @@ export default class DrawerView<T: *> extends PureComponent<void, Props, void> {
|
||||
(this.props.screenProps && this.props.screenProps.drawerLockMode) ||
|
||||
(config && config.drawerLockMode)
|
||||
}
|
||||
drawerBackgroundColor={this.props.drawerBackgroundColor}
|
||||
drawerWidth={this.props.drawerWidth}
|
||||
onDrawerOpen={this._handleDrawerOpen}
|
||||
onDrawerClose={this._handleDrawerClose}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Animated, Platform, StyleSheet, View } from 'react-native';
|
||||
import HeaderTitle from './HeaderTitle';
|
||||
import HeaderBackButton from './HeaderBackButton';
|
||||
import HeaderStyleInterpolator from './HeaderStyleInterpolator';
|
||||
import withOrientation from '../withOrientation';
|
||||
|
||||
import type {
|
||||
NavigationScene,
|
||||
@@ -91,6 +92,7 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
|
||||
|
||||
const titleStyle = details.options.headerTitleStyle;
|
||||
const color = details.options.headerTintColor;
|
||||
const allowFontScaling = details.options.headerTitleAllowFontScaling;
|
||||
|
||||
// On iOS, width of left/right components depends on the calculated
|
||||
// size of the title.
|
||||
@@ -109,6 +111,7 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
|
||||
return (
|
||||
<HeaderTitle
|
||||
onLayout={onLayoutIOS}
|
||||
allowFontScaling={allowFontScaling == null ? true : allowFontScaling}
|
||||
style={[color ? { color } : null, titleStyle]}
|
||||
>
|
||||
{titleString}
|
||||
@@ -281,14 +284,25 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
|
||||
screenProps,
|
||||
progress,
|
||||
style,
|
||||
isLandscape,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
const { options } = this.props.getScreenDetails(scene);
|
||||
const headerStyle = options.headerStyle;
|
||||
const landscapeAwareStatusBarHeight = isLandscape ? 0 : STATUSBAR_HEIGHT;
|
||||
const containerStyles = [
|
||||
styles.container,
|
||||
{
|
||||
paddingTop: landscapeAwareStatusBarHeight,
|
||||
height: APPBAR_HEIGHT + landscapeAwareStatusBarHeight,
|
||||
},
|
||||
headerStyle,
|
||||
style,
|
||||
];
|
||||
|
||||
return (
|
||||
<Animated.View {...rest} style={[styles.container, headerStyle, style]}>
|
||||
<Animated.View {...rest} style={containerStyles}>
|
||||
<View style={styles.appBar}>{appBar}</View>
|
||||
</Animated.View>
|
||||
);
|
||||
@@ -315,9 +329,7 @@ if (Platform.OS === 'ios') {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingTop: STATUSBAR_HEIGHT,
|
||||
backgroundColor: Platform.OS === 'ios' ? '#F7F7F7' : '#FFF',
|
||||
height: STATUSBAR_HEIGHT + APPBAR_HEIGHT,
|
||||
...platformContainerStyles,
|
||||
},
|
||||
appBar: {
|
||||
@@ -353,4 +365,4 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
export default Header;
|
||||
export default withOrientation(Header);
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
/* @flow */
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Animated, TouchableWithoutFeedback, StyleSheet } from 'react-native';
|
||||
import {
|
||||
Animated,
|
||||
TouchableWithoutFeedback,
|
||||
StyleSheet,
|
||||
View,
|
||||
Platform,
|
||||
} from 'react-native';
|
||||
import TabBarIcon from './TabBarIcon';
|
||||
import withOrientation from '../withOrientation';
|
||||
|
||||
import type {
|
||||
NavigationAction,
|
||||
@@ -21,6 +28,8 @@ type DefaultProps = {
|
||||
inactiveTintColor: string,
|
||||
inactiveBackgroundColor: string,
|
||||
showLabel: boolean,
|
||||
showIcon: boolean,
|
||||
allowFontScaling: boolean,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
@@ -28,6 +37,9 @@ type Props = {
|
||||
activeBackgroundColor: string,
|
||||
inactiveTintColor: string,
|
||||
inactiveBackgroundColor: string,
|
||||
showLabel: boolean,
|
||||
showIcon: boolean,
|
||||
allowFontScaling: boolean,
|
||||
position: Animated.Value,
|
||||
navigation: NavigationScreenProp<NavigationState, NavigationAction>,
|
||||
jumpToIndex: (index: number) => void,
|
||||
@@ -35,27 +47,27 @@ type Props = {
|
||||
getOnPress: (
|
||||
scene: TabScene
|
||||
) => (scene: TabScene, jumpToIndex: (index: number) => void) => void,
|
||||
getTestIDProps: (scene: TabScene) => (scene: TabScene) => any,
|
||||
renderIcon: (scene: TabScene) => React.Element<*>,
|
||||
showLabel: boolean,
|
||||
style?: ViewStyleProp,
|
||||
labelStyle?: TextStyleProp,
|
||||
tabStyle?: ViewStyleProp,
|
||||
showIcon: boolean,
|
||||
showIcon?: boolean,
|
||||
isLandscape?: boolean,
|
||||
};
|
||||
|
||||
export default class TabBarBottom extends PureComponent<
|
||||
DefaultProps,
|
||||
Props,
|
||||
void
|
||||
> {
|
||||
const majorVersionIOS = parseInt(Platform.Version, 10);
|
||||
|
||||
class TabBarBottom extends PureComponent<DefaultProps, Props, void> {
|
||||
// See https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/UIKitUICatalog/UITabBar.html
|
||||
static defaultProps = {
|
||||
static defaultProps: DefaultProps = {
|
||||
activeTintColor: '#3478f6', // Default active tint color in iOS 10
|
||||
activeBackgroundColor: 'transparent',
|
||||
inactiveTintColor: '#929292', // Default inactive tint color in iOS 10
|
||||
inactiveBackgroundColor: 'transparent',
|
||||
showLabel: true,
|
||||
showIcon: true,
|
||||
allowFontScaling: true,
|
||||
};
|
||||
|
||||
props: Props;
|
||||
@@ -68,6 +80,9 @@ export default class TabBarBottom extends PureComponent<
|
||||
inactiveTintColor,
|
||||
labelStyle,
|
||||
showLabel,
|
||||
showIcon,
|
||||
isLandscape,
|
||||
allowFontScaling,
|
||||
} = this.props;
|
||||
if (showLabel === false) {
|
||||
return null;
|
||||
@@ -87,9 +102,21 @@ export default class TabBarBottom extends PureComponent<
|
||||
|
||||
const tintColor = scene.focused ? activeTintColor : inactiveTintColor;
|
||||
const label = this.props.getLabel({ ...scene, tintColor });
|
||||
let marginLeft = 0;
|
||||
if (isLandscape && showIcon && majorVersionIOS >= 11) {
|
||||
marginLeft = LABEL_LEFT_MARGIN;
|
||||
}
|
||||
let marginTop = 0;
|
||||
if (!isLandscape && showIcon && majorVersionIOS >= 11) {
|
||||
marginTop = LABEL_TOP_MARGIN;
|
||||
}
|
||||
|
||||
if (typeof label === 'string') {
|
||||
return (
|
||||
<Animated.Text style={[styles.label, { color }, labelStyle]}>
|
||||
<Animated.Text
|
||||
style={[styles.label, { color, marginLeft, marginTop }, labelStyle]}
|
||||
allowFontScaling={allowFontScaling}
|
||||
>
|
||||
{label}
|
||||
</Animated.Text>
|
||||
);
|
||||
@@ -110,6 +137,7 @@ export default class TabBarBottom extends PureComponent<
|
||||
inactiveTintColor,
|
||||
renderIcon,
|
||||
showIcon,
|
||||
showLabel,
|
||||
} = this.props;
|
||||
if (showIcon === false) {
|
||||
return null;
|
||||
@@ -122,21 +150,29 @@ export default class TabBarBottom extends PureComponent<
|
||||
inactiveTintColor={inactiveTintColor}
|
||||
renderIcon={renderIcon}
|
||||
scene={scene}
|
||||
style={styles.icon}
|
||||
style={showLabel && majorVersionIOS >= 11 ? {} : styles.icon}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
_renderTestIDProps = (scene: TabScene) => {
|
||||
const testIDProps =
|
||||
this.props.getTestIDProps && this.props.getTestIDProps(scene);
|
||||
return testIDProps;
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
position,
|
||||
navigation,
|
||||
jumpToIndex,
|
||||
getOnPress,
|
||||
getTestIDProps,
|
||||
activeBackgroundColor,
|
||||
inactiveBackgroundColor,
|
||||
style,
|
||||
tabStyle,
|
||||
isLandscape,
|
||||
} = this.props;
|
||||
const { routes } = navigation.state;
|
||||
// Prepend '-1', so there are always at least 2 items in inputRange
|
||||
@@ -157,17 +193,25 @@ export default class TabBarBottom extends PureComponent<
|
||||
inputRange,
|
||||
outputRange: (outputRange: Array<string>),
|
||||
});
|
||||
|
||||
const justifyContent = this.props.showIcon ? 'flex-end' : 'center';
|
||||
const extraProps = this._renderTestIDProps(scene) || {};
|
||||
const { testID, accessibilityLabel } = extraProps;
|
||||
|
||||
return (
|
||||
<TouchableWithoutFeedback
|
||||
key={route.key}
|
||||
testID={testID}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
onPress={() =>
|
||||
onPress ? onPress(scene, jumpToIndex) : jumpToIndex(index)}
|
||||
>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.tab,
|
||||
{ backgroundColor, justifyContent },
|
||||
isLandscape && majorVersionIOS >= 11 && styles.tabLandscape,
|
||||
!isLandscape && majorVersionIOS >= 11 && styles.tabPortrait,
|
||||
{ backgroundColor },
|
||||
tabStyle,
|
||||
]}
|
||||
>
|
||||
@@ -182,19 +226,29 @@ export default class TabBarBottom extends PureComponent<
|
||||
}
|
||||
}
|
||||
|
||||
const LABEL_LEFT_MARGIN = 20;
|
||||
const LABEL_TOP_MARGIN = 15;
|
||||
const styles = StyleSheet.create({
|
||||
tabBar: {
|
||||
height: 49, // Default tab bar height in iOS 10
|
||||
height: 49, // Default tab bar height in iOS 10+
|
||||
flexDirection: 'row',
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: 'rgba(0, 0, 0, .3)',
|
||||
backgroundColor: '#F7F7F7', // Default background color in iOS 10
|
||||
backgroundColor: '#F7F7F7', // Default background color in iOS 10+
|
||||
},
|
||||
tab: {
|
||||
flex: 1,
|
||||
alignItems: 'stretch',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
tabPortrait: {
|
||||
justifyContent: 'flex-end',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
tabLandscape: {
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
icon: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
@@ -205,3 +259,5 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
});
|
||||
|
||||
export default withOrientation(TabBarBottom);
|
||||
|
||||
@@ -21,6 +21,7 @@ type DefaultProps = {
|
||||
showIcon: boolean,
|
||||
showLabel: boolean,
|
||||
upperCaseLabel: boolean,
|
||||
allowFontScaling: boolean,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
@@ -29,6 +30,7 @@ type Props = {
|
||||
showIcon: boolean,
|
||||
showLabel: boolean,
|
||||
upperCaseLabel: boolean,
|
||||
allowFontScaling: boolean,
|
||||
position: Animated.Value,
|
||||
navigation: NavigationScreenProp<NavigationState, NavigationAction>,
|
||||
jumpToIndex: (index: number) => void,
|
||||
@@ -46,12 +48,13 @@ export default class TabBarTop extends PureComponent<
|
||||
Props,
|
||||
void
|
||||
> {
|
||||
static defaultProps = {
|
||||
static defaultProps: DefaultProps = {
|
||||
activeTintColor: '#fff',
|
||||
inactiveTintColor: '#fff',
|
||||
showIcon: false,
|
||||
showLabel: true,
|
||||
upperCaseLabel: true,
|
||||
allowFontScaling: true,
|
||||
};
|
||||
|
||||
props: Props;
|
||||
@@ -65,6 +68,7 @@ export default class TabBarTop extends PureComponent<
|
||||
showLabel,
|
||||
upperCaseLabel,
|
||||
labelStyle,
|
||||
allowFontScaling,
|
||||
} = this.props;
|
||||
if (showLabel === false) {
|
||||
return null;
|
||||
@@ -86,7 +90,10 @@ export default class TabBarTop extends PureComponent<
|
||||
const label = this.props.getLabel({ ...scene, tintColor });
|
||||
if (typeof label === 'string') {
|
||||
return (
|
||||
<Animated.Text style={[styles.label, { color }, labelStyle]}>
|
||||
<Animated.Text
|
||||
style={[styles.label, { color }, labelStyle]}
|
||||
allowFontScaling={allowFontScaling}
|
||||
>
|
||||
{upperCaseLabel ? label.toUpperCase() : label}
|
||||
</Animated.Text>
|
||||
);
|
||||
|
||||
@@ -104,6 +104,15 @@ class TabView extends PureComponent<void, Props, void> {
|
||||
return options.tabBarOnPress;
|
||||
};
|
||||
|
||||
_getTestIDProps = ({ route }: TabScene) => {
|
||||
const options = this.props.router.getScreenOptions(
|
||||
this.props.childNavigationProps[route.key],
|
||||
this.props.screenProps || {}
|
||||
);
|
||||
|
||||
return options.tabBarTestIDProps;
|
||||
};
|
||||
|
||||
_renderIcon = ({ focused, route, tintColor }: TabScene) => {
|
||||
const options = this.props.router.getScreenOptions(
|
||||
this.props.childNavigationProps[route.key],
|
||||
@@ -133,6 +142,7 @@ class TabView extends PureComponent<void, Props, void> {
|
||||
screenProps={this.props.screenProps}
|
||||
navigation={this.props.navigation}
|
||||
getLabel={this._getLabel}
|
||||
getTestIDProps={this._getTestIDProps}
|
||||
getOnPress={this._getOnPress}
|
||||
renderIcon={this._renderIcon}
|
||||
animationEnabled={animationEnabled}
|
||||
|
||||
31
src/views/__tests__/TabView-test.js
Normal file
31
src/views/__tests__/TabView-test.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import renderer from 'react-test-renderer';
|
||||
import TabRouter from '../../routers/TabRouter';
|
||||
|
||||
import TabView from '../TabView/TabView';
|
||||
import TabBarBottom from '../TabView/TabBarBottom';
|
||||
|
||||
describe('TabBarBottom', () => {
|
||||
it('renders successfully', () => {
|
||||
const navigation = {
|
||||
state: {
|
||||
index: 0,
|
||||
routes: [{ key: 's1', routeName: 's1' }],
|
||||
},
|
||||
};
|
||||
const router = TabRouter({ s1: { screen: View } });
|
||||
|
||||
const rendered = renderer
|
||||
.create(
|
||||
<TabView
|
||||
tabBarComponent={TabBarBottom}
|
||||
navigation={navigation}
|
||||
router={router}
|
||||
/>
|
||||
)
|
||||
.toJSON();
|
||||
|
||||
expect(rendered).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
228
src/views/__tests__/__snapshots__/TabView-test.js.snap
Normal file
228
src/views/__tests__/__snapshots__/TabView-test.js.snap
Normal file
@@ -0,0 +1,228 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`TabBarBottom renders successfully 1`] = `
|
||||
<View
|
||||
loaded={
|
||||
Array [
|
||||
0,
|
||||
]
|
||||
}
|
||||
onLayout={[Function]}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"flex": 1,
|
||||
"overflow": "hidden",
|
||||
},
|
||||
Object {
|
||||
"flex": 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#F7F7F7",
|
||||
"borderTopColor": "rgba(0, 0, 0, .3)",
|
||||
"borderTopWidth": 0.5,
|
||||
"flexDirection": "row",
|
||||
"height": 49,
|
||||
}
|
||||
}
|
||||
>
|
||||
<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]}
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"backgroundColor": "rgba(0, 0, 0, 0)",
|
||||
"flex": 1,
|
||||
"justifyContent": "flex-end",
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexGrow": 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"bottom": 0,
|
||||
"justifyContent": "center",
|
||||
"left": 0,
|
||||
"opacity": 1,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"bottom": 0,
|
||||
"justifyContent": "center",
|
||||
"left": 0,
|
||||
"opacity": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<Text
|
||||
accessible={true}
|
||||
allowFontScaling={true}
|
||||
collapsable={undefined}
|
||||
disabled={false}
|
||||
ellipsizeMode="tail"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "transparent",
|
||||
"color": "rgba(52, 120, 246, 1)",
|
||||
"fontSize": 10,
|
||||
"marginBottom": 1.5,
|
||||
"marginLeft": 0,
|
||||
"marginTop": 0,
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
>
|
||||
s1
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<RCTScrollView
|
||||
DEPRECATED_sendUpdatedChildFrames={false}
|
||||
alwaysBounceHorizontal={false}
|
||||
alwaysBounceVertical={false}
|
||||
automaticallyAdjustContentInsets={false}
|
||||
bounces={false}
|
||||
contentContainerStyle={
|
||||
Object {
|
||||
"flexGrow": 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]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchMove={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
pagingEnabled={true}
|
||||
scrollEnabled={undefined}
|
||||
scrollEventThrottle={16}
|
||||
scrollsToTop={false}
|
||||
sendMomentumEvents={true}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"flexGrow": 1,
|
||||
"flexShrink": 1,
|
||||
"overflow": "scroll",
|
||||
},
|
||||
Object {
|
||||
"flexGrow": 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<RCTScrollContentView
|
||||
collapsable={false}
|
||||
removeClippedSubviews={undefined}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
},
|
||||
Object {
|
||||
"flexGrow": 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
"overflow": "hidden",
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
"overflow": "hidden",
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
navigation={
|
||||
Object {
|
||||
"goBack": [Function],
|
||||
"navigate": [Function],
|
||||
"setParams": [Function],
|
||||
"state": Object {
|
||||
"key": "s1",
|
||||
"routeName": "s1",
|
||||
},
|
||||
}
|
||||
}
|
||||
screenProps={undefined}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</RCTScrollContentView>
|
||||
</RCTScrollView>
|
||||
</View>
|
||||
`;
|
||||
@@ -0,0 +1,7 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`it adds isLandscape to props 1`] = `
|
||||
<View
|
||||
isLandscape={false}
|
||||
/>
|
||||
`;
|
||||
15
src/views/__tests__/withOrientation-test.js
Normal file
15
src/views/__tests__/withOrientation-test.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import renderer from 'react-test-renderer';
|
||||
import withOrientation, { isOrientationLandscape } from '../withOrientation';
|
||||
|
||||
test('it adds isLandscape to props', () => {
|
||||
const WrappedComponent = withOrientation(View);
|
||||
const rendered = renderer.create(<WrappedComponent />).toJSON();
|
||||
expect(rendered).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('calculates orientation correctly', () => {
|
||||
const isLandscape = isOrientationLandscape({ width: 10, height: 1 });
|
||||
expect(isLandscape).toBeTruthy();
|
||||
});
|
||||
55
src/views/withOrientation.js
Normal file
55
src/views/withOrientation.js
Normal file
@@ -0,0 +1,55 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Dimensions } from 'react-native';
|
||||
import hoistNonReactStatic from 'hoist-non-react-statics';
|
||||
|
||||
type WindowDimensions = {
|
||||
width: number,
|
||||
height: number,
|
||||
};
|
||||
|
||||
type InjectedProps = {
|
||||
isLandscape: boolean,
|
||||
};
|
||||
|
||||
type State = {
|
||||
isLandscape: boolean,
|
||||
};
|
||||
|
||||
export const isOrientationLandscape = ({
|
||||
width,
|
||||
height,
|
||||
}: WindowDimensions): boolean => width > height;
|
||||
|
||||
export default function<T: *>(WrappedComponent: ReactClass<T & InjectedProps>) {
|
||||
class withOrientation extends React.Component<void, T, State> {
|
||||
state: State;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
const isLandscape = isOrientationLandscape(Dimensions.get('window'));
|
||||
this.state = { isLandscape };
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
Dimensions.addEventListener('change', this.handleOrientationChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
Dimensions.removeEventListener('change', this.handleOrientationChange);
|
||||
}
|
||||
|
||||
handleOrientationChange = ({ window }: { window: WindowDimensions }) => {
|
||||
const isLandscape = isOrientationLandscape(window);
|
||||
this.setState({ isLandscape });
|
||||
};
|
||||
|
||||
render() {
|
||||
return <WrappedComponent {...this.props} {...this.state} />;
|
||||
}
|
||||
}
|
||||
|
||||
return hoistNonReactStatic(withOrientation, WrappedComponent);
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule RelativeImageStub
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
22
yarn.lock
22
yarn.lock
@@ -2287,6 +2287,18 @@ fbjs@0.8.12:
|
||||
setimmediate "^1.0.5"
|
||||
ua-parser-js "^0.7.9"
|
||||
|
||||
fbjs@^0.8.16:
|
||||
version "0.8.16"
|
||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
|
||||
dependencies:
|
||||
core-js "^1.0.0"
|
||||
isomorphic-fetch "^2.1.1"
|
||||
loose-envify "^1.0.0"
|
||||
object-assign "^4.1.0"
|
||||
promise "^7.1.1"
|
||||
setimmediate "^1.0.5"
|
||||
ua-parser-js "^0.7.9"
|
||||
|
||||
fbjs@^0.8.9:
|
||||
version "0.8.15"
|
||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.15.tgz#4f0695fdfcc16c37c0b07facec8cb4c4091685b9"
|
||||
@@ -4587,12 +4599,12 @@ react-proxy@^1.1.7:
|
||||
lodash "^4.6.1"
|
||||
react-deep-force-update "^1.0.0"
|
||||
|
||||
react-test-renderer@^15.6.1:
|
||||
version "15.6.1"
|
||||
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-15.6.1.tgz#026f4a5bb5552661fd2cc4bbcd0d4bc8a35ebf7e"
|
||||
react-test-renderer@^16.0.0:
|
||||
version "16.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.0.0.tgz#9fe7b8308f2f71f29fc356d4102086f131c9cb15"
|
||||
dependencies:
|
||||
fbjs "^0.8.9"
|
||||
object-assign "^4.1.0"
|
||||
fbjs "^0.8.16"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
react-timer-mixin@^0.13.2:
|
||||
version "0.13.3"
|
||||
|
||||
Reference in New Issue
Block a user