Update/Fix Prettier + Eslint config for codebase

Run Prettier/Eslint on entire codebase, fix issues
This commit is contained in:
Adam Miskiewicz
2017-05-14 12:14:12 -07:00
parent e957187126
commit 86b20f8017
94 changed files with 3630 additions and 3846 deletions

View File

@@ -0,0 +1,6 @@
flow-typed
node_modules
lib*
## Temporary
examples

View File

@@ -1,12 +1,16 @@
{
"extends": [
"airbnb",
"plugin:flowtype/recommended",
"plugin:react/recommended",
"plugin:import/errors",
"plugin:import/warnings",
"prettier",
"prettier/flowtype",
"prettier/react"
],
"parser": "babel-eslint",
"plugins": [
"react",
"flowtype",
"prettier"
],
@@ -18,7 +22,7 @@
},
"rules": {
"prettier/prettier": ["error", {
"trailingComma": "all",
"trailingComma": "es5",
"singleQuote": true
}],
@@ -65,7 +69,7 @@
},
"settings": {
"flowtype": {
"onlyFilesWithFlowAnnotation": false
"onlyFilesWithFlowAnnotation": true
}
}
}

View File

@@ -19,6 +19,9 @@
<PROJECT_ROOT>/website/node_modules/react-native/.*
<PROJECT_ROOT>/website/node_modules/fbjs/.*
; Ignore misc packages
.*/node_modules/eslint-.*
; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
@@ -55,6 +58,3 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
unsafe.enable_getters_and_setters=true
[version]
^0.40.0

View File

@@ -9,13 +9,16 @@ const path = require('path');
const config = require('../../../rn-cli.config');
config.getBlacklist = () => [
new RegExp(`${path.resolve(__dirname, '../../..')}/node_modules/react-native/(.*)`),
new RegExp(
`${path.resolve(__dirname, '../../..')}/node_modules/react-native/(.*)`
),
new RegExp(`${path.resolve(__dirname, '../../..')}/node_modules/react/(.*)`),
...config.getBlacklistForExample('NavigationPlayground'),
new RegExp(`^${path.resolve(__dirname, '..')}/package.json$`),
];
config.getTransformModulePath = () => path.resolve(__dirname, './transformer.js');
config.getTransformModulePath = () =>
path.resolve(__dirname, './transformer.js');
config.getTransformOptions = () => ({
reactNativePath: path.resolve(__dirname, '../node_modules/react-native/'),

View File

@@ -19,21 +19,23 @@ const reactTransformPlugin = require('babel-plugin-react-transform').default;
const hmrTransform = 'react-transform-hmr/lib/index.js';
const transformPath = require.resolve(hmrTransform);
const makeHMRConfig = function(options, filename) {
const transform = filename ?
'./' + path.relative(path.dirname(filename), transformPath) : // packager can't handle absolute paths
hmrTransform;
const makeHMRConfig = function(options, filename) {
const transform = filename
? './' + path.relative(path.dirname(filename), transformPath) // packager can't handle absolute paths
: hmrTransform;
return {
plugins: [
[
reactTransformPlugin,
{
transforms: [{
transform,
imports: ['react-native'],
locals: ['module'],
}],
transforms: [
{
transform,
imports: ['react-native'],
locals: ['module'],
},
],
},
],
],
@@ -42,13 +44,22 @@ const makeHMRConfig = function(options, filename) {
const buildAliasPreset = (reactNativePath, reactPath) => ({
plugins: [
[require('babel-plugin-module-resolver').default, {
alias: Object.assign({}, {
'react-native': path.resolve(`${reactNativePath || './node_modules/react-native'}`),
react: path.resolve(`${reactPath || './node_modules/react'}`),
}, require('babel-preset-exponent').plugins[0][1].alias),
cwd: path.resolve(__dirname, '..'),
}],
[
require('babel-plugin-module-resolver').default,
{
alias: Object.assign(
{},
{
'react-native': path.resolve(
`${reactNativePath || './node_modules/react-native'}`
),
react: path.resolve(`${reactPath || './node_modules/react'}`),
},
require('babel-preset-exponent').plugins[0][1].alias
),
cwd: path.resolve(__dirname, '..'),
},
],
],
});
@@ -59,7 +70,10 @@ const buildAliasPreset = (reactNativePath, reactPath) => ({
function buildBabelConfig(filename, options) {
const exponentBabelPreset = require('babel-preset-exponent');
const babelConfig = {
presets: [...exponentBabelPreset.presets, buildAliasPreset(options.reactNativePath, options.reactPath)],
presets: [
...exponentBabelPreset.presets,
buildAliasPreset(options.reactNativePath, options.reactPath),
],
plugins: [],
};
@@ -97,7 +111,7 @@ function transform(src, filename, options) {
};
}
module.exports = function (data, callback) {
module.exports = function(data, callback) {
let result;
try {
result = transform(data.sourceCode, data.filename, data.options);

View File

@@ -1,6 +1,4 @@
import {
AppRegistry,
} from 'react-native';
import { AppRegistry } from 'react-native';
import App from './js/App';

View File

@@ -49,8 +49,12 @@ const ExampleRoutes = {
screen: CustomTabs,
},
ModalStack: {
name: Platform.OS === 'ios' ? 'Modal Stack Example' : 'Stack with Dynamic Header',
description: Platform.OS === 'ios' ? 'Stack navigation with modals' : 'Dynamically showing and hiding the header',
name: Platform.OS === 'ios'
? 'Modal Stack Example'
: 'Stack with Dynamic Header',
description: Platform.OS === 'ios'
? 'Stack navigation with modals'
: 'Dynamically showing and hiding the header',
screen: ModalStack,
},
StacksInTabs: {
@@ -80,7 +84,7 @@ const ExampleRoutes = {
const MainScreen = ({ navigation }) => (
<ScrollView>
<Banner />
{Object.keys(ExampleRoutes).map((routeName: string) =>
{Object.keys(ExampleRoutes).map((routeName: string) => (
<TouchableOpacity
key={routeName}
onPress={() => {
@@ -92,28 +96,33 @@ const MainScreen = ({ navigation }) => (
>
<View style={styles.item}>
<Text style={styles.title}>{ExampleRoutes[routeName].name}</Text>
<Text style={styles.description}>{ExampleRoutes[routeName].description}</Text>
<Text style={styles.description}>
{ExampleRoutes[routeName].description}
</Text>
</View>
</TouchableOpacity>
)}
))}
</ScrollView>
);
const AppNavigator = StackNavigator({
...ExampleRoutes,
Index: {
screen: MainScreen,
const AppNavigator = StackNavigator(
{
...ExampleRoutes,
Index: {
screen: MainScreen,
},
},
}, {
initialRouteName: 'Index',
headerMode: 'none',
{
initialRouteName: 'Index',
headerMode: 'none',
/*
/*
* Use modal on iOS because the card mode comes from the right,
* which conflicts with the drawer example gesture
*/
mode: Platform.OS === 'ios' ? 'modal' : 'card',
});
mode: Platform.OS === 'ios' ? 'modal' : 'card',
}
);
export default () => <AppNavigator />;

View File

@@ -2,20 +2,11 @@
import React from 'react';
import {
Image,
Platform,
StyleSheet,
Text,
View,
} from 'react-native';
import { Image, Platform, StyleSheet, Text, View } from 'react-native';
const Banner = () => (
<View style={styles.banner}>
<Image
source={require('./assets/NavLogo.png')}
style={styles.image}
/>
<Image source={require('./assets/NavLogo.png')} style={styles.image} />
<Text style={styles.title}>React Navigation Examples</Text>
</View>
);

View File

@@ -33,29 +33,18 @@ const MyNavScreen = ({ navigation, banner }) => (
);
const MyHomeScreen = ({ navigation }) => (
<MyNavScreen
banner="Home Screen"
navigation={navigation}
/>
<MyNavScreen banner="Home Screen" navigation={navigation} />
);
const MyNotificationsScreen = ({ navigation }) => (
<MyNavScreen
banner="Notifications Screen"
navigation={navigation}
/>
<MyNavScreen banner="Notifications Screen" navigation={navigation} />
);
const MySettingsScreen = ({ navigation }) => (
<MyNavScreen
banner="Settings Screen"
navigation={navigation}
/>
<MyNavScreen banner="Settings Screen" navigation={navigation} />
);
const CustomTabBar = ({
navigation,
}) => {
const CustomTabBar = ({ navigation }) => {
const { routes } = navigation.state;
return (
<View style={styles.tabContainer}>
@@ -70,12 +59,9 @@ const CustomTabBar = ({
))}
</View>
);
}
};
const CustomTabView = ({
router,
navigation,
}) => {
const CustomTabView = ({ router, navigation }) => {
const { routes, index } = navigation.state;
const ActiveScreen = router.getComponentForState(navigation.state);
return (
@@ -91,25 +77,30 @@ const CustomTabView = ({
);
};
const CustomTabRouter = TabRouter({
Home: {
screen: MyHomeScreen,
path: '',
const CustomTabRouter = TabRouter(
{
Home: {
screen: MyHomeScreen,
path: '',
},
Notifications: {
screen: MyNotificationsScreen,
path: 'notifications',
},
Settings: {
screen: MySettingsScreen,
path: 'settings',
},
},
Notifications: {
screen: MyNotificationsScreen,
path: 'notifications',
},
Settings: {
screen: MySettingsScreen,
path: 'settings',
},
}, {
// Change this to start on a different tab
initialRouteName: 'Home',
});
{
// Change this to start on a different tab
initialRouteName: 'Home',
}
);
const CustomTabs = createNavigationContainer(createNavigator(CustomTabRouter)(CustomTabView));
const CustomTabs = createNavigationContainer(
createNavigator(CustomTabRouter)(CustomTabView)
);
const styles = StyleSheet.create({
container: {
@@ -127,7 +118,7 @@ const styles = StyleSheet.create({
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 4,
}
},
});
export default CustomTabs;

View File

@@ -3,15 +3,8 @@
*/
import React from 'react';
import {
Button,
Platform,
ScrollView,
StyleSheet,
} from 'react-native';
import {
DrawerNavigator,
} from 'react-navigation';
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';
@@ -22,18 +15,12 @@ const MyNavScreen = ({ navigation, banner }) => (
onPress={() => navigation.navigate('DrawerOpen')}
title="Open drawer"
/>
<Button
onPress={() => navigation.goBack(null)}
title="Go back"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</ScrollView>
);
const InboxScreen = ({ navigation }) => (
<MyNavScreen
banner={'Inbox Screen'}
navigation={navigation}
/>
<MyNavScreen banner={'Inbox Screen'} navigation={navigation} />
);
InboxScreen.navigationOptions = {
drawerLabel: 'Inbox',
@@ -47,37 +34,33 @@ InboxScreen.navigationOptions = {
};
const DraftsScreen = ({ navigation }) => (
<MyNavScreen
banner={'Drafts Screen'}
navigation={navigation}
/>
<MyNavScreen banner={'Drafts Screen'} navigation={navigation} />
);
DraftsScreen.navigationOptions = {
drawerLabel: 'Drafts',
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="drafts"
size={24}
style={{ color: tintColor }}
/>
<MaterialIcons name="drafts" size={24} style={{ color: tintColor }} />
),
};
const DrawerExample = DrawerNavigator({
Inbox: {
path: '/',
screen: InboxScreen,
const DrawerExample = DrawerNavigator(
{
Inbox: {
path: '/',
screen: InboxScreen,
},
Drafts: {
path: '/sent',
screen: DraftsScreen,
},
},
Drafts: {
path: '/sent',
screen: DraftsScreen,
},
}, {
initialRouteName: 'Drafts',
contentOptions: {
activeTintColor: '#e91e63',
},
});
{
initialRouteName: 'Drafts',
contentOptions: {
activeTintColor: '#e91e63',
},
}
);
const styles = StyleSheet.create({
container: {

View File

@@ -3,14 +3,8 @@
*/
import React from 'react';
import {
Button,
ScrollView,
Text,
} from 'react-native';
import {
StackNavigator,
} from 'react-navigation';
import { Button, ScrollView, Text } from 'react-native';
import { StackNavigator } from 'react-navigation';
import SampleText from './SampleText';
const MyNavScreen = ({ navigation, banner }) => (
@@ -24,24 +18,21 @@ const MyNavScreen = ({ navigation, banner }) => (
onPress={() => navigation.navigate('HeaderTest')}
title="Go to a header toggle screen"
/>
{navigation.state.routeName === 'HeaderTest' && <Button
title="Toggle Header"
onPress={() => navigation.setParams({
headerVisible: (!navigation.state.params || !navigation.state.params.headerVisible),
})}
/>}
<Button
onPress={() => navigation.goBack(null)}
title="Go back"
/>
{navigation.state.routeName === 'HeaderTest' &&
<Button
title="Toggle Header"
onPress={() =>
navigation.setParams({
headerVisible: !navigation.state.params ||
!navigation.state.params.headerVisible,
})}
/>}
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</ScrollView>
);
const MyHomeScreen = ({ navigation }) => (
<MyNavScreen
banner="Home Screen"
navigation={navigation}
/>
<MyNavScreen banner="Home Screen" navigation={navigation} />
);
MyHomeScreen.navigationOptions = {
title: 'Welcome',
@@ -57,44 +48,48 @@ MyProfileScreen.navigationOptions = ({ navigation }) => ({
title: `${navigation.state.params.name}'s Profile!`,
});
const ProfileNavigator = StackNavigator({
Home: {
screen: MyHomeScreen,
const ProfileNavigator = StackNavigator(
{
Home: {
screen: MyHomeScreen,
},
Profile: {
path: 'people/:name',
screen: MyProfileScreen,
},
},
Profile: {
path: 'people/:name',
screen: MyProfileScreen,
},
}, {
navigationOptions: {
header: null,
},
});
{
navigationOptions: {
header: null,
},
}
);
const MyHeaderTestScreen = ({ navigation }) => (
<MyNavScreen
banner={`Full screen view`}
navigation={navigation}
/>
<MyNavScreen banner={`Full screen view`} navigation={navigation} />
);
MyHeaderTestScreen.navigationOptions = ({ navigation }) => {
const headerVisible = navigation.state.params && navigation.state.params.headerVisible;
const headerVisible =
navigation.state.params && navigation.state.params.headerVisible;
return {
header: headerVisible ? undefined : null,
title: 'Now you see me',
};
};
const ModalStack = StackNavigator({
Home: {
screen: MyHomeScreen,
const ModalStack = StackNavigator(
{
Home: {
screen: MyHomeScreen,
},
ProfileNavigator: {
screen: ProfileNavigator,
},
HeaderTest: { screen: MyHeaderTestScreen },
},
ProfileNavigator: {
screen: ProfileNavigator,
},
HeaderTest: {screen: MyHeaderTestScreen},
}, {
mode: 'modal',
});
{
mode: 'modal',
}
);
export default ModalStack;

View File

@@ -2,21 +2,14 @@
import React from 'react';
import {
StyleSheet,
Text,
} from 'react-native';
import { StyleSheet, Text } from 'react-native';
/**
* Used across examples as a screen placeholder.
*/
import type { Children } from 'react';
import type { Children } from 'react';
const SampleText = ({
children
}: {
children?: Children
}) => (
const SampleText = ({ children }: { children?: Children }) => (
<Text style={styles.sampleText}>{children}</Text>
);

View File

@@ -3,13 +3,8 @@
*/
import React from 'react';
import {
Button,
ScrollView,
} from 'react-native';
import {
StackNavigator,
} from 'react-navigation';
import { Button, ScrollView } from 'react-native';
import { StackNavigator } from 'react-navigation';
import SampleText from './SampleText';
const MyNavScreen = ({ navigation, banner }) => (
@@ -23,18 +18,12 @@ const MyNavScreen = ({ navigation, banner }) => (
onPress={() => navigation.navigate('Photos', { name: 'Jane' })}
title="Go to a photos screen"
/>
<Button
onPress={() => navigation.goBack(null)}
title="Go back"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</ScrollView>
);
const MyHomeScreen = ({ navigation }) => (
<MyNavScreen
banner="Home Screen"
navigation={navigation}
/>
<MyNavScreen banner="Home Screen" navigation={navigation} />
);
MyHomeScreen.navigationOptions = {
title: 'Welcome',
@@ -52,18 +41,15 @@ MyPhotosScreen.navigationOptions = {
const MyProfileScreen = ({ navigation }) => (
<MyNavScreen
banner={
`${navigation.state.params.mode === 'edit' ? 'Now Editing ' : ''
}${navigation.state.params.name}'s Profile`
}
banner={`${navigation.state.params.mode === 'edit' ? 'Now Editing ' : ''}${navigation.state.params.name}'s Profile`}
navigation={navigation}
/>
);
MyProfileScreen.navigationOptions = props => {
const {navigation} = props;
const {state, setParams} = navigation;
const {params} = state;
const { navigation } = props;
const { state, setParams } = navigation;
const { params } = state;
return {
headerTitle: `${params.name}'s Profile!`,
// Render a button on the right side of the header.
@@ -71,7 +57,8 @@ MyProfileScreen.navigationOptions = props => {
headerRight: (
<Button
title={params.mode === 'edit' ? 'Done' : 'Edit'}
onPress={() => setParams({ mode: params.mode === 'edit' ? '' : 'edit' })}
onPress={() =>
setParams({ mode: params.mode === 'edit' ? '' : 'edit' })}
/>
),
};

View File

@@ -3,15 +3,8 @@
*/
import React from 'react';
import {
Button,
Platform,
ScrollView,
StyleSheet,
} from 'react-native';
import {
TabNavigator,
} from 'react-navigation';
import { Button, Platform, ScrollView, StyleSheet } from 'react-native';
import { TabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import SampleText from './SampleText';
@@ -26,18 +19,12 @@ const MyNavScreen = ({ navigation, banner }) => (
onPress={() => navigation.navigate('Settings')}
title="Go to settings tab"
/>
<Button
onPress={() => navigation.goBack(null)}
title="Go back"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</ScrollView>
);
const MyHomeScreen = ({ navigation }) => (
<MyNavScreen
banner="Home Tab"
navigation={navigation}
/>
<MyNavScreen banner="Home Tab" navigation={navigation} />
);
MyHomeScreen.navigationOptions = {
@@ -52,10 +39,7 @@ MyHomeScreen.navigationOptions = {
};
const MyPeopleScreen = ({ navigation }) => (
<MyNavScreen
banner="People Tab"
navigation={navigation}
/>
<MyNavScreen banner="People Tab" navigation={navigation} />
);
MyPeopleScreen.navigationOptions = {
@@ -70,10 +54,7 @@ MyPeopleScreen.navigationOptions = {
};
const MyChatScreen = ({ navigation }) => (
<MyNavScreen
banner="Chat Tab"
navigation={navigation}
/>
<MyNavScreen banner="Chat Tab" navigation={navigation} />
);
MyChatScreen.navigationOptions = {
@@ -88,10 +69,7 @@ MyChatScreen.navigationOptions = {
};
const MySettingsScreen = ({ navigation }) => (
<MyNavScreen
banner="Settings Tab"
navigation={navigation}
/>
<MyNavScreen banner="Settings Tab" navigation={navigation} />
);
MySettingsScreen.navigationOptions = {
@@ -105,28 +83,31 @@ MySettingsScreen.navigationOptions = {
),
};
const SimpleTabs = TabNavigator({
Home: {
screen: MyHomeScreen,
path: '',
const SimpleTabs = TabNavigator(
{
Home: {
screen: MyHomeScreen,
path: '',
},
People: {
screen: MyPeopleScreen,
path: 'cart',
},
Chat: {
screen: MyChatScreen,
path: 'chat',
},
Settings: {
screen: MySettingsScreen,
path: 'settings',
},
},
People: {
screen: MyPeopleScreen,
path: 'cart',
},
Chat: {
screen: MyChatScreen,
path: 'chat',
},
Settings: {
screen: MySettingsScreen,
path: 'settings',
},
}, {
tabBarOptions: {
activeTintColor: Platform.OS === 'ios' ? '#e91e63' : '#fff',
},
});
{
tabBarOptions: {
activeTintColor: Platform.OS === 'ios' ? '#e91e63' : '#fff',
},
}
);
const styles = StyleSheet.create({
container: {

View File

@@ -3,14 +3,8 @@
*/
import React from 'react';
import {
Button,
ScrollView,
} from 'react-native';
import {
StackNavigator,
TabNavigator,
} from 'react-navigation';
import { Button, ScrollView } from 'react-native';
import { StackNavigator, TabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import SampleText from './SampleText';
@@ -30,18 +24,12 @@ const MyNavScreen = ({ navigation, banner }) => (
onPress={() => navigation.navigate('SettingsTab')}
title="Go to settings tab"
/>
<Button
onPress={() => navigation.goBack(null)}
title="Go back"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</ScrollView>
);
const MyHomeScreen = ({ navigation }) => (
<MyNavScreen
banner="Home Screen"
navigation={navigation}
/>
<MyNavScreen banner="Home Screen" navigation={navigation} />
);
const MyProfileScreen = ({ navigation }) => (
@@ -52,17 +40,11 @@ const MyProfileScreen = ({ navigation }) => (
);
const MyNotificationsSettingsScreen = ({ navigation }) => (
<MyNavScreen
banner="Notifications Screen"
navigation={navigation}
/>
<MyNavScreen banner="Notifications Screen" navigation={navigation} />
);
const MySettingsScreen = ({ navigation }) => (
<MyNavScreen
banner="Settings Screen"
navigation={navigation}
/>
<MyNavScreen banner="Settings Screen" navigation={navigation} />
);
const MainTab = StackNavigator({
@@ -98,39 +80,42 @@ const SettingsTab = StackNavigator({
},
});
const StacksInTabs = TabNavigator({
MainTab: {
screen: MainTab,
path: '/',
navigationOptions: {
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home-outline'}
size={26}
style={{ color: tintColor }}
/>
),
const StacksInTabs = TabNavigator(
{
MainTab: {
screen: MainTab,
path: '/',
navigationOptions: {
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home-outline'}
size={26}
style={{ color: tintColor }}
/>
),
},
},
SettingsTab: {
screen: SettingsTab,
path: '/settings',
navigationOptions: {
tabBarLabel: 'Settings',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-settings' : 'ios-settings-outline'}
size={26}
style={{ color: tintColor }}
/>
),
},
},
},
SettingsTab: {
screen: SettingsTab,
path: '/settings',
navigationOptions: {
tabBarLabel: 'Settings',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-settings' : 'ios-settings-outline'}
size={26}
style={{ color: tintColor }}
/>
),
},
},
}, {
tabBarPosition: 'bottom',
animationEnabled: false,
swipeEnabled: false,
});
{
tabBarPosition: 'bottom',
animationEnabled: false,
swipeEnabled: false,
}
);
export default StacksInTabs;

View File

@@ -3,14 +3,8 @@
*/
import React from 'react';
import {
Button,
ScrollView,
} from 'react-native';
import {
StackNavigator,
TabNavigator,
} from 'react-navigation';
import { Button, ScrollView } from 'react-native';
import { StackNavigator, TabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import SampleText from './SampleText';
@@ -30,18 +24,12 @@ const MyNavScreen = ({ navigation, banner }) => (
onPress={() => navigation.navigate('SettingsTab')}
title="Go to settings tab"
/>
<Button
onPress={() => navigation.goBack(null)}
title="Go back"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</ScrollView>
);
const MyHomeScreen = ({ navigation }) => (
<MyNavScreen
banner="Home Screen"
navigation={navigation}
/>
<MyNavScreen banner="Home Screen" navigation={navigation} />
);
const MyProfileScreen = ({ navigation }) => (
@@ -52,54 +40,51 @@ const MyProfileScreen = ({ navigation }) => (
);
const MyNotificationsSettingsScreen = ({ navigation }) => (
<MyNavScreen
banner="Notifications Screen"
navigation={navigation}
/>
<MyNavScreen banner="Notifications Screen" navigation={navigation} />
);
const MySettingsScreen = ({ navigation }) => (
<MyNavScreen
banner="Settings Screen"
navigation={navigation}
/>
<MyNavScreen banner="Settings Screen" navigation={navigation} />
);
const TabNav = TabNavigator({
MainTab: {
screen: MyHomeScreen,
path: '/',
navigationOptions: {
title: 'Welcome',
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home-outline'}
size={26}
style={{ color: tintColor }}
/>
),
const TabNav = TabNavigator(
{
MainTab: {
screen: MyHomeScreen,
path: '/',
navigationOptions: {
title: 'Welcome',
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home-outline'}
size={26}
style={{ color: tintColor }}
/>
),
},
},
SettingsTab: {
screen: MySettingsScreen,
path: '/settings',
navigationOptions: {
title: 'Settings',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-settings' : 'ios-settings-outline'}
size={26}
style={{ color: tintColor }}
/>
),
},
},
},
SettingsTab: {
screen: MySettingsScreen,
path: '/settings',
navigationOptions: {
title: 'Settings',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-settings' : 'ios-settings-outline'}
size={26}
style={{ color: tintColor }}
/>
),
},
},
}, {
tabBarPosition: 'bottom',
animationEnabled: false,
swipeEnabled: false,
});
{
tabBarPosition: 'bottom',
animationEnabled: false,
swipeEnabled: false,
}
);
const StacksOverTabs = StackNavigator({
Root: {
@@ -115,7 +100,7 @@ const StacksOverTabs = StackNavigator({
screen: MyProfileScreen,
path: '/people/:name',
navigationOptions: ({ navigation }) => {
title: `${navigation.state.params.name}'s Profile!`
title: `${navigation.state.params.name}'s Profile!`;
},
},
});

View File

@@ -3,16 +3,8 @@
*/
import React from 'react';
import {
Button,
Platform,
ScrollView,
StyleSheet,
} from 'react-native';
import {
TabNavigator,
DrawerNavigator,
} from 'react-navigation';
import { Button, Platform, ScrollView, StyleSheet } from 'react-native';
import { TabNavigator, DrawerNavigator } from 'react-navigation';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import SimpleTabs from './SimpleTabs';
import StacksOverTabs from './StacksOverTabs';

View File

@@ -6,6 +6,7 @@
"test": "jest"
},
"dependencies": {
"prop-types": "^15.5.10",
"react": "16.0.0-alpha.6",
"react-native": "0.43.3",
"react-redux": "5.0.4",

View File

@@ -22,7 +22,8 @@ const mapStateToProps = state => ({
const mapDispatchToProps = dispatch => ({
logout: () => dispatch({ type: 'Logout' }),
loginScreen: () => dispatch(NavigationActions.navigate({ routeName: 'Login' })),
loginScreen: () =>
dispatch(NavigationActions.navigate({ routeName: 'Login' })),
});
export default connect(mapStateToProps, mapDispatchToProps)(AuthButton);

View File

@@ -1,10 +1,5 @@
import React, { PropTypes } from 'react';
import {
Button,
StyleSheet,
Text,
View,
} from 'react-native';
import { Button, StyleSheet, Text, View } from 'react-native';
const styles = StyleSheet.create({
container: {

View File

@@ -1,11 +1,6 @@
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import {
Button,
StyleSheet,
Text,
View,
} from 'react-native';
import { Button, StyleSheet, Text, View } from 'react-native';
import { NavigationActions } from 'react-navigation';
const styles = StyleSheet.create({
@@ -26,7 +21,8 @@ const LoginStatusMessage = ({ isLoggedIn, dispatch }) => {
{'You are "logged in" right now'}
</Text>
<Button
onPress={() => dispatch(NavigationActions.navigate({ routeName: 'Profile' }))}
onPress={() =>
dispatch(NavigationActions.navigate({ routeName: 'Profile' }))}
title="Profile"
/>
</View>

View File

@@ -1,9 +1,5 @@
import React from 'react';
import {
StyleSheet,
Text,
View,
} from 'react-native';
import { StyleSheet, Text, View } from 'react-native';
const styles = StyleSheet.create({
container: {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { addNavigationHelpers, StackNavigator } from 'react-navigation';

View File

@@ -7,16 +7,25 @@ import { AppNavigator } from '../navigators/AppNavigator';
const firstAction = AppNavigator.router.getActionForPathAndParams('Main');
const tempNavState = AppNavigator.router.getStateForAction(firstAction);
const secondAction = AppNavigator.router.getActionForPathAndParams('Login');
const initialNavState = AppNavigator.router.getStateForAction(secondAction, tempNavState);
const initialNavState = AppNavigator.router.getStateForAction(
secondAction,
tempNavState
);
function nav(state = initialNavState, action) {
let nextState;
switch (action.type) {
case 'Login':
nextState = AppNavigator.router.getStateForAction(NavigationActions.back(), state);
nextState = AppNavigator.router.getStateForAction(
NavigationActions.back(),
state
);
break;
case 'Logout':
nextState = AppNavigator.router.getStateForAction(NavigationActions.navigate({ routeName: 'Login' }), state);
nextState = AppNavigator.router.getStateForAction(
NavigationActions.navigate({ routeName: 'Login' }),
state
);
break;
default:
nextState = AppNavigator.router.getStateForAction(action, state);

View File

@@ -2471,7 +2471,7 @@ longest@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
loose-envify@^1.0.0, loose-envify@^1.1.0:
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
dependencies:
@@ -2908,6 +2908,13 @@ prop-types@^15.0.0, prop-types@^15.5.8:
dependencies:
fbjs "^0.8.9"
prop-types@^15.5.10:
version "15.5.10"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
dependencies:
fbjs "^0.8.9"
loose-envify "^1.3.1"
prr@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"

View File

@@ -1,4 +1,7 @@
/* eslint-env jest */
/**
* @flow
* eslint-env jest
*/
// See https://github.com/facebook/jest/issues/2208
jest.mock('Linking', () => ({
@@ -6,16 +9,20 @@ jest.mock('Linking', () => ({
removeEventListener: jest.fn(),
openURL: jest.fn(),
canOpenURL: jest.fn(),
getInitialURL: jest.fn().mockImplementation((value: string) => Promise.resolve(value)),
getInitialURL: jest
.fn()
.mockImplementation((value: string) => Promise.resolve(value)),
}));
// See https://github.com/facebook/react-native/issues/11659
jest.mock('ScrollView', () => {
// $FlowExpectedError
const RealComponent = require.requireActual('ScrollView');
class ScrollView extends RealComponent {
scrollTo = () => {}
scrollTo = () => {};
}
return ScrollView;
});
// $FlowExpectedError
Date.now = jest.fn(() => 0);

View File

@@ -29,8 +29,8 @@
"run-playground-android": "cd examples/NavigationPlayground && react-native run-android",
"test": "npm run lint && npm run flow && npm run jest",
"jest": "jest",
"lint": "eslint src",
"format": "eslint --fix src",
"lint": "eslint .",
"format": "eslint --fix .",
"flow": "flow",
"prepublish": "npm run clean && npm run build"
},
@@ -40,27 +40,27 @@
"src"
],
"devDependencies": {
"babel-cli": "^6.24.0",
"babel-core": "^6.24.0",
"babel-eslint": "^7.0.0",
"babel-jest": "^19.0.0",
"babel-plugin-flow-react-proptypes": "^1.2.0",
"babel-preset-es2015": "^6.24.0",
"babel-preset-react": "^6.23.0",
"babel-preset-react-native": "^1.9.0",
"babel-cli": "^6.24.1",
"babel-core": "^6.24.1",
"babel-eslint": "^7.2.3",
"babel-jest": "^20.0.1",
"babel-plugin-flow-react-proptypes": "^2.2.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-react-native": "^1.9.2",
"babel-preset-react-native-syntax": "^1.0.0",
"babel-preset-stage-1": "^6.16.0",
"eslint": "^3.17.1",
"eslint-config-airbnb": "^14.1.0",
"eslint-config-prettier": "^1.5.0",
"eslint-plugin-flowtype": "^2.30.3",
"babel-preset-stage-1": "^6.24.1",
"eslint": "^3.19.0",
"eslint-config-prettier": "^2.1.0",
"eslint-plugin-flowtype": "^2.33.0",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-jsx-a11y": "^4.0.0",
"eslint-plugin-jsx-a11y": "^5.0.1",
"eslint-plugin-prettier": "^2.0.1",
"eslint-plugin-react": "^6.10.0",
"flow-bin": "^0.40.0",
"jest": "^19.0.2",
"prettier": "^0.22.0",
"eslint-plugin-react": "^7.0.1",
"flow-bin": "0.40.0",
"jest": "^20.0.1",
"prettier": "^1.3.1",
"prettier-eslint": "^6.2.2",
"react": "16.0.0-alpha.6",
"react-native": "^0.43.2",
"react-native-vector-icons": "^3.0.0",
@@ -72,11 +72,11 @@
},
"dependencies": {
"clamp": "^1.0.1",
"fbjs": "^0.8.5",
"fbjs": "^0.8.12",
"hoist-non-react-statics": "^1.2.0",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.5.8",
"react-native-drawer-layout-polyfill": "1.2.0",
"prop-types": "^15.5.10",
"react-native-drawer-layout-polyfill": "^1.3.0",
"react-native-tab-view": "^0.0.65"
},
"jest": {

View File

@@ -10,23 +10,27 @@
const blacklist = require('react-native/packager/blacklist');
const config = require('react-native/packager/rn-cli.config');
const examples = [
'NavigationPlayground',
'ReduxExample',
];
const examples = ['NavigationPlayground', 'ReduxExample'];
config.getBlacklist = () => (
examples.reduce((a, example) => a.concat([
...config.getBlacklistForExample(example),
new RegExp(`examples/${example}/__exponent/(.*)`),
]), [])
);
config.getBlacklist = () =>
examples.reduce(
(a, example) =>
a.concat([
...config.getBlacklistForExample(example),
new RegExp(`examples/${example}/__exponent/(.*)`),
]),
[]
);
config.getBlacklistForExample = (example) => ([
...examples.filter(x => x !== example).map(x => new RegExp(`examples/${x}/node_modules/react-native/(.*)`)),
...examples.filter(x => x !== example).map(x => new RegExp(`examples/${x}/node_modules/react/(.*)`)),
config.getBlacklistForExample = example => [
...examples
.filter(x => x !== example)
.map(x => new RegExp(`examples/${x}/node_modules/react-native/(.*)`)),
...examples
.filter(x => x !== example)
.map(x => new RegExp(`examples/${x}/node_modules/react/(.*)`)),
new RegExp(`examples/${example}/node_modules/react-navigation/(.*)`),
]);
];
config.getBlacklistRE = () => blacklist(config.getBlacklist());
@@ -34,9 +38,7 @@ config.getProjectRoots = () => getRoots();
config.getAssetRoots = () => getRoots();
function getRoots() {
return [
__dirname,
];
return [__dirname];
}
module.exports = config;

View File

@@ -17,7 +17,7 @@ function crawl(location) {
crawl('docs');
var names = files.map(function(file) {
const nameWithExt = file.split('docs'+path.sep)[1];
const nameWithExt = file.split('docs' + path.sep)[1];
const name = nameWithExt.split('.md')[0];
return name;
});
@@ -25,7 +25,12 @@ var names = files.map(function(file) {
var mdData = {};
names.map(function(name) {
mdData[name] = fs.readFileSync('docs'+path.sep+name+'.md', {encoding: 'utf8'});
mdData[name] = fs.readFileSync('docs' + path.sep + name + '.md', {
encoding: 'utf8',
});
});
fs.writeFileSync('website'+path.sep+'docs-dist.json', JSON.stringify(mdData));
fs.writeFileSync(
'website' + path.sep + 'docs-dist.json',
JSON.stringify(mdData)
);

View File

@@ -7,11 +7,10 @@ const RESET = namespacedAction('RESET');
const SET_PARAMS = namespacedAction('SET_PARAMS');
const URI = namespacedAction('URI');
const createAction = (type: string) =>
(payload: Object = {}) => ({
type,
...payload,
});
const createAction = (type: string) => (payload: Object = {}) => ({
type,
...payload,
});
const back = createAction(BACK);
const init = createAction(INIT);
@@ -44,7 +43,7 @@ const mapDeprecatedActionAndWarn = (action: Object) => {
"the 'actions' object.",
'See https://github.com/react-community/react-navigation/pull/120 for',
'more details.',
].join(' '),
].join(' ')
);
return {

View File

@@ -45,7 +45,7 @@ const StateUtils = {
invariant(
StateUtils.indexOf(state, route.key) === -1,
'should not push route with duplicated key %s',
route.key,
route.key
);
const routes = state.routes.slice();
@@ -126,7 +126,7 @@ const StateUtils = {
replaceAt(
state: NavigationState,
key: string,
route: NavigationRoute,
route: NavigationRoute
): NavigationState {
const index = StateUtils.indexOf(state, key);
return StateUtils.replaceAtIndex(state, index, route);
@@ -140,13 +140,13 @@ const StateUtils = {
replaceAtIndex(
state: NavigationState,
index: number,
route: NavigationRoute,
route: NavigationRoute
): NavigationState {
invariant(
!!state.routes[index],
'invalid index %s for replacing route %s',
index,
route.key,
route.key
);
if (state.routes[index] === route) {
@@ -171,11 +171,11 @@ const StateUtils = {
reset(
state: NavigationState,
routes: Array<NavigationRoute>,
index?: number,
index?: number
): NavigationState {
invariant(
routes.length && Array.isArray(routes),
'invalid routes to replace',
'invalid routes to replace'
);
const nextIndex: number = index === undefined ? routes.length - 1 : index;

View File

@@ -10,10 +10,14 @@ export type HeaderMode = 'float' | 'screen' | 'none';
export type HeaderProps = NavigationSceneRendererProps & {
mode: HeaderMode,
router: NavigationRouter<NavigationState, NavigationAction, NavigationStackScreenOptions>,
getScreenDetails: (
NavigationScene,
) => NavigationScreenDetails<NavigationStackScreenOptions>,
router: NavigationRouter<
NavigationState,
NavigationAction,
NavigationStackScreenOptions
>,
getScreenDetails: NavigationScene => NavigationScreenDetails<
NavigationStackScreenOptions
>,
style: Style,
};
@@ -69,7 +73,7 @@ export type NavigationStateRoute = NavigationLeafRoute & {
export type NavigationScreenOptionsGetter<Options, Action> = (
navigation: NavigationScreenProp<NavigationRoute, Action>,
screenProps?: {},
screenProps?: {}
) => Options;
export type NavigationRouter<State, Action, Options> = {
@@ -86,10 +90,12 @@ export type NavigationRouter<State, Action, Options> = {
*/
getActionForPathAndParams: (
path: string,
params?: NavigationParams,
params?: NavigationParams
) => ?Action,
getPathAndParamsForState: (state: State) => {
getPathAndParamsForState: (
state: State
) => {
path: string,
params?: NavigationParams,
},
@@ -113,7 +119,7 @@ export type NavigationScreenOption<T> =
| T
| ((
navigation: NavigationScreenProp<NavigationRoute, NavigationAction>,
config: T,
config: T
) => T);
export type Style =
@@ -141,11 +147,13 @@ export type NavigationScreenConfigProps = {
export type NavigationScreenConfig<Options> =
| Options
| (NavigationScreenConfigProps & ((
{
navigationOptions: NavigationScreenProp<NavigationRoute, NavigationAction>,
},
) => Options));
| (NavigationScreenConfigProps &
(({
navigationOptions: NavigationScreenProp<
NavigationRoute,
NavigationAction
>,
}) => Options));
export type NavigationComponent =
| NavigationScreenComponent<*, *>
@@ -215,7 +223,7 @@ export type NavigationStackViewConfig = {
};
export type NavigationStackScreenOptions = NavigationScreenOptions & {
header?: ?(React.Element<*> | ((HeaderProps) => React.Element<*>)),
header?: ?(React.Element<*> | (HeaderProps => React.Element<*>)),
headerTitle?: string | React.Element<*>,
headerTitleStyle?: Style,
headerTintColor?: string,
@@ -283,29 +291,29 @@ export type NavigationTabRouterConfig = {
export type NavigationTabScreenOptions = NavigationScreenOptions & {
tabBarIcon?:
| React.Element<*>
| ((
options: { tintColor: ?string, focused: boolean },
) => ?React.Element<*>),
| ((options: { tintColor: ?string, focused: boolean }) => ?React.Element<
*
>),
tabBarLabel?:
| string
| React.Element<*>
| ((
options: { tintColor: ?string, focused: boolean },
) => ?React.Element<*>),
| ((options: { tintColor: ?string, focused: boolean }) => ?React.Element<
*
>),
tabBarVisible?: boolean,
};
export type NavigationDrawerScreenOptions = NavigationScreenOptions & {
drawerIcon?:
| React.Element<*>
| ((
options: { tintColor: ?string, focused: boolean },
) => ?React.Element<*>),
| ((options: { tintColor: ?string, focused: boolean }) => ?React.Element<
*
>),
drawerLabel?:
| React.Element<*>
| ((
options: { tintColor: ?string, focused: boolean },
) => ?React.Element<*>),
| ((options: { tintColor: ?string, focused: boolean }) => ?React.Element<
*
>),
};
export type NavigationRouteConfigMap = {
@@ -326,7 +334,7 @@ export type NavigationScreenProp<S, A> = {
navigate: (
routeName: string,
params?: NavigationParams,
action?: NavigationAction,
action?: NavigationAction
) => boolean,
setParams: (newParams: NavigationParams) => boolean,
};
@@ -417,13 +425,13 @@ export type TransitionConfig = {
export type NavigationAnimationSetter = (
position: AnimatedValue,
newState: NavigationState,
lastState: NavigationState,
lastState: NavigationState
) => void;
export type NavigationSceneRenderer = () => ?React.Element<*>;
export type NavigationStyleInterpolator = (
props: NavigationSceneRendererProps,
props: NavigationSceneRendererProps
) => Style;
export type LayoutEvent = {

View File

@@ -42,14 +42,15 @@ describe('StateUtils', () => {
routes: [{ key: 'a', routeName }, { key: 'b', routeName }],
};
expect(NavigationStateUtils.push(state, { key: 'b', routeName })).toEqual(
newState,
newState
);
});
it('does not push duplicated route', () => {
const state = { index: 0, routes: [{ key: 'a', routeName }] };
expect(() =>
NavigationStateUtils.push(state, { key: 'a', routeName })).toThrow();
NavigationStateUtils.push(state, { key: 'a', routeName })
).toThrow();
});
// Pop
@@ -147,7 +148,7 @@ describe('StateUtils', () => {
routes: [{ key: 'a', routeName }, { key: 'c', routeName }],
};
expect(
NavigationStateUtils.replaceAt(state, 'b', { key: 'c', routeName }),
NavigationStateUtils.replaceAt(state, 'b', { key: 'c', routeName })
).toEqual(newState);
});
@@ -161,7 +162,7 @@ describe('StateUtils', () => {
routes: [{ key: 'a', routeName }, { key: 'c', routeName }],
};
expect(
NavigationStateUtils.replaceAtIndex(state, 1, { key: 'c', routeName }),
NavigationStateUtils.replaceAtIndex(state, 1, { key: 'c', routeName })
).toEqual(newState);
});
@@ -171,7 +172,7 @@ describe('StateUtils', () => {
routes: [{ key: 'a', routeName }, { key: 'b', routeName }],
};
expect(
NavigationStateUtils.replaceAtIndex(state, 1, state.routes[1]),
NavigationStateUtils.replaceAtIndex(state, 1, state.routes[1])
).toEqual(state);
});
@@ -189,7 +190,7 @@ describe('StateUtils', () => {
NavigationStateUtils.reset(state, [
{ key: 'x', routeName },
{ key: 'y', routeName },
]),
])
).toEqual(newState);
expect(() => {
@@ -210,15 +211,15 @@ describe('StateUtils', () => {
NavigationStateUtils.reset(
state,
[{ key: 'x', routeName }, { key: 'y', routeName }],
0,
),
0
)
).toEqual(newState);
expect(() => {
NavigationStateUtils.reset(
state,
[{ key: 'x', routeName }, { key: 'y', routeName }],
100,
100
);
}).toThrow();
});

View File

@@ -12,7 +12,7 @@ describe('addNavigationHelpers', () => {
addNavigationHelpers({
state: { key: 'A', routeName: 'Home' },
dispatch: mockedDispatch,
}).goBack('A'),
}).goBack('A')
).toEqual(true);
expect(mockedDispatch).toBeCalledWith({
type: NavigationActions.BACK,
@@ -29,7 +29,7 @@ describe('addNavigationHelpers', () => {
addNavigationHelpers({
state: { routeName: 'Home' },
dispatch: mockedDispatch,
}).goBack(),
}).goBack()
).toEqual(true);
expect(mockedDispatch).toBeCalledWith({ type: NavigationActions.BACK });
expect(mockedDispatch.mock.calls.length).toBe(1);
@@ -43,7 +43,7 @@ describe('addNavigationHelpers', () => {
addNavigationHelpers({
state: { routeName: 'Home' },
dispatch: mockedDispatch,
}).navigate('Profile', { name: 'Matt' }),
}).navigate('Profile', { name: 'Matt' })
).toEqual(true);
expect(mockedDispatch).toBeCalledWith({
type: NavigationActions.NAVIGATE,
@@ -61,7 +61,7 @@ describe('addNavigationHelpers', () => {
addNavigationHelpers({
state: { key: 'B', routeName: 'Settings' },
dispatch: mockedDispatch,
}).setParams({ notificationsEnabled: 'yes' }),
}).setParams({ notificationsEnabled: 'yes' })
).toEqual(true);
expect(mockedDispatch).toBeCalledWith({
type: NavigationActions.SET_PARAMS,

View File

@@ -19,19 +19,19 @@ export default function<S: *>(navigation: NavigationProp<S, NavigationAction>) {
navigation.dispatch(
NavigationActions.back({
key: key === undefined ? navigation.state.key : key,
}),
})
),
navigate: (
routeName: string,
params?: NavigationParams,
action?: NavigationAction,
action?: NavigationAction
): boolean =>
navigation.dispatch(
NavigationActions.navigate({
routeName,
params,
action,
}),
})
),
/**
* For updating current route params. For example the nav bar title and
@@ -43,7 +43,7 @@ export default function<S: *>(navigation: NavigationProp<S, NavigationAction>) {
NavigationActions.setParams({
params,
key: navigation.state.key,
}),
})
),
};
}

View File

@@ -19,7 +19,7 @@ type NavigationContainerProps = {
onNavigationStateChange?: (
NavigationState,
NavigationState,
NavigationAction,
NavigationAction
) => void,
};
@@ -37,11 +37,11 @@ type State = {
*/
export default function createNavigationContainer<T: *>(
Component: ReactClass<NavigationNavigatorProps<T>>,
containerOptions?: {},
containerOptions?: {}
) {
invariant(
typeof containerOptions === 'undefined',
'containerOptions.URIPrefix has been removed. Pass the uriPrefix prop to the navigator instead',
'containerOptions.URIPrefix has been removed. Pass the uriPrefix prop to the navigator instead'
);
class NavigationContainer extends React.Component<void, Props<T>, State> {
@@ -75,11 +75,7 @@ export default function createNavigationContainer<T: *>(
return;
}
const {
navigation,
screenProps,
...containerProps
} = props;
const { navigation, screenProps, ...containerProps } = props;
const keys = Object.keys(containerProps);
@@ -88,7 +84,7 @@ export default function createNavigationContainer<T: *>(
'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.',
'navigator should maintain its own state, do not pass a navigation prop.'
);
}
@@ -119,7 +115,7 @@ export default function createNavigationContainer<T: *>(
_onNavigationStateChange(
prevNav: NavigationState,
nav: NavigationState,
action: NavigationAction,
action: NavigationAction
) {
if (
typeof this.props.onNavigationStateChange === 'undefined' &&
@@ -158,14 +154,15 @@ export default function createNavigationContainer<T: *>(
}
this.subs = BackAndroid.addEventListener('backPress', () =>
this.dispatch(NavigationActions.back()));
this.dispatch(NavigationActions.back())
);
Linking.addEventListener('url', ({ url }: { url: string }) => {
this._handleOpenURL(url);
});
Linking.getInitialURL().then(
(url: string) => url && this._handleOpenURL(url),
(url: string) => url && this._handleOpenURL(url)
);
}
@@ -182,7 +179,8 @@ export default function createNavigationContainer<T: *>(
const nav = Component.router.getStateForAction(action, state.nav);
if (nav && nav !== state.nav) {
this.setState({ nav }, () =>
this._onNavigationStateChange(state.nav, nav, action));
this._onNavigationStateChange(state.nav, nav, action)
);
return true;
}
return false;

View File

@@ -18,10 +18,10 @@ import type {
NavigationTabRouterConfig,
} from '../TypeDefinition';
export type DrawerNavigatorConfig =
& { containerConfig?: void }
& NavigationTabRouterConfig
& DrawerViewConfig;
export type DrawerNavigatorConfig = {
containerConfig?: void,
} & NavigationTabRouterConfig &
DrawerViewConfig;
const DefaultDrawerConfig = {
/*
@@ -36,7 +36,7 @@ const DefaultDrawerConfig = {
const DrawerNavigator = (
routeConfigs: NavigationRouteConfigMap,
config: DrawerNavigatorConfig,
config: DrawerNavigatorConfig
) => {
const mergedConfig = { ...DefaultDrawerConfig, ...config };
const {
@@ -57,7 +57,7 @@ const DrawerNavigator = (
contentRouter,
routeConfigs,
config,
NavigatorTypes.DRAWER,
NavigatorTypes.DRAWER
)((props: *) => <DrawerScreen {...props} />),
},
DrawerOpen: {
@@ -66,14 +66,14 @@ const DrawerNavigator = (
},
{
initialRouteName: 'DrawerClose',
},
}
);
const navigator = createNavigator(
drawerRouter,
routeConfigs,
config,
NavigatorTypes.DRAWER,
NavigatorTypes.DRAWER
)((props: *) => (
<DrawerView
{...props}

View File

@@ -13,14 +13,14 @@ import type {
NavigationRouteConfigMap,
} from '../TypeDefinition';
export type StackNavigatorConfig =
& { containerOptions?: void }
& NavigationStackViewConfig
& NavigationStackRouterConfig;
export type StackNavigatorConfig = {
containerOptions?: void,
} & NavigationStackViewConfig &
NavigationStackRouterConfig;
export default (
routeConfigMap: NavigationRouteConfigMap,
stackConfig: StackNavigatorConfig = {},
stackConfig: StackNavigatorConfig = {}
) => {
const {
initialRouteName,
@@ -47,7 +47,7 @@ export default (
router,
routeConfigMap,
stackConfig,
NavigatorTypes.STACK,
NavigatorTypes.STACK
)((props: *) => (
<CardStackTransitioner
{...props}

View File

@@ -19,14 +19,14 @@ import type {
NavigationTabRouterConfig,
} from '../TypeDefinition';
export type TabNavigatorConfig =
& { containerOptions?: void }
& NavigationTabRouterConfig
& TabViewConfig;
export type TabNavigatorConfig = {
containerOptions?: void,
} & NavigationTabRouterConfig &
TabViewConfig;
const TabNavigator = (
routeConfigs: NavigationRouteConfigMap,
config: TabNavigatorConfig = {},
config: TabNavigatorConfig = {}
) => {
// Use the look native to the platform by default
const mergedConfig = { ...TabNavigator.Presets.Default, ...config };
@@ -46,7 +46,7 @@ const TabNavigator = (
router,
routeConfigs,
config,
NavigatorTypes.STACK,
NavigatorTypes.STACK
)((props: *) => (
<TabView
{...props}

View File

@@ -18,24 +18,23 @@ const createNavigator = (
router: NavigationRouter<*, *, *>,
routeConfigs: NavigationRouteConfigMap,
navigatorConfig: any,
navigatorType: NavigatorType,
) =>
(View: NavigationNavigator<*, *, *, *>) => {
class Navigator extends React.Component {
props: NavigationNavigatorProps<*>;
navigatorType: NavigatorType
) => (View: NavigationNavigator<*, *, *, *>) => {
class Navigator extends React.Component {
props: NavigationNavigatorProps<*>;
static router = router;
static router = router;
static routeConfigs = routeConfigs;
static navigatorConfig = navigatorConfig;
static navigatorType = navigatorType;
static routeConfigs = routeConfigs;
static navigatorConfig = navigatorConfig;
static navigatorType = navigatorType;
render() {
return <View {...this.props} router={router} />;
}
render() {
return <View {...this.props} router={router} />;
}
}
return Navigator;
};
return Navigator;
};
export default createNavigator;

View File

@@ -30,7 +30,7 @@ function _getUuid() {
export default (
routeConfigs: NavigationRouteConfigMap,
stackConfig: NavigationStackRouterConfig = {},
stackConfig: NavigationStackRouterConfig = {}
): NavigationRouter<*, *, *> => {
// Fail fast on invalid route definitions
validateRouteConfigMap(routeConfigs);
@@ -49,9 +49,7 @@ export default (
}
});
const {
initialRouteParams,
} = stackConfig;
const { initialRouteParams } = stackConfig;
const initialRouteName = stackConfig.initialRouteName || routeNames[0];
@@ -90,7 +88,7 @@ export default (
getStateForAction(
passedAction: NavigationStackAction,
state: ?NavigationState,
state: ?NavigationState
) {
const action = NavigationActions.mapDeprecatedActionAndWarn(passedAction);
@@ -117,7 +115,7 @@ export default (
NavigationActions.navigate({
routeName: initialRouteName,
params: initialRouteParams,
}),
})
);
}
const params = (route.params ||
@@ -167,8 +165,8 @@ export default (
const childRouter = childRouters[action.routeName];
let route;
if (childRouter) {
const childAction = action.action ||
NavigationActions.init({ params: action.params });
const childAction =
action.action || NavigationActions.init({ params: action.params });
route = {
params: action.params,
...childRouter.getStateForAction(childAction),
@@ -194,12 +192,12 @@ export default (
if (childRouter) {
// For each child router, start with a blank state
const initChildRoute = childRouter.getStateForAction(
NavigationActions.init(),
NavigationActions.init()
);
// Then check to see if the router handles our navigate action
const navigatedChildRoute = childRouter.getStateForAction(
action,
initChildRoute,
initChildRoute
);
let routeToPush = null;
if (navigatedChildRoute === null) {
@@ -223,7 +221,7 @@ export default (
if (action.type === NavigationActions.SET_PARAMS) {
const lastRoute = state.routes.find(
/* $FlowFixMe */
(route: *) => route.key === action.key,
(route: *) => route.key === action.key
);
if (lastRoute) {
const params = {
@@ -264,7 +262,7 @@ export default (
};
delete route.type;
return route;
},
}
),
index: action.index,
};
@@ -275,7 +273,7 @@ export default (
if (action.key) {
const backRoute = state.routes.find(
/* $FlowFixMe */
(route: *) => route.key === action.key,
(route: *) => route.key === action.key
);
/* $FlowFixMe */
backRouteIndex = state.routes.indexOf(backRoute);
@@ -295,7 +293,7 @@ export default (
},
getPathAndParamsForState(
state: NavigationState,
state: NavigationState
): { path: string, params?: NavigationParams } {
const route = state.routes[state.index];
const routeName = route.routeName;
@@ -359,14 +357,15 @@ export default (
if (childRouters[matchedRouteName]) {
nestedAction = childRouters[matchedRouteName].getActionForPathAndParams(
/* $FlowFixMe */
pathMatch.slice(pathMatchKeys.length).join('/'),
pathMatch.slice(pathMatchKeys.length).join('/')
);
}
// reduce the items of the query string. any query params may
// be overridden by path params
const queryParams = (queryString || '').split('&').reduce(
(result: *, item: string) => {
const queryParams = (queryString || '')
.split('&')
.reduce((result: *, item: string) => {
if (item !== '') {
const nextResult = result || {};
const [key, value] = item.split('=');
@@ -374,15 +373,14 @@ export default (
return nextResult;
}
return result;
},
null,
);
}, null);
// reduce the matched pieces of the path into the params
// of the route. `params` is null if there are no params.
/* $FlowFixMe */
const params = pathMatch.slice(1).reduce(
(result: *, matchResult: *, i: number) => {
const params = pathMatch
.slice(1)
.reduce((result: *, matchResult: *, i: number) => {
const key = pathMatchKeys[i];
if (key.asterisk || !key) {
return result;
@@ -391,9 +389,7 @@ export default (
const paramName = key.name;
nextResult[paramName] = matchResult;
return nextResult;
},
queryParams,
);
}, queryParams);
return NavigationActions.navigate({
routeName: matchedRouteName,
@@ -404,7 +400,7 @@ export default (
getScreenOptions: createConfigGetter(
routeConfigs,
stackConfig.navigationOptions,
stackConfig.navigationOptions
),
getScreenConfig: getScreenConfigDeprecated,

View File

@@ -24,7 +24,7 @@ import type {
export default (
routeConfigs: NavigationRouteConfigMap,
config: NavigationTabRouterConfig = {},
config: NavigationTabRouterConfig = {}
): NavigationRouter<*, *, *> => {
// Fail fast on invalid route definitions
validateRouteConfigMap(routeConfigs);
@@ -49,12 +49,12 @@ export default (
invariant(
initialRouteIndex !== -1,
`Invalid initialRouteName '${initialRouteName}' for TabRouter. ` +
`Should be one of ${order.map((n: *) => `"${n}"`).join(', ')}`,
`Should be one of ${order.map((n: *) => `"${n}"`).join(', ')}`
);
return {
getStateForAction(
action: NavigationAction | { action: NavigationAction },
inputState?: ?NavigationState,
inputState?: ?NavigationState
): ?NavigationState {
// eslint-disable-next-line no-param-reassign
action = NavigationActions.mapDeprecatedActionAndWarn(action);
@@ -65,7 +65,8 @@ export default (
const routes = order.map((routeName: string) => {
const tabRouter = tabRouters[routeName];
if (tabRouter) {
const childAction = action.action ||
const childAction =
action.action ||
NavigationActions.init({
...(action.params ? { params: action.params } : {}),
});
@@ -99,7 +100,7 @@ export default (
...route.params,
...params,
},
}: NavigationRoute),
}: NavigationRoute)
);
}
}
@@ -110,7 +111,7 @@ export default (
if (activeTabRouter) {
const activeTabState = activeTabRouter.getStateForAction(
action.action || action,
activeTabLastState,
activeTabLastState
);
if (!activeTabState && inputState) {
return null;
@@ -128,8 +129,8 @@ export default (
// Handle tab changing. Do this after letting the current tab try to
// handle the action, to allow inner tabs to change first
let activeTabIndex = state.index;
const isBackEligible = action.key == null ||
action.key === activeTabLastState.key;
const isBackEligible =
action.key == null || action.key === activeTabLastState.key;
if (
action.type === NavigationActions.BACK &&
isBackEligible &&
@@ -181,7 +182,7 @@ export default (
if (action.type === NavigationActions.SET_PARAMS) {
const lastRoute = state.routes.find(
/* $FlowFixMe */
(route: *) => route.key === action.key,
(route: *) => route.key === action.key
);
if (lastRoute) {
const params = {
@@ -249,13 +250,13 @@ export default (
},
getComponentForState(
state: NavigationState,
state: NavigationState
): NavigationScreenComponent<*, NavigationTabScreenOptions> {
const routeName = order[state.index];
invariant(
routeName,
`There is no route defined for index ${state.index}. Check that
that you passed in a navigation state with a valid tab/screen index.`,
that you passed in a navigation state with a valid tab/screen index.`
);
const childRouter = tabRouters[routeName];
if (childRouter) {
@@ -294,43 +295,46 @@ export default (
* This will return null if there is no action matched
*/
getActionForPathAndParams(path: string, params: ?NavigationParams) {
return order
.map((tabId: string) => {
const parts = path.split('/');
const pathToTest = paths[tabId];
if (parts[0] === pathToTest) {
const tabRouter = tabRouters[tabId];
const action: NavigationNavigateAction = NavigationActions.navigate(
{
routeName: tabId,
},
);
if (tabRouter && tabRouter.getActionForPathAndParams) {
action.action = tabRouter.getActionForPathAndParams(
parts.slice(1).join('/'),
params,
return (
order
.map((tabId: string) => {
const parts = path.split('/');
const pathToTest = paths[tabId];
if (parts[0] === pathToTest) {
const tabRouter = tabRouters[tabId];
const action: NavigationNavigateAction = NavigationActions.navigate(
{
routeName: tabId,
}
);
} else if (params) {
action.params = params;
if (tabRouter && tabRouter.getActionForPathAndParams) {
action.action = tabRouter.getActionForPathAndParams(
parts.slice(1).join('/'),
params
);
} else if (params) {
action.params = params;
}
return action;
}
return action;
}
return null;
})
.find((action: *) => !!action) ||
return null;
})
.find((action: *) => !!action) ||
order
.map((tabId: string) => {
const tabRouter = tabRouters[tabId];
return tabRouter &&
tabRouter.getActionForPathAndParams(path, params);
return (
tabRouter && tabRouter.getActionForPathAndParams(path, params)
);
})
.find((action: *) => !!action) ||
null;
null
);
},
getScreenOptions: createConfigGetter(
routeConfigs,
config.navigationOptions,
config.navigationOptions
),
getScreenConfig: getScreenConfigDeprecated,

View File

@@ -51,20 +51,20 @@ Object.keys(ROUTERS).forEach((routerName: string) => {
expect(
router.getScreenOptions(
addNavigationHelpers({ state: routes[0], dispatch: () => false }),
{},
).title,
{}
).title
).toEqual(undefined);
expect(
router.getScreenOptions(
addNavigationHelpers({ state: routes[1], dispatch: () => false }),
{},
).title,
{}
).title
).toEqual('BarTitle');
expect(
router.getScreenOptions(
addNavigationHelpers({ state: routes[2], dispatch: () => false }),
{},
).title,
{}
).title
).toEqual('Baz-123');
});
});
@@ -99,7 +99,7 @@ test('Handles no-op actions with tabs within stack router', () => {
expect(state1).toEqual(state2);
const state3 = TestRouter.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Zap' },
state2,
state2
);
expect(state2).toEqual(state3);
});
@@ -132,7 +132,7 @@ test('Handles deep action', () => {
routeName: 'Foo',
action: { type: NavigationActions.NAVIGATE, routeName: 'Zoo' },
},
state1,
state1
);
expect(state2 && state2.index).toEqual(1);
/* $FlowFixMe */
@@ -168,7 +168,7 @@ test('Supports lazily-evaluated getScreen', () => {
expect(state1).toEqual(state2);
const state3 = TestRouter.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Zap' },
state2,
state2
);
expect(state2).toEqual(state3);
});

View File

@@ -89,7 +89,7 @@ describe('StackRouter', () => {
{ key: 'b', routeName: 'bar' },
{ key: 'c', routeName: 'foo' },
],
}),
})
).toBe(FooScreen);
expect(
router.getComponentForState({
@@ -98,7 +98,7 @@ describe('StackRouter', () => {
{ key: 'a', routeName: 'foo' },
{ key: 'b', routeName: 'bar' },
],
}),
})
).toBe(BarScreen);
});
@@ -122,7 +122,7 @@ describe('StackRouter', () => {
{ key: 'b', routeName: 'bar' },
{ key: 'c', routeName: 'foo' },
],
}),
})
).toBe(FooScreen);
expect(
router.getComponentForState({
@@ -131,7 +131,7 @@ describe('StackRouter', () => {
{ key: 'a', routeName: 'foo' },
{ key: 'b', routeName: 'bar' },
],
}),
})
).toBe(BarScreen);
});
@@ -212,7 +212,7 @@ describe('StackRouter', () => {
test('Parses paths with a query', () => {
expect(
TestStackRouter.getActionForPathAndParams('people/foo?code=test&foo=bar'),
TestStackRouter.getActionForPathAndParams('people/foo?code=test&foo=bar')
).toEqual({
type: NavigationActions.NAVIGATE,
routeName: 'person',
@@ -226,7 +226,7 @@ describe('StackRouter', () => {
test('Parses paths with an empty query value', () => {
expect(
TestStackRouter.getActionForPathAndParams('people/foo?code=&foo=bar'),
TestStackRouter.getActionForPathAndParams('people/foo?code=&foo=bar')
).toEqual({
type: NavigationActions.NAVIGATE,
routeName: 'person',
@@ -329,7 +329,7 @@ describe('StackRouter', () => {
});
const pushedState = TestRouter.getStateForAction(
NavigationActions.navigate({ routeName: 'qux' }),
initState,
initState
);
// $FlowFixMe
expect(pushedState.index).toEqual(1);
@@ -366,7 +366,7 @@ describe('StackRouter', () => {
routeName: 'Bar',
params: { name: 'Zoom' },
},
state,
state
);
expect(state2 && state2.index).toEqual(1);
expect(state2 && state2.routes[1].routeName).toEqual('Bar');
@@ -374,7 +374,7 @@ describe('StackRouter', () => {
expect(state2 && state2.routes.length).toEqual(2);
const state3 = router.getStateForAction(
{ type: NavigationActions.BACK },
state2,
state2
);
expect(state3).toEqual({
index: 0,
@@ -419,7 +419,7 @@ describe('StackRouter', () => {
routeName: 'Bar',
params: { name: 'Zoom' },
},
state,
state
);
expect(state2 && state2.index).toEqual(1);
expect(state2 && state2.routes[1].routeName).toEqual('Bar');
@@ -427,7 +427,7 @@ describe('StackRouter', () => {
expect(state2 && state2.routes.length).toEqual(2);
const state3 = router.getStateForAction(
{ type: NavigationActions.BACK },
state2,
state2
);
expect(state3).toEqual({
index: 0,
@@ -458,7 +458,7 @@ describe('StackRouter', () => {
routeName: 'Bar',
params: { name: 'Zoom' },
},
state,
state
);
const state3 = router.getStateForAction(
{
@@ -466,16 +466,16 @@ describe('StackRouter', () => {
routeName: 'Bar',
params: { name: 'Foo' },
},
state2,
state2
);
const state4 = router.getStateForAction(
{ type: NavigationActions.BACK, key: 'wrongKey' },
state3,
state3
);
expect(state3).toEqual(state4);
const state5 = router.getStateForAction(
{ type: NavigationActions.BACK, key: state3 && state3.routes[1].key },
state4,
state4
);
expect(state5).toEqual(state);
});
@@ -492,7 +492,7 @@ describe('StackRouter', () => {
screen: BarScreen,
},
},
{ initialRouteName: 'Bar' },
{ initialRouteName: 'Bar' }
);
const state = router.getStateForAction({ type: NavigationActions.INIT });
expect(state).toEqual({
@@ -514,7 +514,7 @@ describe('StackRouter', () => {
screen: FooScreen,
},
},
{ initialRouteName: 'Bar', initialRouteParams: { foo: 'bar' } },
{ initialRouteName: 'Bar', initialRouteParams: { foo: 'bar' } }
);
const state = router.getStateForAction({ type: NavigationActions.INIT });
expect(state).toEqual({
@@ -547,7 +547,7 @@ describe('StackRouter', () => {
routeName: 'Bar',
params: { bar: '42' },
},
state,
state
);
expect(state2).not.toBeNull();
expect(state2 && state2.index).toEqual(1);
@@ -567,7 +567,7 @@ describe('StackRouter', () => {
{
initialRouteName: 'Bar',
initialRouteParams: { name: 'Zoo' },
},
}
);
const state = router.getStateForAction({ type: NavigationActions.INIT });
const state2 = router.getStateForAction(
@@ -576,7 +576,7 @@ describe('StackRouter', () => {
params: { name: 'Qux' },
key: 'Init-id-0-16',
},
state,
state
);
expect(state2 && state2.index).toEqual(0);
expect(state2 && state2.routes[0].params).toEqual({ name: 'Qux' });
@@ -604,7 +604,7 @@ describe('StackRouter', () => {
params: { name: 'foobar' },
key: 'Init-id-0-17',
},
state,
state
);
expect(state2 && state2.index).toEqual(0);
/* $FlowFixMe */
@@ -640,7 +640,7 @@ describe('StackRouter', () => {
],
index: 1,
},
state,
state
);
expect(state2 && state2.index).toEqual(1);
expect(state2 && state2.routes[0].params).toEqual({ bar: '42' });
@@ -673,7 +673,7 @@ describe('StackRouter', () => {
actions: [{ type: NavigationActions.NAVIGATE, routeName: 'Foo' }],
index: 0,
},
state,
state
);
expect(state2 && state2.index).toEqual(0);
@@ -707,7 +707,7 @@ describe('StackRouter', () => {
routeName: 'Foo',
action: { type: NavigationActions.NAVIGATE, routeName: 'baz' },
},
state,
state
);
const state3 = router.getStateForAction(
{
@@ -716,7 +716,7 @@ describe('StackRouter', () => {
actions: [{ type: NavigationActions.NAVIGATE, routeName: 'Foo' }],
index: 0,
},
state2,
state2
);
const state4 = router.getStateForAction(
{
@@ -725,7 +725,7 @@ describe('StackRouter', () => {
actions: [{ type: NavigationActions.NAVIGATE, routeName: 'Bar' }],
index: 0,
},
state3,
state3
);
expect(state4 && state4.index).toEqual(0);
@@ -747,7 +747,7 @@ describe('StackRouter', () => {
routeName: 'Bar',
params: { foo: '42' },
},
state,
state
);
expect(state2 && state2.routes[1].params).toEqual({ foo: '42' });
/* $FlowFixMe */
@@ -778,7 +778,7 @@ describe('StackRouter', () => {
routeName: 'Bar',
params: { foo: '42' },
},
state,
state
);
expect(state2 && state2.routes[1].params).toEqual({ foo: '42' });
/* $FlowFixMe */
@@ -806,7 +806,7 @@ describe('StackRouter', () => {
screen: () => <div />,
},
},
{ initialRouteName: 'Bar' },
{ initialRouteName: 'Bar' }
);
const action = router.getActionForPathAndParams('');
expect(action).toEqual({
@@ -889,7 +889,7 @@ describe('StackRouter', () => {
],
index: 1,
},
state,
state
);
expect(state2 && state2.index).toEqual(1);
expect(state2 && state2.routes[0].params).toEqual({ bar: '42' });

View File

@@ -30,7 +30,7 @@ describe('TabRouter', () => {
expect(state).toEqual(expectedState);
const state2 = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Bar' },
state,
state
);
const expectedState2 = {
index: 1,
@@ -44,7 +44,7 @@ describe('TabRouter', () => {
expect(router.getComponentForState(expectedState2)).toEqual(ScreenB);
const state3 = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Bar' },
state2,
state2
);
expect(state3).toEqual(null);
});
@@ -67,7 +67,7 @@ describe('TabRouter', () => {
expect(state).toEqual(expectedState);
const state2 = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Bar' },
state,
state
);
const expectedState2 = {
index: 1,
@@ -81,7 +81,7 @@ describe('TabRouter', () => {
expect(router.getComponentForState(expectedState2)).toEqual(ScreenB);
const state3 = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Bar' },
state2,
state2
);
expect(state3).toEqual(null);
});
@@ -89,7 +89,7 @@ describe('TabRouter', () => {
test('Can set the initial tab', () => {
const router = TabRouter(
{ Foo: BareLeafRouteConfig, Bar: BareLeafRouteConfig },
{ initialRouteName: 'Bar' },
{ initialRouteName: 'Bar' }
);
const state = router.getStateForAction({ type: NavigationActions.INIT });
expect(state).toEqual({
@@ -121,12 +121,12 @@ describe('TabRouter', () => {
test('getStateForAction returns null when navigating to same tab', () => {
const router = TabRouter(
{ Foo: BareLeafRouteConfig, Bar: BareLeafRouteConfig },
{ initialRouteName: 'Bar' },
{ initialRouteName: 'Bar' }
);
const state = router.getStateForAction({ type: NavigationActions.INIT });
const state2 = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Bar' },
state,
state
);
expect(state2).toEqual(null);
});
@@ -233,11 +233,11 @@ describe('TabRouter', () => {
// Ensure that navigating back and forth doesn't overwrite
state = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Bar' },
state,
state
);
state = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Boo' },
state,
state
);
expect(state && state.routes[1]).toEqual({
index: 0,
@@ -283,7 +283,7 @@ describe('TabRouter', () => {
});
const state2 = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Foo' },
state,
state
);
expect(state2).toEqual({
index: 1,
@@ -303,7 +303,7 @@ describe('TabRouter', () => {
});
const state3 = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Foo' },
state2,
state2
);
expect(state3).toEqual(null);
});
@@ -362,7 +362,7 @@ describe('TabRouter', () => {
});
const state2 = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Zap' },
state,
state
);
expect(state2).toEqual({
index: 0,
@@ -397,7 +397,7 @@ describe('TabRouter', () => {
});
const state3 = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'Zap' },
state2,
state2
);
expect(state3).toEqual(null);
const state4 = router.getStateForAction({
@@ -550,14 +550,14 @@ describe('TabRouter', () => {
test('Maps old actions (uses "getStateForAction returns null when navigating to same tab" test)', () => {
const router = TabRouter(
{ Foo: BareLeafRouteConfig, Bar: BareLeafRouteConfig },
{ initialRouteName: 'Bar' },
{ initialRouteName: 'Bar' }
);
/* $FlowFixMe: these are for deprecated action names */
const state = router.getStateForAction({ type: 'Init' });
/* $FlowFixMe: these are for deprecated action names */
const state2 = router.getStateForAction(
{ type: 'Navigate', routeName: 'Bar' },
state,
state
);
expect(state2).toEqual(null);
});
@@ -582,7 +582,7 @@ describe('TabRouter', () => {
const state1 = router.getStateForAction(
{ type: NavigationActions.NAVIGATE, routeName: 'b', params },
state0,
state0
);
expect(state1).toEqual({

View File

@@ -46,18 +46,19 @@ test('should get config for screen', () => {
}
}
const getScreenOptions: NavigationScreenOptionsGetter<NavigationStackScreenOptions, *> = createConfigGetter(
{
Home: { screen: HomeScreen },
Settings: { screen: SettingsScreen },
Notifications: {
screen: NotificationScreen,
navigationOptions: {
title: '10 new notifications',
},
const getScreenOptions: NavigationScreenOptionsGetter<
NavigationStackScreenOptions,
*
> = createConfigGetter({
Home: { screen: HomeScreen },
Settings: { screen: SettingsScreen },
Notifications: {
screen: NotificationScreen,
navigationOptions: {
title: '10 new notifications',
},
},
);
});
const routes = [
{ key: 'A', routeName: 'Home' },
@@ -70,50 +71,50 @@ test('should get config for screen', () => {
expect(
getScreenOptions(
addNavigationHelpers({ state: routes[0], dispatch: () => false }),
{},
).title,
{}
).title
).toEqual('Welcome anonymous');
expect(
getScreenOptions(
addNavigationHelpers({ state: routes[1], dispatch: () => false }),
{},
).title,
{}
).title
).toEqual('Welcome jane');
expect(
getScreenOptions(
addNavigationHelpers({ state: routes[0], dispatch: () => false }),
{},
).gesturesEnabled,
{}
).gesturesEnabled
).toEqual(true);
expect(
getScreenOptions(
addNavigationHelpers({ state: routes[2], dispatch: () => false }),
{},
).title,
{}
).title
).toEqual('Settings!!!');
expect(
getScreenOptions(
addNavigationHelpers({ state: routes[2], dispatch: () => false }),
{},
).gesturesEnabled,
{}
).gesturesEnabled
).toEqual(false);
expect(
getScreenOptions(
addNavigationHelpers({ state: routes[3], dispatch: () => false }),
{},
).title,
{}
).title
).toEqual('10 new notifications');
expect(
getScreenOptions(
addNavigationHelpers({ state: routes[3], dispatch: () => false }),
{},
).gesturesEnabled,
{}
).gesturesEnabled
).toEqual(true);
expect(
getScreenOptions(
addNavigationHelpers({ state: routes[4], dispatch: () => false }),
{},
).gesturesEnabled,
{}
).gesturesEnabled
).toEqual(false);
});
@@ -135,9 +136,10 @@ test('should throw if the route does not exist', () => {
expect(() =>
getScreenOptions(
addNavigationHelpers({ state: routes[0], dispatch: () => false }),
{},
)).toThrowError(
"There is no route defined for key Settings.\nMust be one of: 'Home'",
{}
)
).toThrowError(
"There is no route defined for key Settings.\nMust be one of: 'Home'"
);
});
@@ -152,6 +154,7 @@ test('should throw if the screen is not defined under the route config', () => {
expect(() =>
getScreenOptions(
addNavigationHelpers({ state: routes[0], dispatch: () => false }),
)).toThrowError('Route Home must define a screen or a getScreen.');
addNavigationHelpers({ state: routes[0], dispatch: () => false })
)
).toThrowError('Route Home must define a screen or a getScreen.');
});

View File

@@ -21,7 +21,7 @@ import type {
function applyConfig(
configurer: ?NavigationScreenConfig<*>,
navigationOptions: *,
configProps: NavigationScreenConfigProps,
configProps: NavigationScreenConfigProps
): * {
if (typeof configurer === 'function') {
return {
@@ -43,62 +43,61 @@ function applyConfig(
export default (
routeConfigs: NavigationRouteConfigMap,
navigatorScreenConfig?: NavigationScreenConfig<*>,
) =>
(
navigation: NavigationScreenProp<NavigationRoute, NavigationAction>,
screenProps: *,
) => {
const { state, dispatch } = navigation;
const route = state;
// $FlowFixMe
const { routes, index } = (route: NavigationStateRoute);
navigatorScreenConfig?: NavigationScreenConfig<*>
) => (
navigation: NavigationScreenProp<NavigationRoute, NavigationAction>,
screenProps: *
) => {
const { state, dispatch } = navigation;
const route = state;
// $FlowFixMe
const { routes, index } = (route: NavigationStateRoute);
invariant(
route.routeName && typeof route.routeName === 'string',
'Cannot get config because the route does not have a routeName.'
);
const Component = getScreenForRouteName(routeConfigs, route.routeName);
let outputConfig = {};
if (Component.router) {
invariant(
route.routeName && typeof route.routeName === 'string',
'Cannot get config because the route does not have a routeName.',
route && routes && index != null,
`Expect nav state to have routes and index, ${JSON.stringify(route)}`
);
const Component = getScreenForRouteName(routeConfigs, route.routeName);
let outputConfig = {};
if (Component.router) {
invariant(
route && routes && index != null,
`Expect nav state to have routes and index, ${JSON.stringify(route)}`,
);
const childRoute = routes[index];
const childNavigation = addNavigationHelpers({
state: childRoute,
dispatch,
});
outputConfig = Component.router.getScreenOptions(
childNavigation,
screenProps,
);
}
const routeConfig = routeConfigs[route.routeName];
const routeScreenConfig = routeConfig.navigationOptions;
const componentScreenConfig = Component.navigationOptions;
const configOptions = { navigation, screenProps: screenProps || {} };
outputConfig = applyConfig(
navigatorScreenConfig,
outputConfig,
configOptions,
const childRoute = routes[index];
const childNavigation = addNavigationHelpers({
state: childRoute,
dispatch,
});
outputConfig = Component.router.getScreenOptions(
childNavigation,
screenProps
);
outputConfig = applyConfig(
componentScreenConfig,
outputConfig,
configOptions,
);
outputConfig = applyConfig(routeScreenConfig, outputConfig, configOptions);
}
validateScreenOptions(outputConfig, route);
const routeConfig = routeConfigs[route.routeName];
return outputConfig;
};
const routeScreenConfig = routeConfig.navigationOptions;
const componentScreenConfig = Component.navigationOptions;
const configOptions = { navigation, screenProps: screenProps || {} };
outputConfig = applyConfig(
navigatorScreenConfig,
outputConfig,
configOptions
);
outputConfig = applyConfig(
componentScreenConfig,
outputConfig,
configOptions
);
outputConfig = applyConfig(routeScreenConfig, outputConfig, configOptions);
validateScreenOptions(outputConfig, route);
return outputConfig;
};

View File

@@ -6,5 +6,5 @@ import invariant from 'fbjs/lib/invariant';
export default () =>
invariant(
false,
'`getScreenConfig` has been replaced with `getScreenOptions`',
'`getScreenConfig` has been replaced with `getScreenOptions`'
);

View File

@@ -13,7 +13,7 @@ import type {
*/
export default function getScreenForRouteName( // eslint-disable-line consistent-return
routeConfigs: NavigationRouteConfigMap,
routeName: string,
routeName: string
): NavigationComponent {
const routeConfig = routeConfigs[routeName];
@@ -22,7 +22,7 @@ export default function getScreenForRouteName( // eslint-disable-line consistent
`There is no route defined for key ${routeName}.\n` +
`Must be one of: ${Object.keys(routeConfigs)
.map((a: string) => `'${a}'`)
.join(',')}`,
.join(',')}`
);
if (routeConfig.screen) {
@@ -36,7 +36,7 @@ export default function getScreenForRouteName( // eslint-disable-line consistent
`The getScreen defined for route '${routeName} didn't return a valid ` +
'screen or navigator.\n\n' +
'Please pass it like this:\n' +
`${routeName}: {\n getScreen: () => require('./MyScreen').default\n}`,
`${routeName}: {\n getScreen: () => require('./MyScreen').default\n}`
);
return screen;
}

View File

@@ -12,7 +12,7 @@ function validateRouteConfigMap(routeConfigs: NavigationRouteConfigMap) {
const routeNames = Object.keys(routeConfigs);
invariant(
routeNames.length > 0,
'Please specify at least one route when configuring a navigator.',
'Please specify at least one route when configuring a navigator.'
);
routeNames.forEach((routeName: string) => {
@@ -26,14 +26,14 @@ function validateRouteConfigMap(routeConfigs: NavigationRouteConfigMap) {
'...\n' +
`${routeName}: {\n` +
' screen: MyScreen,\n' +
'}',
'}'
);
if (routeConfig.screen && routeConfig.getScreen) {
invariant(
false,
`Route '${routeName}' should declare a screen or ` +
'a getScreen, not both.',
'a getScreen, not both.'
);
}
@@ -52,7 +52,7 @@ function validateRouteConfigMap(routeConfigs: NavigationRouteConfigMap) {
'...\n' +
`${routeName}: {\n` +
' screen: MyNavigator,\n' +
'}',
'}'
);
}
});

View File

@@ -28,7 +28,7 @@ export default (screenOptions: *, route: NavigationRoute) => {
'({ navigation }) => ({',
' title: navigation.state...',
'})',
].join('\n'),
].join('\n')
);
}
@@ -48,7 +48,7 @@ export default (screenOptions: *, route: NavigationRoute) => {
'({ navigation }) => ({',
` ${deprecatedKey}Key: navigation.state...`,
'})',
].join('\n'),
].join('\n')
);
}
@@ -62,7 +62,7 @@ export default (screenOptions: *, route: NavigationRoute) => {
'{',
` ${deprecatedKey}: {`,
...Object.keys(screenOptions[deprecatedKey]).map(
(key: string) => ` ${key}: ...,`,
(key: string) => ` ${key}: ...,`
),
' },',
'}',
@@ -71,10 +71,10 @@ export default (screenOptions: *, route: NavigationRoute) => {
'{',
...Object.keys(screenOptions[deprecatedKey]).map(
(key: string) =>
` ${deprecatedKey + key[0].toUpperCase() + key.slice(1)}: ...,`,
` ${deprecatedKey + key[0].toUpperCase() + key.slice(1)}: ...,`
),
'}',
].join('\n'),
].join('\n')
);
}
};

View File

@@ -22,11 +22,7 @@ class Card extends React.Component<any, Props, any> {
props: Props;
render() {
const {
children,
pointerEvents,
style,
} = this.props;
const { children, pointerEvents, style } = this.props;
return (
<Animated.View
pointerEvents={pointerEvents}

View File

@@ -43,7 +43,11 @@ type Props = {
headerComponent?: ReactClass<*>,
mode: 'card' | 'modal',
navigation: NavigationScreenProp<NavigationState, NavigationAction>,
router: NavigationRouter<NavigationState, NavigationAction, NavigationStackScreenOptions>,
router: NavigationRouter<
NavigationState,
NavigationAction,
NavigationStackScreenOptions
>,
cardStyle?: Style,
onTransitionStart?: () => void,
onTransitionEnd?: () => void,
@@ -158,7 +162,7 @@ class CardStack extends Component {
_renderHeader(
scene: NavigationScene,
headerMode: HeaderMode,
headerMode: HeaderMode
): ?React.Element<*> {
const { header } = this._getScreenDetails(scene).options;
@@ -221,7 +225,7 @@ class CardStack extends Component {
const backFromScene = scenes.find((s: *) => s.index === toValue + 1);
if (!this._isResponding && backFromScene) {
navigation.dispatch(
NavigationActions.back({ key: backFromScene.route.key }),
NavigationActions.back({ key: backFromScene.route.key })
);
}
});
@@ -250,7 +254,7 @@ class CardStack extends Component {
},
onMoveShouldSetPanResponder: (
event: { nativeEvent: { pageY: number, pageX: number } },
gesture: any,
gesture: any
) => {
if (index !== scene.index) {
return false;
@@ -259,9 +263,8 @@ class CardStack extends Component {
? index
: this._immediateIndex;
const currentDragDistance = gesture[isVertical ? 'dy' : 'dx'];
const currentDragPosition = event.nativeEvent[
isVertical ? 'pageY' : 'pageX'
];
const currentDragPosition =
event.nativeEvent[isVertical ? 'pageY' : 'pageX'];
const axisLength = isVertical
? layout.height.__getValue()
: layout.width.__getValue();
@@ -279,13 +282,12 @@ class CardStack extends Component {
return false;
}
const hasDraggedEnough = Math.abs(currentDragDistance) >
RESPOND_THRESHOLD;
const hasDraggedEnough =
Math.abs(currentDragDistance) > RESPOND_THRESHOLD;
const isOnFirstCard = immediateIndex === 0;
const shouldSetResponder = hasDraggedEnough &&
axisHasBeenMeasured &&
!isOnFirstCard;
const shouldSetResponder =
hasDraggedEnough && axisHasBeenMeasured && !isOnFirstCard;
return shouldSetResponder;
},
onPanResponderMove: (event: any, gesture: any) => {
@@ -379,7 +381,7 @@ class CardStack extends Component {
_renderInnerScene(
SceneComponent: ReactClass<*>,
scene: NavigationScene,
scene: NavigationScene
): React.Element<any> {
const { navigation } = this._getScreenDetails(scene);
const { screenProps } = this.props;
@@ -415,13 +417,13 @@ class CardStack extends Component {
this.props.transitionConfig,
{},
{},
isModal,
isModal
);
const style = screenInterpolator &&
screenInterpolator({ ...this.props, scene });
const style =
screenInterpolator && screenInterpolator({ ...this.props, scene });
const SceneComponent = this.props.router.getComponentForRouteName(
scene.route.routeName,
scene.route.routeName
);
return (

View File

@@ -23,10 +23,7 @@ import type { NavigationSceneRendererProps } from '../TypeDefinition';
* Render the initial style when the initial layout isn't measured yet.
*/
function forInitial(props: NavigationSceneRendererProps): Object {
const {
navigation,
scene,
} = props;
const { navigation, scene } = props;
const focused = navigation.state.index === scene.index;
const opacity = focused ? 1 : 0;
@@ -42,11 +39,7 @@ function forInitial(props: NavigationSceneRendererProps): Object {
* Standard iOS-style slide in from the right.
*/
function forHorizontal(props: NavigationSceneRendererProps): Object {
const {
layout,
position,
scene,
} = props;
const { layout, position, scene } = props;
if (!layout.isMeasured) {
return forInitial(props);
@@ -89,11 +82,7 @@ function forHorizontal(props: NavigationSceneRendererProps): Object {
* Standard iOS-style slide in from the bottom (used for modals).
*/
function forVertical(props: NavigationSceneRendererProps): Object {
const {
layout,
position,
scene,
} = props;
const { layout, position, scene } = props;
if (!layout.isMeasured) {
return forInitial(props);
@@ -129,11 +118,7 @@ function forVertical(props: NavigationSceneRendererProps): Object {
* Standard Android-style fade in from the bottom.
*/
function forFadeFromBottomAndroid(props: NavigationSceneRendererProps): Object {
const {
layout,
position,
scene,
} = props;
const { layout, position, scene } = props;
if (!layout.isMeasured) {
return forInitial(props);

View File

@@ -21,15 +21,19 @@ import type {
TransitionConfig,
} from '../TypeDefinition';
const NativeAnimatedModule = NativeModules &&
NativeModules.NativeAnimatedModule;
const NativeAnimatedModule =
NativeModules && NativeModules.NativeAnimatedModule;
type Props = {
screenProps?: {},
headerMode: HeaderMode,
mode: 'card' | 'modal',
navigation: NavigationScreenProp<NavigationState, NavigationAction>,
router: NavigationRouter<NavigationState, NavigationAction, NavigationStackScreenOptions>,
router: NavigationRouter<
NavigationState,
NavigationAction,
NavigationStackScreenOptions
>,
cardStyle?: Style,
onTransitionStart?: () => void,
onTransitionEnd?: () => void,
@@ -68,7 +72,7 @@ class CardStackTransitioner extends Component<DefaultProps, Props, void> {
// props for the new screen
transitionProps: NavigationTransitionProps,
// props for the old screen
prevTransitionProps: NavigationTransitionProps,
prevTransitionProps: NavigationTransitionProps
) => {
const isModal = this.props.mode === 'modal';
// Copy the object so we can assign useNativeDriver below
@@ -78,7 +82,7 @@ class CardStackTransitioner extends Component<DefaultProps, Props, void> {
this.props.transitionConfig,
transitionProps,
prevTransitionProps,
isModal,
isModal
).transitionSpec,
};
if (

View File

@@ -28,19 +28,17 @@ type Props = {
/**
* Component that renders the navigation list in the drawer.
*/
const DrawerNavigatorItems = (
{
navigation,
activeTintColor,
activeBackgroundColor,
inactiveTintColor,
inactiveBackgroundColor,
getLabel,
renderIcon,
style,
labelStyle,
}: Props,
) => (
const DrawerNavigatorItems = ({
navigation,
activeTintColor,
activeBackgroundColor,
inactiveTintColor,
inactiveBackgroundColor,
getLabel,
renderIcon,
style,
labelStyle,
}: Props) => (
<View style={[styles.container, style]}>
{navigation.state.routes.map((route: *, index: number) => {
const focused = navigation.state.index === index;

View File

@@ -16,7 +16,11 @@ import type {
type Props = {
screenProps?: {},
router: NavigationRouter<NavigationState, NavigationAction, NavigationDrawerScreenOptions>,
router: NavigationRouter<
NavigationState,
NavigationAction,
NavigationDrawerScreenOptions
>,
navigation: NavigationScreenProp<NavigationState, NavigationAction>,
childNavigationProps: {
[key: string]: NavigationScreenProp<NavigationRoute, NavigationAction>,

View File

@@ -20,7 +20,11 @@ import type { DrawerScene } from './DrawerView';
type Navigation = NavigationScreenProp<NavigationRoute, NavigationAction>;
type Props = {
router: NavigationRouter<NavigationState, NavigationAction, NavigationDrawerScreenOptions>,
router: NavigationRouter<
NavigationState,
NavigationAction,
NavigationDrawerScreenOptions
>,
navigation: Navigation,
childNavigationProps: { [key: string]: Navigation },
contentComponent: ReactClass<*>,
@@ -37,11 +41,11 @@ class DrawerSidebar extends PureComponent<void, Props, void> {
_getScreenOptions = (routeKey: string) => {
const DrawerScreen = this.props.router.getComponentForRouteName(
'DrawerClose',
'DrawerClose'
);
return DrawerScreen.router.getScreenOptions(
this.props.childNavigationProps[routeKey],
this.props.screenProps,
this.props.screenProps
);
};

View File

@@ -33,7 +33,11 @@ export type DrawerViewConfig = {
type Props = DrawerViewConfig & {
screenProps?: {},
router: NavigationRouter<NavigationState, NavigationAction, NavigationDrawerScreenOptions>,
router: NavigationRouter<
NavigationState,
NavigationAction,
NavigationDrawerScreenOptions
>,
navigation: NavigationScreenProp<NavigationState, NavigationAction>,
};
@@ -80,10 +84,10 @@ export default class DrawerView<T: *> extends PureComponent<void, Props, void> {
};
_updateScreenNavigation = (
navigation: NavigationScreenProp<NavigationState, NavigationAction>,
navigation: NavigationScreenProp<NavigationState, NavigationAction>
) => {
const navigationState = navigation.state.routes.find(
(route: *) => route.routeName === 'DrawerClose',
(route: *) => route.routeName === 'DrawerClose'
);
if (
this._screenNavigationProp &&
@@ -98,10 +102,10 @@ export default class DrawerView<T: *> extends PureComponent<void, Props, void> {
};
_getNavigationState = (
navigation: NavigationScreenProp<NavigationState, NavigationAction>,
navigation: NavigationScreenProp<NavigationState, NavigationAction>
) => {
const navigationState = navigation.state.routes.find(
(route: *) => route.routeName === 'DrawerClose',
(route: *) => route.routeName === 'DrawerClose'
);
return navigationState;
};
@@ -121,7 +125,7 @@ export default class DrawerView<T: *> extends PureComponent<void, Props, void> {
render() {
const DrawerScreen = this.props.router.getComponentForRouteName(
'DrawerClose',
'DrawerClose'
);
return (
<DrawerLayout

View File

@@ -73,9 +73,8 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
if (!lastScene) {
return null;
}
return this.props.getScreenDetails(
lastScene,
).options.headerTruncatedBackTitle;
return this.props.getScreenDetails(lastScene).options
.headerTruncatedBackTitle;
}
_renderTitleComponent = (props: SceneProps) => {
@@ -122,7 +121,7 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
}
const backButtonTitle = this._getBackButtonTitleString(props.scene);
const truncatedBackButtonTitle = this._getTruncatedBackButtonTitle(
props.scene,
props.scene
);
const width = this.state.widths[props.scene.key]
? (this.props.layout.initWidth - this.state.widths[props.scene.key]) / 2
@@ -153,7 +152,7 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
props,
'left',
this._renderLeftComponent,
HeaderStyleInterpolator.forLeft,
HeaderStyleInterpolator.forLeft
);
}
@@ -173,7 +172,7 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
{ ...props, style },
'title',
this._renderTitleComponent,
HeaderStyleInterpolator.forCenter,
HeaderStyleInterpolator.forCenter
);
}
@@ -182,7 +181,7 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
props,
'right',
this._renderRightComponent,
HeaderStyleInterpolator.forRight,
HeaderStyleInterpolator.forRight
);
}
@@ -190,16 +189,10 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
props: SceneProps,
name: SubViewName,
renderer: SubViewRenderer,
styleInterpolator: NavigationStyleInterpolator,
styleInterpolator: NavigationStyleInterpolator
): ?React.Element<*> {
const {
scene,
} = props;
const {
index,
isStale,
key,
} = scene;
const { scene } = props;
const { index, isStale, key } = scene;
const offset = this.props.navigation.state.index - index;
@@ -261,13 +254,13 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
let appBar;
if (this.props.mode === 'float') {
const scenesProps: Array<SceneProps> = this.props.scenes.map(
(scene: NavigationScene) => ({
position: this.props.position,
progress: this.props.progress,
scene,
}),
);
const scenesProps: Array<
SceneProps
> = this.props.scenes.map((scene: NavigationScene) => ({
position: this.props.position,
progress: this.props.progress,
scene,
}));
appBar = scenesProps.map(this._renderHeader, this);
} else {
appBar = this._renderHeader({

View File

@@ -65,7 +65,7 @@ export default function create(Component: ReactClass<*>): ReactClass<*> {
if (component) {
invariant(
typeof component.setNativeProps === 'function',
'component must implement method `setNativeProps`',
'component must implement method `setNativeProps`'
);
}
}
@@ -74,7 +74,7 @@ export default function create(Component: ReactClass<*>): ReactClass<*> {
this._positionListener && this._positionListener.remove();
this._positionListener = new AnimatedValueSubscription(
props.position,
this._onPositionChange,
this._onPositionChange
);
}
@@ -89,11 +89,7 @@ export default function create(Component: ReactClass<*>): ReactClass<*> {
}
_computePointerEvents(): string {
const {
navigation,
position,
scene,
} = this.props;
const { navigation, position, scene } = this.props;
if (scene.isStale || navigation.state.index !== scene.index) {
// The scene isn't focused.

View File

@@ -30,11 +30,7 @@ export default class SceneView extends PureComponent<void, Props, void> {
}
render() {
const {
screenProps,
navigation,
component: Component,
} = this.props;
const { screenProps, navigation, component: Component } = this.props;
return <Component screenProps={screenProps} navigation={navigation} />;
}

View File

@@ -44,13 +44,15 @@ function compareScenes(one: NavigationScene, two: NavigationScene): number {
*/
function areScenesShallowEqual(
one: NavigationScene,
two: NavigationScene,
two: NavigationScene
): boolean {
return one.key === two.key &&
return (
one.key === two.key &&
one.index === two.index &&
one.isStale === two.isStale &&
one.isActive === two.isActive &&
areRoutesShallowEqual(one.route, two.route);
areRoutesShallowEqual(one.route, two.route)
);
}
/**
@@ -58,7 +60,7 @@ function areScenesShallowEqual(
*/
function areRoutesShallowEqual(
one: ?NavigationRoute,
two: ?NavigationRoute,
two: ?NavigationRoute
): boolean {
if (!one || !two) {
return one === two;
@@ -74,7 +76,7 @@ function areRoutesShallowEqual(
export default function ScenesReducer(
scenes: Array<NavigationScene>,
nextState: NavigationState,
prevState: ?NavigationState,
prevState: ?NavigationState
): Array<NavigationScene> {
if (prevState === nextState) {
return scenes;
@@ -106,7 +108,7 @@ export default function ScenesReducer(
invariant(
!nextKeys.has(key),
`navigation.state.routes[${index}].key "${key}" conflicts with ` +
'another route!',
'another route!'
);
nextKeys.add(key);
@@ -171,7 +173,7 @@ export default function ScenesReducer(
invariant(
activeScenesCount === 1,
'there should always be only one scene active, not %s.',
activeScenesCount,
activeScenesCount
);
if (nextScenes.length !== scenes.length) {
@@ -180,7 +182,7 @@ export default function ScenesReducer(
if (
nextScenes.some(
(scene: *, index: *) => !areScenesShallowEqual(scenes[index], scene),
(scene: *, index: *) => !areScenesShallowEqual(scenes[index], scene)
)
) {
return nextScenes;

View File

@@ -70,7 +70,7 @@ export default class TabBarBottom
const inputRange = [-1, ...routes.map((x: *, i: number) => i)];
const outputRange = inputRange.map(
(inputIndex: number) =>
inputIndex === index ? activeTintColor : inactiveTintColor,
inputIndex === index ? activeTintColor : inactiveTintColor
);
const color = position.interpolate({
inputRange,
@@ -140,7 +140,7 @@ export default class TabBarBottom
(inputIndex: number) =>
inputIndex === index
? activeBackgroundColor
: inactiveBackgroundColor,
: inactiveBackgroundColor
);
const backgroundColor = position.interpolate({
inputRange,

View File

@@ -40,11 +40,11 @@ export default class TabBarIcon extends PureComponent<void, Props, void> {
const inputRange = [-1, ...routes.map((x: *, i: number) => i)];
const activeOpacity = position.interpolate({
inputRange,
outputRange: inputRange.map((i: number) => i === index ? 1 : 0),
outputRange: inputRange.map((i: number) => (i === index ? 1 : 0)),
});
const inactiveOpacity = position.interpolate({
inputRange,
outputRange: inputRange.map((i: number) => i === index ? 0 : 1),
outputRange: inputRange.map((i: number) => (i === index ? 0 : 1)),
});
// We render the icon twice at the same position on top of each other:
// active and inactive one, so we can fade between them.

View File

@@ -67,7 +67,7 @@ export default class TabBarTop
const inputRange = [-1, ...routes.map((x: *, i: number) => i)];
const outputRange = inputRange.map(
(inputIndex: number) =>
inputIndex === index ? activeTintColor : inactiveTintColor,
inputIndex === index ? activeTintColor : inactiveTintColor
);
const color = position.interpolate({
inputRange,

View File

@@ -41,7 +41,11 @@ type Props = {
screenProps?: {},
navigation: NavigationScreenProp<NavigationState, NavigationAction>,
router: NavigationRouter<NavigationState, NavigationAction, NavigationTabScreenOptions>,
router: NavigationRouter<
NavigationState,
NavigationAction,
NavigationTabScreenOptions
>,
childNavigationProps: {
[key: string]: NavigationScreenProp<NavigationRoute, NavigationAction>,
},
@@ -59,7 +63,7 @@ class TabView extends PureComponent<void, Props, void> {
const { screenProps } = this.props;
const childNavigation = this.props.childNavigationProps[route.key];
const TabComponent = this.props.router.getComponentForRouteName(
route.routeName,
route.routeName
);
return (
<View style={styles.page}>
@@ -75,7 +79,7 @@ class TabView extends PureComponent<void, Props, void> {
_getLabel = ({ route, tintColor, focused }: TabScene) => {
const options = this.props.router.getScreenOptions(
this.props.childNavigationProps[route.key],
this.props.screenProps || {},
this.props.screenProps || {}
);
if (options.tabBarLabel) {
@@ -94,7 +98,7 @@ class TabView extends PureComponent<void, Props, void> {
_renderIcon = ({ focused, route, tintColor }: TabScene) => {
const options = this.props.router.getScreenOptions(
this.props.childNavigationProps[route.key],
this.props.screenProps || {},
this.props.screenProps || {}
);
if (options.tabBarIcon) {
return typeof options.tabBarIcon === 'function'
@@ -145,7 +149,7 @@ class TabView extends PureComponent<void, Props, void> {
const { state } = this.props.navigation;
const options = router.getScreenOptions(
this.props.childNavigationProps[state.routes[state.index].key],
screenProps || {},
screenProps || {}
);
const tabBarVisible = options.tabBarVisible == null

View File

@@ -50,7 +50,8 @@ export default class TouchableItem
* We need to pass the background prop to specify a borderless ripple effect.
*/
if (
Platform.OS === 'android' && Platform.Version >= ANDROID_VERSION_LOLLIPOP
Platform.OS === 'android' &&
Platform.Version >= ANDROID_VERSION_LOLLIPOP
) {
const { style, ...rest } = this.props; // eslint-disable-line no-unused-vars
@@ -60,7 +61,7 @@ export default class TouchableItem
style={null}
background={TouchableNativeFeedback.Ripple(
this.props.pressColor,
this.props.borderless,
this.props.borderless
)}
>
<View style={this.props.style}>

View File

@@ -55,13 +55,14 @@ function defaultTransitionConfig(
// props for the old screen
prevTransitionProps: NavigationTransitionProps,
// whether we're animating in/out a modal screen
isModal: boolean,
isModal: boolean
): TransitionConfig {
if (Platform.OS === 'android') {
// Use the default Android animation no matter if the screen is a modal.
// Android doesn't have full-screen modals like iOS does, it has dialogs.
if (
prevTransitionProps && transitionProps.index < prevTransitionProps.index
prevTransitionProps &&
transitionProps.index < prevTransitionProps.index
) {
// Navigating back to the previous screen
return FadeOutToBottomAndroid;
@@ -81,12 +82,12 @@ function getTransitionConfig(
transitionProps: NavigationTransitionProps,
// props for the old screen
prevTransitionProps: NavigationTransitionProps,
isModal: boolean,
isModal: boolean
): TransitionConfig {
const defaultConfig = defaultTransitionConfig(
transitionProps,
prevTransitionProps,
isModal,
isModal
);
if (transitionConfigurer) {
return {

View File

@@ -22,14 +22,14 @@ import type {
type Props = {
configureTransition: (
transitionProps: NavigationTransitionProps,
prevTransitionProps: ?NavigationTransitionProps,
prevTransitionProps: ?NavigationTransitionProps
) => NavigationTransitionSpec,
navigation: NavigationScreenProp<NavigationState, NavigationAction>,
onTransitionEnd?: () => void,
onTransitionStart?: () => void,
render: (
transitionProps: NavigationTransitionProps,
prevTransitionProps: ?NavigationTransitionProps,
prevTransitionProps: ?NavigationTransitionProps
) => any,
style?: any,
};
@@ -103,15 +103,15 @@ class Transitioner extends React.Component<*, Props, State> {
const nextScenes = NavigationScenesReducer(
this.state.scenes,
nextProps.navigation.state,
this.props.navigation.state,
this.props.navigation.state
);
if (nextScenes === this.state.scenes) {
return;
}
const indexHasChanged = nextProps.navigation.state.index !==
this.props.navigation.state.index;
const indexHasChanged =
nextProps.navigation.state.index !== this.props.navigation.state.index;
if (this._isTransitionRunning) {
this._queuedTransition = { nextProps, nextScenes, indexHasChanged };
return;
@@ -123,17 +123,14 @@ class Transitioner extends React.Component<*, Props, State> {
_startTransition(
nextProps: Props,
nextScenes: Array<NavigationScene>,
indexHasChanged: boolean,
indexHasChanged: boolean
) {
const nextState = {
...this.state,
scenes: nextScenes,
};
const {
position,
progress,
} = nextState;
const { position, progress } = nextState;
progress.setValue(0);
@@ -144,7 +141,7 @@ class Transitioner extends React.Component<*, Props, State> {
const transitionUserSpec = nextProps.configureTransition
? nextProps.configureTransition(
this._transitionProps,
this._prevTransitionProps,
this._prevTransitionProps
)
: null;
@@ -179,7 +176,7 @@ class Transitioner extends React.Component<*, Props, State> {
nextProps.onTransitionStart &&
nextProps.onTransitionStart(
this._transitionProps,
this._prevTransitionProps,
this._prevTransitionProps
);
Animated.parallel(animations).start(this._onTransitionEnd);
});
@@ -241,7 +238,7 @@ class Transitioner extends React.Component<*, Props, State> {
this._startTransition(
this._queuedTransition.nextProps,
this._queuedTransition.nextScenes,
this._queuedTransition.indexHasChanged,
this._queuedTransition.indexHasChanged
);
this._queuedTransition = null;
} else {
@@ -253,18 +250,11 @@ class Transitioner extends React.Component<*, Props, State> {
function buildTransitionProps(
props: Props,
state: State,
state: State
): NavigationTransitionProps {
const {
navigation,
} = props;
const { navigation } = props;
const {
layout,
position,
progress,
scenes,
} = state;
const { layout, position, progress, scenes } = state;
const scene = scenes.find(isSceneActive);

View File

@@ -15,7 +15,7 @@ type InjectedProps = {
};
export default function withNavigation<T: *>(
Component: ReactClass<T & InjectedProps>,
Component: ReactClass<T & InjectedProps>
) {
const componentWithNavigation = (props: T, { navigation }: Context) => (
<Component {...props} navigation={navigation} />

View File

@@ -16,7 +16,7 @@ type InjectedProps<N> = {
* HOC which caches the child navigation items.
*/
export default function withCachedChildNavigation<T: *, N: *>(
Comp: ReactClass<T & InjectedProps<N>>,
Comp: ReactClass<T & InjectedProps<N>>
): ReactClass<T> {
return class extends PureComponent {
static displayName = `withCachedChildNavigation(${Comp.displayName || Comp.name})`;
@@ -36,7 +36,7 @@ export default function withCachedChildNavigation<T: *, N: *>(
};
_updateNavigationProps = (
navigation: NavigationScreenProp<N, NavigationAction>,
navigation: NavigationScreenProp<N, NavigationAction>
) => {
// Update props for each child route
if (!this._childNavigationProps) {

View File

@@ -4,25 +4,25 @@
var REACT_APP = /^REACT_APP_/i;
function getClientEnvironment(publicUrl) {
var processEnv = Object
.keys(process.env)
var processEnv = Object.keys(process.env)
.filter(key => REACT_APP.test(key))
.reduce((env, key) => {
env[key] = JSON.stringify(process.env[key]);
return env;
}, {
// Useful for determining whether were running in production mode.
// Most importantly, it switches React into the correct mode.
'NODE_ENV': JSON.stringify(
process.env.NODE_ENV || 'development'
),
// Useful for resolving the correct path to static assets in `public`.
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
// This should only be used as an escape hatch. Normally you would put
// images into the `src` and `import` them in code to get their paths.
'PUBLIC_URL': JSON.stringify(publicUrl)
});
return {'process.env': processEnv};
.reduce(
(env, key) => {
env[key] = JSON.stringify(process.env[key]);
return env;
},
{
// Useful for determining whether were running in production mode.
// Most importantly, it switches React into the correct mode.
NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
// Useful for resolving the correct path to static assets in `public`.
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
// This should only be used as an escape hatch. Normally you would put
// images into the `src` and `import` them in code to get their paths.
PUBLIC_URL: JSON.stringify(publicUrl),
}
);
return { 'process.env': processEnv };
}
module.exports = getClientEnvironment;

View File

@@ -1 +1 @@
module.exports = "test-file-stub";
module.exports = 'test-file-stub';

View File

@@ -39,13 +39,13 @@ module.exports = {
testsSetup: resolveApp('src/setupTests.js'),
appNodeModules: resolveApp('node_modules'),
ownNodeModules: resolveApp('node_modules'),
nodePaths: nodePaths
nodePaths: nodePaths,
};
// config before publish: we're in ./packages/react-scripts/config/
if (__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1) {
if (
__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1
) {
module.exports = {
appRoot: resolveOwn(''),
appBuild: resolveOwn('../../../build'),
@@ -59,6 +59,6 @@ if (__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1)
testsSetup: resolveOwn('../template/src/setupTests.js'),
appNodeModules: resolveOwn('../node_modules'),
ownNodeModules: resolveOwn('../node_modules'),
nodePaths: nodePaths
nodePaths: nodePaths,
};
}

View File

@@ -19,7 +19,9 @@ const publicUrl = '';
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
console.log(paths.nodePaths.concat([path.resolve(__dirname, '../node_modules')]));
console.log(
paths.nodePaths.concat([path.resolve(__dirname, '../node_modules')])
);
// This is the development configuration.
// It is focused on developer experience and fast rebuilds.
@@ -71,7 +73,9 @@ module.exports = {
// We use `fallback` instead of `root` because we want `node_modules` to "win"
// if there any conflicts. This matches Node resolution mechanism.
// https://github.com/facebookincubator/create-react-app/issues/253
fallback: paths.nodePaths.concat([path.resolve(__dirname, '../node_modules')]),
fallback: paths.nodePaths.concat([
path.resolve(__dirname, '../node_modules'),
]),
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
@@ -103,7 +107,6 @@ module.exports = {
include: paths.appSrc,
loader: 'babel',
query: {
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/react-scripts/
// directory for faster rebuilds. We use findCacheDir() because of:

View File

@@ -53,10 +53,7 @@ module.exports = {
// You can exclude the *.map files from the build during deployment.
devtool: 'source-map',
// In production, we only want to load the polyfills and the app code.
entry: [
require.resolve('./polyfills'),
paths.appIndexJs,
],
entry: [require.resolve('./polyfills'), paths.appIndexJs],
output: {
// The build folder.
path: paths.appBuildPublic,
@@ -74,7 +71,9 @@ module.exports = {
// We use `fallback` instead of `root` because we want `node_modules` to "win"
// if there any conflicts. This matches Node resolution mechanism.
// https://github.com/facebookincubator/create-react-app/issues/253
fallback: paths.nodePaths.concat([path.resolve(__dirname, '../node_modules')]),
fallback: paths.nodePaths.concat([
path.resolve(__dirname, '../node_modules'),
]),
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
@@ -105,7 +104,6 @@ module.exports = {
test: /\.(js|jsx)$/,
include: paths.appSrc,
loader: 'babel',
},
// The notation here is somewhat confusing.
// "postcss" loader applies autoprefixer to our CSS.
@@ -129,7 +127,10 @@ module.exports = {
// Webpack 1.x uses Uglify plugin as a signal to minify *all* the assets
// including CSS. This is confusing and will be removed in Webpack 2:
// https://github.com/webpack/webpack/issues/283
loader: ExtractTextPlugin.extract('style', 'css?importLoaders=1&-autoprefixer!postcss'),
loader: ExtractTextPlugin.extract(
'style',
'css?importLoaders=1&-autoprefixer!postcss'
),
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
// JSON is not enabled by default in Webpack but both Node and Browserify

View File

@@ -6,7 +6,6 @@
"autoprefixer": "6.5.1",
"babel-cli": "^6.18.0",
"babel-core": "6.17.0",
"babel-eslint": "7.0.0",
"babel-jest": "16.0.0",
"babel-loader": "6.2.5",
"babel-plugin-flow-react-proptypes": "grabbou/babel-plugin-flow-react-proptypes#release",
@@ -18,13 +17,6 @@
"css-loader": "0.25.0",
"detect-port": "1.0.1",
"dotenv": "2.0.0",
"eslint": "3.8.1",
"eslint-config-react-app": "^0.3.0",
"eslint-loader": "1.6.0",
"eslint-plugin-flowtype": "2.21.0",
"eslint-plugin-import": "2.0.1",
"eslint-plugin-jsx-a11y": "2.2.3",
"eslint-plugin-react": "6.4.1",
"extract-text-webpack-plugin": "1.0.1",
"file-loader": "0.9.0",
"filesize": "3.3.0",
@@ -54,6 +46,7 @@
"dependencies": {
"@blueprintjs/core": "^1.0.1",
"prismjs": "^1.6.0",
"prop-types": "^15.5.10",
"react": "~15.3.2",
"react-addons-css-transition-group": "~15.3.2",
"react-dom": "~15.3.2",
@@ -102,8 +95,5 @@
"presets": [
"react-app"
]
},
"eslintConfig": {
"extends": "react-app"
}
}

View File

@@ -83,46 +83,65 @@ recursive(paths.appBuild, (err, fileNames) => {
const navLibPackageJson = require(libPkgPath);
exec('babel', ['src', '--out-dir', paths.appBuildLib], {
cwd: paths.appRoot,
});
exec('babel', [ 'src', '--out-dir', paths.appBuildLib], {cwd: paths.appRoot});
fs.readdirSync(paths.appBuildLib).forEach((module) => {
fs.readdirSync(paths.appBuildLib).forEach(module => {
const modulePath = path.join(paths.appBuildLib, module);
let moduleData = fs.readFileSync(modulePath, {encoding: 'utf8'});
let moduleData = fs.readFileSync(modulePath, { encoding: 'utf8' });
// This is a dangerous shameful hack but it allows the website source to use a standard-looking import:
moduleData = moduleData.split("require('react-navigation'").join("require('../react-navigation/react-navigation.web'");
moduleData = moduleData
.split("require('react-navigation'")
.join("require('../react-navigation/react-navigation.web'");
fs.writeFileSync(modulePath, moduleData);
});
const libPath = path.join(paths.appBuild, 'react-navigation');
fs.mkdirSync(libPath);
fs.copySync(
path.join(paths.libRoot, 'lib'),
libPath
);
fs.copySync(path.join(paths.libRoot, 'lib'), libPath);
// fs.writeFileSync(path.join(libPath, 'package.json'), JSON.stringify(Object.assign({}, navLibPackageJson, {
// main: 'lib/react-navigation',
// }), null, 2));
fs.writeFileSync(path.join(paths.appBuild, 'package.json'), JSON.stringify(Object.assign({
version: '1.0.0',
name: 'web-build',
}, appPackageJson.server, {
dependencies: Object.assign({}, appPackageJson.dependencies, navLibPackageJson.dependencies, appPackageJson.server.dependencies, {
'react-navigation': '',
}),
}), null, 2));
fs.writeFileSync(
path.join(paths.appBuild, 'package.json'),
JSON.stringify(
Object.assign(
{
version: '1.0.0',
name: 'web-build',
},
appPackageJson.server,
{
dependencies: Object.assign(
{},
appPackageJson.dependencies,
navLibPackageJson.dependencies,
appPackageJson.server.dependencies,
{
'react-navigation': '',
}
),
}
),
null,
2
)
);
});
// Print a detailed summary of build files.
function printFileSizes(stats, previousSizeMap) {
const assets = stats.toJson().assets
.filter(asset => /\.(js|css)$/.test(asset.name))
.map((asset) => {
const fileContents = fs.readFileSync(`${paths.appBuildPublic}/${asset.name}`);
const assets = stats
.toJson()
.assets.filter(asset => /\.(js|css)$/.test(asset.name))
.map(asset => {
const fileContents = fs.readFileSync(
`${paths.appBuildPublic}/${asset.name}`
);
const size = gzipSize(fileContents);
const previousSize = previousSizeMap[removeFileNameHash(asset.name)];
const difference = getDifferenceLabel(size, previousSize);
@@ -134,10 +153,11 @@ function printFileSizes(stats, previousSizeMap) {
};
});
assets.sort((a, b) => b.size - a.size);
const longestSizeLabelLength = Math.max.apply(null,
const longestSizeLabelLength = Math.max.apply(
null,
assets.map(a => stripAnsi(a.sizeLabel).length)
);
assets.forEach((asset) => {
assets.forEach(asset => {
let sizeLabel = asset.sizeLabel;
const sizeLength = stripAnsi(sizeLabel).length;
if (sizeLength < longestSizeLabelLength) {
@@ -145,8 +165,7 @@ function printFileSizes(stats, previousSizeMap) {
sizeLabel += rightPadding;
}
console.log(
` ${sizeLabel
} ${chalk.dim(asset.folder + path.sep)}${chalk.cyan(asset.name)}`
` ${sizeLabel} ${chalk.dim(asset.folder + path.sep)}${chalk.cyan(asset.name)}`
);
});
}
@@ -155,7 +174,7 @@ function printFileSizes(stats, previousSizeMap) {
function printErrors(summary, errors) {
console.log(chalk.red(summary));
console.log();
errors.forEach((err) => {
errors.forEach(err => {
console.log(err.message || err);
console.log(err.stack);
console.log();
@@ -191,20 +210,28 @@ function build(previousSizeMap) {
const publicPath = config.output.publicPath;
if (homepagePath && homepagePath.indexOf('.github.io/') !== -1) {
// "homepage": "http://user.github.io/project"
console.log(`The project was built assuming it is hosted at ${chalk.green(publicPath)}.`);
console.log(`You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`);
console.log(
`The project was built assuming it is hosted at ${chalk.green(publicPath)}.`
);
console.log(
`You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`
);
console.log();
console.log(`The ${chalk.cyan('build')} folder is ready to be deployed.`);
console.log(`To publish it at ${chalk.green(homepagePath)}, run:`);
console.log();
console.log(` ${chalk.cyan('npm')} install --save-dev gh-pages`);
console.log();
console.log(`Add the following script in your ${chalk.cyan('package.json')}.`);
console.log(
`Add the following script in your ${chalk.cyan('package.json')}.`
);
console.log();
console.log(` ${chalk.dim('// ...')}`);
console.log(` ${chalk.yellow('"scripts"')}: {`);
console.log(` ${chalk.dim('// ...')}`);
console.log(` ${chalk.yellow('"deploy"')}: ${chalk.yellow('"gh-pages -d build"')}`);
console.log(
` ${chalk.yellow('"deploy"')}: ${chalk.yellow('"gh-pages -d build"')}`
);
console.log(' }');
console.log();
console.log('Then run:');
@@ -213,24 +240,36 @@ function build(previousSizeMap) {
console.log();
} else if (publicPath !== '/') {
// "homepage": "http://mywebsite.com/project"
console.log(`The project was built assuming it is hosted at ${chalk.green(publicPath)}.`);
console.log(`You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`);
console.log(
`The project was built assuming it is hosted at ${chalk.green(publicPath)}.`
);
console.log(
`You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`
);
console.log();
console.log(`The ${chalk.cyan('build')} folder is ready to be deployed.`);
console.log();
} else {
// no homepage or "homepage": "http://mywebsite.com"
console.log('The project was built assuming it is hosted at the server root.');
console.log(
'The project was built assuming it is hosted at the server root.'
);
if (homepagePath) {
// "homepage": "http://mywebsite.com"
console.log(`You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`);
console.log(
`You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`
);
console.log();
} else {
// no homepage
console.log(`To override this, specify the ${chalk.green('homepage')} in your ${chalk.cyan('package.json')}.`);
console.log(
`To override this, specify the ${chalk.green('homepage')} in your ${chalk.cyan('package.json')}.`
);
console.log('For example, add this to build it for GitHub Pages:');
console.log();
console.log(` ${chalk.green('"homepage"')}${chalk.cyan(': ')}${chalk.green('"http://myname.github.io/myapp"')}${chalk.cyan(',')}`);
console.log(
` ${chalk.green('"homepage"')}${chalk.cyan(': ')}${chalk.green('"http://myname.github.io/myapp"')}${chalk.cyan(',')}`
);
console.log();
}
console.log(`The ${chalk.cyan('build')} folder is ready to be deployed.`);

View File

@@ -4,7 +4,7 @@ process.env.NODE_ENV = 'development';
// if this file is missing. dotenv will never modify any environment variables
// that have already been set.
// https://github.com/motdotla/dotenv
require('dotenv').config({silent: true});
require('dotenv').config({ silent: true });
var chalk = require('chalk');
var webpack = require('webpack');
@@ -34,7 +34,7 @@ var handleCompile;
// We only use this block for testing of Create React App itself:
var isSmokeTest = process.argv.some(arg => arg.indexOf('--smoke-test') > -1);
if (isSmokeTest) {
handleCompile = function (err, stats) {
handleCompile = function(err, stats) {
if (err || stats.hasErrors() || stats.hasWarnings()) {
process.exit(1);
} else {
@@ -71,10 +71,14 @@ function setupCompiler(host, port, protocol) {
console.log();
console.log('The app is running at:');
console.log();
console.log(' ' + chalk.cyan(protocol + '://' + host + ':' + port + '/'));
console.log(
' ' + chalk.cyan(protocol + '://' + host + ':' + port + '/')
);
console.log();
console.log('Note that the development build is not optimized.');
console.log('To create a production build, use ' + chalk.cyan('npm run build') + '.');
console.log(
'To create a production build, use ' + chalk.cyan('npm run build') + '.'
);
console.log();
}
@@ -99,8 +103,16 @@ function setupCompiler(host, port, protocol) {
});
// Teach some ESLint tricks.
console.log('You may use special comments to disable some warnings.');
console.log('Use ' + chalk.yellow('// eslint-disable-next-line') + ' to ignore the next line.');
console.log('Use ' + chalk.yellow('/* eslint-disable */') + ' to ignore all warnings in a file.');
console.log(
'Use ' +
chalk.yellow('// eslint-disable-next-line') +
' to ignore the next line.'
);
console.log(
'Use ' +
chalk.yellow('/* eslint-disable */') +
' to ignore all warnings in a file.'
);
}
});
}
@@ -108,53 +120,76 @@ function setupCompiler(host, port, protocol) {
// We need to provide a custom onError function for httpProxyMiddleware.
// It allows us to log custom error messages on the console.
function onProxyError(proxy) {
return function(err, req, res){
return function(err, req, res) {
var host = req.headers && req.headers.host;
console.log(
chalk.red('Proxy error:') + ' Could not proxy request ' + chalk.cyan(req.url) +
' from ' + chalk.cyan(host) + ' to ' + chalk.cyan(proxy) + '.'
chalk.red('Proxy error:') +
' Could not proxy request ' +
chalk.cyan(req.url) +
' from ' +
chalk.cyan(host) +
' to ' +
chalk.cyan(proxy) +
'.'
);
console.log(
'See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (' +
chalk.cyan(err.code) + ').'
chalk.cyan(err.code) +
').'
);
console.log();
// And immediately send the proper error response to the client.
// Otherwise, the request will eventually timeout with ERR_EMPTY_RESPONSE on the client side.
if (res.writeHead && !res.headersSent) {
res.writeHead(500);
res.writeHead(500);
}
res.end('Proxy error: Could not proxy request ' + req.url + ' from ' +
host + ' to ' + proxy + ' (' + err.code + ').'
res.end(
'Proxy error: Could not proxy request ' +
req.url +
' from ' +
host +
' to ' +
proxy +
' (' +
err.code +
').'
);
}
};
}
function addMiddleware(devServer) {
// `proxy` lets you to specify a fallback server during development.
// Every unrecognized request will be forwarded to it.
var proxy = require(paths.appPackageJson).proxy;
devServer.use(historyApiFallback({
// Paths with dots should still use the history fallback.
// See https://github.com/facebookincubator/create-react-app/issues/387.
disableDotRule: true,
// For single page apps, we generally want to fallback to /index.html.
// However we also want to respect `proxy` for API calls.
// So if `proxy` is specified, we need to decide which fallback to use.
// We use a heuristic: if request `accept`s text/html, we pick /index.html.
// Modern browsers include text/html into `accept` header when navigating.
// However API calls like `fetch()` wont generally accept text/html.
// If this heuristic doesnt work well for you, dont use `proxy`.
htmlAcceptHeaders: proxy ?
['text/html'] :
['text/html', '*/*']
}));
devServer.use(
historyApiFallback({
// Paths with dots should still use the history fallback.
// See https://github.com/facebookincubator/create-react-app/issues/387.
disableDotRule: true,
// For single page apps, we generally want to fallback to /index.html.
// However we also want to respect `proxy` for API calls.
// So if `proxy` is specified, we need to decide which fallback to use.
// We use a heuristic: if request `accept`s text/html, we pick /index.html.
// Modern browsers include text/html into `accept` header when navigating.
// However API calls like `fetch()` wont generally accept text/html.
// If this heuristic doesnt work well for you, dont use `proxy`.
htmlAcceptHeaders: proxy ? ['text/html'] : ['text/html', '*/*'],
})
);
if (proxy) {
if (typeof proxy !== 'string') {
console.log(chalk.red('When specified, "proxy" in package.json must be a string.'));
console.log(chalk.red('Instead, the type of "proxy" was "' + typeof proxy + '".'));
console.log(chalk.red('Either remove "proxy" from package.json, or make it a string.'));
console.log(
chalk.red('When specified, "proxy" in package.json must be a string.')
);
console.log(
chalk.red('Instead, the type of "proxy" was "' + typeof proxy + '".')
);
console.log(
chalk.red(
'Either remove "proxy" from package.json, or make it a string.'
)
);
process.exit(1);
}
@@ -165,7 +200,8 @@ function addMiddleware(devServer) {
// - /sockjs-node/* (WebpackDevServer uses this for hot reloading)
// Tip: use https://jex.im/regulex/ to visualize the regex
var mayProxy = /^(?!\/(index\.html$|.*\.hot-update\.json$|sockjs-node\/)).*$/;
devServer.use(mayProxy,
devServer.use(
mayProxy,
// Pass the scope regex both to Express and to the middleware for proxying
// of both HTTP and WebSockets to work without false positives.
httpProxyMiddleware(pathname => mayProxy.test(pathname), {
@@ -173,7 +209,7 @@ function addMiddleware(devServer) {
logLevel: 'silent',
onError: onProxyError(proxy),
secure: false,
changeOrigin: true
changeOrigin: true,
})
);
}
@@ -217,11 +253,11 @@ function runDevServer(host, port, protocol) {
// Reportedly, this avoids CPU overload on some systems.
// https://github.com/facebookincubator/create-react-app/issues/293
watchOptions: {
ignored: /node_modules/
ignored: /node_modules/,
},
// Enable HTTPS if the HTTPS environment variable is set to 'true'
https: protocol === "https",
host: host
https: protocol === 'https',
host: host,
});
// Our custom middleware proxies requests to /index.html or a remote API.
@@ -241,7 +277,7 @@ function runDevServer(host, port, protocol) {
}
function run(port) {
var protocol = process.env.HTTPS === 'true' ? "https" : "http";
var protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
var host = process.env.HOST || 'localhost';
setupCompiler(host, port, protocol);
runDevServer(host, port, protocol);

View File

@@ -5,7 +5,7 @@ process.env.PUBLIC_URL = '';
// if this file is missing. dotenv will never modify any environment variables
// that have already been set.
// https://github.com/motdotla/dotenv
require('dotenv').config({silent: true});
require('dotenv').config({ silent: true });
const jest = require('jest');
const argv = process.argv.slice(2);
@@ -15,5 +15,4 @@ if (!process.env.CI) {
argv.push('--watch');
}
jest.run(argv);

View File

@@ -15,9 +15,7 @@ import {
createNavigator,
} from 'react-navigation';
import type {
NavigationScreenComponent,
} from 'react-navigation';
import type { NavigationScreenComponent } from 'react-navigation';
type ScreenOptions = {
linkName: string,
@@ -25,8 +23,8 @@ type ScreenOptions = {
title: string,
};
const NavView = ({navigation, router}) => {
const {state} = navigation;
const NavView = ({ navigation, router }: { navigation: any, router: any }) => {
const { state } = navigation;
const Component = router.getComponentForState(state);
return (
<Component
@@ -45,260 +43,275 @@ type DocPageConfig = {
};
const createDocPage = (
config: DocPageConfig,
config: DocPageConfig
): (() => NavigationScreenComponent<*, ScreenOptions>) => {
const Page: NavigationScreenComponent<*, ScreenOptions> = ({ navigation }) => (
<MDPage
docPath={config.doc}
navigation={navigation}
/>
);
const Page: NavigationScreenComponent<*, ScreenOptions> = ({
navigation,
}: {
navigation: any,
}) => <MDPage docPath={config.doc} navigation={navigation} />;
Page.navigationOptions = {
doc: config.doc,
title: config.title,
linkName: config.linkName,
};
return Page;
}
};
const GuideDocs = createNavigator(TabRouter({
GettingStarted: {
screen: createDocPage({
doc: 'guides/Guide-Intro',
title: 'Hello Mobile Navigation',
linkName: 'Hello Mobile Navigation',
}),
path: '',
},
NestedNavigator: {
screen: createDocPage({
doc: 'guides/Guide-Nested',
title: 'Nesting Navigators',
linkName: 'Nesting Navigators',
}),
path: 'nesting',
},
ConfiguringHeaders: {
screen: createDocPage({
doc: 'guides/Guide-Headers',
title: 'Configuring Headers',
linkName: 'Configuring Headers',
}),
path: 'headers',
},
}))(NavView);
const GuideDocs = createNavigator(
TabRouter({
GettingStarted: {
screen: createDocPage({
doc: 'guides/Guide-Intro',
title: 'Hello Mobile Navigation',
linkName: 'Hello Mobile Navigation',
}),
path: '',
},
NestedNavigator: {
screen: createDocPage({
doc: 'guides/Guide-Nested',
title: 'Nesting Navigators',
linkName: 'Nesting Navigators',
}),
path: 'nesting',
},
ConfiguringHeaders: {
screen: createDocPage({
doc: 'guides/Guide-Headers',
title: 'Configuring Headers',
linkName: 'Configuring Headers',
}),
path: 'headers',
},
})
)(NavView);
GuideDocs.navigationOptions = {
linkName: 'Getting Started',
icon: 'pt-icon-flows',
};
const GuidesDocs = createNavigator(TabRouter({
ReduxIntegration: {
screen: createDocPage({
doc: 'guides/Redux-Integration',
title: 'Redux Integration Guide',
linkName: 'Redux Integration',
}),
path: 'redux',
},
WebIntegration: {
screen: createDocPage({
doc: 'guides/Web-Integration',
title: 'Web Integration Guide',
linkName: 'Web Integration',
}),
path: 'web',
},
DeepLinking: {
screen: createDocPage({
doc: 'guides/Deep-Linking',
title: 'Deep Linking Guide',
linkName: 'Deep Linking',
}),
path: 'linking',
},
ScreenTracking: {
screen: createDocPage({
doc: 'guides/Screen-Tracking',
title: 'Screen tracking and analytics',
linkName: 'Screen Tracking',
}),
path: 'screen-tracking',
},
Contributors: {
screen: createDocPage({
doc: 'guides/Contributors',
title: 'Contributors Guide',
linkName: 'Contributors',
}),
path: 'contributors',
},
}))(NavView);
const GuidesDocs = createNavigator(
TabRouter({
ReduxIntegration: {
screen: createDocPage({
doc: 'guides/Redux-Integration',
title: 'Redux Integration Guide',
linkName: 'Redux Integration',
}),
path: 'redux',
},
WebIntegration: {
screen: createDocPage({
doc: 'guides/Web-Integration',
title: 'Web Integration Guide',
linkName: 'Web Integration',
}),
path: 'web',
},
DeepLinking: {
screen: createDocPage({
doc: 'guides/Deep-Linking',
title: 'Deep Linking Guide',
linkName: 'Deep Linking',
}),
path: 'linking',
},
ScreenTracking: {
screen: createDocPage({
doc: 'guides/Screen-Tracking',
title: 'Screen tracking and analytics',
linkName: 'Screen Tracking',
}),
path: 'screen-tracking',
},
Contributors: {
screen: createDocPage({
doc: 'guides/Contributors',
title: 'Contributors Guide',
linkName: 'Contributors',
}),
path: 'contributors',
},
})
)(NavView);
GuidesDocs.navigationOptions = {
linkName: 'Advanced Guides',
icon: 'pt-icon-manual',
};
const NavigatorsDocs = createNavigator(TabRouter({
Navigators: {
screen: createDocPage({
doc: 'api/navigators/Navigators',
title: 'Intro to Navigators',
linkName: 'Intro to Navigators',
}),
path: '',
},
StackNavigator: {
screen: createDocPage({
doc: 'api/navigators/StackNavigator',
title: 'StackNavigator',
linkName: 'StackNavigator',
}),
path: 'stack',
},
TabNavigator: {
screen: createDocPage({
doc: 'api/navigators/TabNavigator',
title: 'TabNavigator',
linkName: 'TabNavigator',
}),
path: 'tab',
},
DrawerNavigator: {
screen: createDocPage({
doc: 'api/navigators/DrawerNavigator',
title: 'DrawerNavigator',
linkName: 'DrawerNavigator',
}),
path: 'drawer',
},
NavigationProp: {
screen: createDocPage({
doc: 'guides/Screen-Navigation-Prop',
title: 'The Navigation Prop',
linkName: 'The Navigation Prop',
}),
path: 'navigation-prop',
},
NavigationActions: {
screen: createDocPage({
doc: 'guides/Navigation-Actions',
title: 'Navigation Actions',
linkName: 'Navigation Actions',
}),
path: 'navigation-actions',
},
NavigationOptions: {
screen: createDocPage({
doc: 'guides/Screen-Nav-Options',
title: 'Screen Nav Options',
linkName: 'Screen Nav Options',
}),
path: 'navigation-options',
},
Custom: {
screen: createDocPage({
doc: 'guides/Custom-Navigators',
title: 'Custom Navigators',
linkName: 'Custom Navigators',
}),
path: 'custom',
},
}))(NavView);
const NavigatorsDocs = createNavigator(
TabRouter({
Navigators: {
screen: createDocPage({
doc: 'api/navigators/Navigators',
title: 'Intro to Navigators',
linkName: 'Intro to Navigators',
}),
path: '',
},
StackNavigator: {
screen: createDocPage({
doc: 'api/navigators/StackNavigator',
title: 'StackNavigator',
linkName: 'StackNavigator',
}),
path: 'stack',
},
TabNavigator: {
screen: createDocPage({
doc: 'api/navigators/TabNavigator',
title: 'TabNavigator',
linkName: 'TabNavigator',
}),
path: 'tab',
},
DrawerNavigator: {
screen: createDocPage({
doc: 'api/navigators/DrawerNavigator',
title: 'DrawerNavigator',
linkName: 'DrawerNavigator',
}),
path: 'drawer',
},
NavigationProp: {
screen: createDocPage({
doc: 'guides/Screen-Navigation-Prop',
title: 'The Navigation Prop',
linkName: 'The Navigation Prop',
}),
path: 'navigation-prop',
},
NavigationActions: {
screen: createDocPage({
doc: 'guides/Navigation-Actions',
title: 'Navigation Actions',
linkName: 'Navigation Actions',
}),
path: 'navigation-actions',
},
NavigationOptions: {
screen: createDocPage({
doc: 'guides/Screen-Nav-Options',
title: 'Screen Nav Options',
linkName: 'Screen Nav Options',
}),
path: 'navigation-options',
},
Custom: {
screen: createDocPage({
doc: 'guides/Custom-Navigators',
title: 'Custom Navigators',
linkName: 'Custom Navigators',
}),
path: 'custom',
},
})
)(NavView);
NavigatorsDocs.navigationOptions = {
linkName: 'Navigators',
icon: 'pt-icon-briefcase',
};
const RoutersDocs = createNavigator(TabRouter({
Routers: {
screen: createDocPage({
doc: 'api/routers/Routers',
title: 'Routers',
linkName: 'Routers',
}),
path: '',
},
RoutersAPI: {
screen: createDocPage({
doc: 'api/routers/RoutersAPI',
title: 'Router API',
linkName: 'Custom Router API',
}),
path: 'api',
},
StackRouter: {
screen: createDocPage({
doc: 'api/routers/StackRouter',
title: 'StackRouter',
linkName: 'StackRouter',
}),
path: 'stack',
},
TabRouter: {
screen: createDocPage({
doc: 'api/routers/TabRouter',
title: 'TabRouter',
linkName: 'TabRouter',
}),
path: 'tab',
},
}))(NavView);
const RoutersDocs = createNavigator(
TabRouter({
Routers: {
screen: createDocPage({
doc: 'api/routers/Routers',
title: 'Routers',
linkName: 'Routers',
}),
path: '',
},
RoutersAPI: {
screen: createDocPage({
doc: 'api/routers/RoutersAPI',
title: 'Router API',
linkName: 'Custom Router API',
}),
path: 'api',
},
StackRouter: {
screen: createDocPage({
doc: 'api/routers/StackRouter',
title: 'StackRouter',
linkName: 'StackRouter',
}),
path: 'stack',
},
TabRouter: {
screen: createDocPage({
doc: 'api/routers/TabRouter',
title: 'TabRouter',
linkName: 'TabRouter',
}),
path: 'tab',
},
})
)(NavView);
RoutersDocs.navigationOptions = {
linkName: 'Routers',
icon: 'pt-icon-fork',
};
const ViewsDocs = createNavigator(TabRouter({
Views: {
screen: createDocPage({
doc: 'api/views/Views',
title: 'Views',
linkName: 'Navigation Views',
}),
path: '',
},
TransitionerView: {
screen: createDocPage({
doc: 'api/views/Transitioner',
title: 'Transitioner',
linkName: 'Transitioner',
}),
path: 'transitioner',
},
}))(NavView);
const ViewsDocs = createNavigator(
TabRouter({
Views: {
screen: createDocPage({
doc: 'api/views/Views',
title: 'Views',
linkName: 'Navigation Views',
}),
path: '',
},
TransitionerView: {
screen: createDocPage({
doc: 'api/views/Transitioner',
title: 'Transitioner',
linkName: 'Transitioner',
}),
path: 'transitioner',
},
})
)(NavView);
ViewsDocs.navigationOptions = {
linkName: 'Views',
icon: 'pt-icon-eye-open',
};
const DocsPage = createNavigator(TabRouter({
GuideDocs: {
screen: GuideDocs,
path: 'intro',
},
NavigatorsTab: {
screen: NavigatorsDocs,
path: 'navigators',
},
GuidesTab: {
screen: GuidesDocs,
path: 'guides',
},
RoutersTab: {
screen: RoutersDocs,
path: 'routers',
},
ViewsTab: {
screen: ViewsDocs,
path: 'views',
},
}))(PageWithSidebar);
DocsPage.navigationOptions = ({ navigationOptions }) => ({
const DocsPage = createNavigator(
TabRouter({
GuideDocs: {
screen: GuideDocs,
path: 'intro',
},
NavigatorsTab: {
screen: NavigatorsDocs,
path: 'navigators',
},
GuidesTab: {
screen: GuidesDocs,
path: 'guides',
},
RoutersTab: {
screen: RoutersDocs,
path: 'routers',
},
ViewsTab: {
screen: ViewsDocs,
path: 'views',
},
})
)(PageWithSidebar);
DocsPage.navigationOptions = ({
navigationOptions,
}: {
navigationOptions: any,
}) => ({
title: `${navigationOptions.title} | React Navigation`,
});
@@ -308,35 +321,39 @@ IntroPost.navigationOptions = {
linkName: 'Introduction',
};
const BlogHistoryPage = createNavigator(TabRouter({
RoadToV1: {
screen: createDocPage({
doc: 'blog/2017-04-On-the-path-to-v1',
title: 'On the path to v1',
linkName: 'On the path to v1',
}),
path: '2017/4/On-the-path-to-v1',
},
IntroPost: {
screen: createDocPage({
doc: 'blog/2017-01-Introducing-React-Navigation',
title: 'Introducing React Navigation for React Native',
linkName: 'React Navigation Intro',
}),
path: '2017/1/Introducing-React-Navigation',
},
}))(PageWithSidebar);
const BlogHistoryPage = createNavigator(
TabRouter({
RoadToV1: {
screen: createDocPage({
doc: 'blog/2017-04-On-the-path-to-v1',
title: 'On the path to v1',
linkName: 'On the path to v1',
}),
path: '2017/4/On-the-path-to-v1',
},
IntroPost: {
screen: createDocPage({
doc: 'blog/2017-01-Introducing-React-Navigation',
title: 'Introducing React Navigation for React Native',
linkName: 'React Navigation Intro',
}),
path: '2017/1/Introducing-React-Navigation',
},
})
)(PageWithSidebar);
BlogHistoryPage.navigationOptions = {
linkName: 'Recent Posts',
icon: 'pt-icon-history',
};
const BlogPage = createNavigator(TabRouter({
HistoryTab: {
screen: BlogHistoryPage,
path: '',
},
}))(PageWithSidebar);
const BlogPage = createNavigator(
TabRouter({
HistoryTab: {
screen: BlogHistoryPage,
path: '',
},
})
)(PageWithSidebar);
const NotFoundError = () => (
<div className="errorScreen">
@@ -344,25 +361,27 @@ const NotFoundError = () => (
</div>
);
const App = createNavigator(TabRouter({
Home: {
screen: HomePage,
path: '',
},
Docs: {
screen: DocsPage,
path: 'docs',
},
Blog: {
screen: BlogPage,
path: 'blog',
},
NotFound: {
screen: NotFoundError,
navigationOptions: {
title: 'Page Not Found | React Navigation',
const App = createNavigator(
TabRouter({
Home: {
screen: HomePage,
path: '',
},
},
}))(AppFrame);
Docs: {
screen: DocsPage,
path: 'docs',
},
Blog: {
screen: BlogPage,
path: 'blog',
},
NotFound: {
screen: NotFoundError,
navigationOptions: {
title: 'Page Not Found | React Navigation',
},
},
})
)(AppFrame);
export default App;

View File

@@ -2,11 +2,9 @@ import React from 'react';
import Link from './Link';
import Footer from './Footer';
import {
addNavigationHelpers,
} from 'react-navigation';
import { addNavigationHelpers } from 'react-navigation';
const NavigationLinks = ({navigation, className, reverse}) => {
const NavigationLinks = ({ navigation, className, reverse }) => {
let links = [
...navigation.state.routes.map((route, i) => {
if (route.routeName === 'Home' || route.routeName === 'NotFound') {
@@ -15,8 +13,9 @@ const NavigationLinks = ({navigation, className, reverse}) => {
return (
<Link
to={route.routeName}
className={i === navigation.state.index ? 'active':''}
key={route.routeName}>
className={i === navigation.state.index ? 'active' : ''}
key={route.routeName}
>
{route.routeName}
</Link>
);
@@ -34,55 +33,71 @@ const NavigationLinks = ({navigation, className, reverse}) => {
{links}
</div>
);
}
};
class AppFrame extends React.Component {
state = {isMobileMenuOpen: false};
state = { isMobileMenuOpen: false };
componentWillReceiveProps(props) {
if (this.props.navigation.state !== props.navigation.state) {
this.setState({isMobileMenuOpen: false});
window.scrollTo(0,0);
this.setState({ isMobileMenuOpen: false });
window.scrollTo(0, 0);
}
}
render() {
const {navigation, router} = this.props;
const {isMobileMenuOpen} = this.state;
const { navigation, router } = this.props;
const { isMobileMenuOpen } = this.state;
const childNavigation = addNavigationHelpers({
...navigation,
state: navigation.state.routes[navigation.state.index],
});
const {state} = navigation;
const ScreenView = router.getComponentForRouteName(state.routes[state.index].routeName);
const {routes, index} = state;
const { state } = navigation;
const ScreenView = router.getComponentForRouteName(
state.routes[state.index].routeName
);
const { routes, index } = state;
const route = routes[index];
const hasChildNavigation = !!route.routes;
return (
<div className={`main-app ${isMobileMenuOpen ? 'mobileMenuActive' : ''}`}>
<nav className="pt-navbar" id="navbar"><div className="inner-navbar">
<nav className="pt-navbar" id="navbar">
<div className="inner-navbar">
<Link className="pt-navbar-group pt-align-left project-title" to="Home">
<img src="/assets/react-nav-logo.svg" role="presentation" className="logo" />
<h1 className="pt-navbar-heading">
React Navigation
</h1>
</Link>
<Link
className="pt-navbar-group pt-align-left project-title"
to="Home"
>
<img
src="/assets/react-nav-logo.svg"
role="presentation"
className="logo"
/>
<h1 className="pt-navbar-heading">
React Navigation
</h1>
</Link>
<NavigationLinks navigation={navigation} className="navbuttons" />
<NavigationLinks navigation={navigation} className="navbuttons" />
{hasChildNavigation && (
<span
className={`pt-icon-properties openMenuButton ${isMobileMenuOpen ? 'active' : ''}`}
onClick={() => {
this.setState(s => ({ isMobileMenuOpen: !s.isMobileMenuOpen}));
window.scrollTo(0,0);
}}
/>
)}
{hasChildNavigation &&
<span
className={`pt-icon-properties openMenuButton ${isMobileMenuOpen ? 'active' : ''}`}
onClick={() => {
this.setState(s => ({
isMobileMenuOpen: !s.isMobileMenuOpen,
}));
window.scrollTo(0, 0);
}}
/>}
</div></nav>
</div>
</nav>
<NavigationLinks navigation={navigation} className="mobile-navbuttons" reverse />
<NavigationLinks
navigation={navigation}
className="mobile-navbuttons"
reverse
/>
<ScreenView navigation={childNavigation} />

View File

@@ -1,5 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import { NavigationActions, addNavigationHelpers } from 'react-navigation';
@@ -14,43 +14,69 @@ function getAction(router, path, params) {
});
}
module.exports = (NavigationAwareView) => {
const initialAction = getAction(NavigationAwareView.router, window.location.pathname.substr(1));
const initialState = NavigationAwareView.router.getStateForAction(initialAction);
console.log({initialAction, initialState});
export default NavigationAwareView => {
const initialAction = getAction(
NavigationAwareView.router,
window.location.pathname.substr(1)
);
const initialState = NavigationAwareView.router.getStateForAction(
initialAction
);
console.log({ initialAction, initialState });
class NavigationContainer extends React.Component {
state = initialState;
componentDidMount() {
const navigation = addNavigationHelpers({state: this.state.routes[this.state.index], dispatch: this.dispatch});
document.title = NavigationAwareView.router.getScreenOptions(navigation).title;
window.onpopstate = (e) => {
const navigation = addNavigationHelpers({
state: this.state.routes[this.state.index],
dispatch: this.dispatch,
});
document.title = NavigationAwareView.router.getScreenOptions(
navigation
).title;
window.onpopstate = e => {
e.preventDefault();
const action = getAction(NavigationAwareView.router, window.location.pathname.substr(1));
const action = getAction(
NavigationAwareView.router,
window.location.pathname.substr(1)
);
if (action) this.dispatch(action);
};
}
componentWillUpdate(props, state) {
const {path, params} = NavigationAwareView.router.getPathAndParamsForState(state);
const {
path,
params,
} = NavigationAwareView.router.getPathAndParamsForState(state);
const maybeHash = params && params.hash ? `#${params.hash}` : '';
const uri = `/${path}${maybeHash}`;
if (window.location.pathname !== uri) {
window.history.pushState({}, state.title, uri);
}
const navigation = addNavigationHelpers({state: state.routes[state.index], dispatch: this.dispatch});
document.title = NavigationAwareView.router.getScreenOptions(navigation).title;
const navigation = addNavigationHelpers({
state: state.routes[state.index],
dispatch: this.dispatch,
});
document.title = NavigationAwareView.router.getScreenOptions(
navigation
).title;
}
componentDidUpdate() {
const {params} = NavigationAwareView.router.getPathAndParamsForState(this.state);
const { params } = NavigationAwareView.router.getPathAndParamsForState(
this.state
);
if (params && params.hash) {
document.getElementById(params.hash).scrollIntoView();
}
}
dispatch = (action) => {
const state = NavigationAwareView.router.getStateForAction(action, this.state);
dispatch = action => {
const state = NavigationAwareView.router.getStateForAction(
action,
this.state
);
if (!state) {
console.log('Dispatched action did not change state: ', {action});
console.log('Dispatched action did not change state: ', { action });
} else if (console.group) {
console.group('Navigation Dispatch: ');
console.log('Action: ', action);
@@ -58,7 +84,11 @@ module.exports = (NavigationAwareView) => {
console.log('Last State: ', this.state);
console.groupEnd();
} else {
console.log('Navigation Dispatch: ', {action, newState: state, lastState: this.state});
console.log('Navigation Dispatch: ', {
action,
newState: state,
lastState: this.state,
});
}
if (!state) {
@@ -72,20 +102,31 @@ module.exports = (NavigationAwareView) => {
return false;
};
render() {
return <NavigationAwareView navigation={addNavigationHelpers({state: this.state, dispatch: this.dispatch})} />
return (
<NavigationAwareView
navigation={addNavigationHelpers({
state: this.state,
dispatch: this.dispatch,
})}
/>
);
}
getURIForAction = (action) => {
const state = NavigationAwareView.router.getStateForAction(action, this.state) || this.state;
const {path} = NavigationAwareView.router.getPathAndParamsForState(state);
getURIForAction = action => {
const state =
NavigationAwareView.router.getStateForAction(action, this.state) ||
this.state;
const { path } = NavigationAwareView.router.getPathAndParamsForState(
state
);
return `/${path}`;
}
};
getActionForPathAndParams = (path, params) => {
return NavigationAwareView.router.getActionForPathAndParams(path, params);
}
};
static childContextTypes = {
getActionForPathAndParams: React.PropTypes.func.isRequired,
getURIForAction: React.PropTypes.func.isRequired,
dispatch: React.PropTypes.func.isRequired,
getActionForPathAndParams: PropTypes.func.isRequired,
getURIForAction: PropTypes.func.isRequired,
dispatch: PropTypes.func.isRequired,
};
getChildContext() {
return {

View File

@@ -1,19 +1,21 @@
import React from 'react';
const Footer = () => (
<div className="footer"><div className="inner-footer">
<div className="footer">
<div className="inner-footer">
<section className="copyright">
<a href="https://github.com/react-community/react-navigation">
React Navigation
</a>
·
<a href="https://github.com/react-community/react-navigation/blob/master/LICENSE">
Distributed under BSD License
</a>
</section>
<section className="copyright">
<a href="https://github.com/react-community/react-navigation">
React Navigation
</a>
·
<a href="https://github.com/react-community/react-navigation/blob/master/LICENSE">
Distributed under BSD License
</a>
</section>
</div></div>
</div>
</div>
);
export default Footer;

View File

@@ -10,7 +10,7 @@ const GettingStartedButton = () => (
<div className="cta-row">
<Link className="cta" to="GettingStarted">
<span className="label">Get Started</span>
<span className="icon pt-icon-arrow-right"></span>
<span className="icon pt-icon-arrow-right" />
</Link>
</div>
);
@@ -20,7 +20,7 @@ const ExampleCodeBrowser = (config, ExampleFiles) => {
class CodeBrowser extends Component {
state = { index: 0 };
render() {
const {index} = this.state;
const { index } = this.state;
return (
<div className={this.props.alt ? 'code-example alt' : 'code-example'}>
<div className="code-example-section">
@@ -31,7 +31,8 @@ const ExampleCodeBrowser = (config, ExampleFiles) => {
<a
key={fileName}
className={index === i ? 'active' : ''}
onClick={() => this.setState({ index: i })}>
onClick={() => this.setState({ index: i })}
>
{fileName}
</a>
);
@@ -39,10 +40,7 @@ const ExampleCodeBrowser = (config, ExampleFiles) => {
</div>
<CodeBlock code={ExampleFiles[fileNames[index]]} />
</div>
<PhoneGraphic
sources={config.examples}
alt={this.props.alt}
/>
<PhoneGraphic sources={config.examples} alt={this.props.alt} />
</div>
</div>
);
@@ -51,14 +49,16 @@ const ExampleCodeBrowser = (config, ExampleFiles) => {
return CodeBrowser;
};
const StackExampleBrowser = ExampleCodeBrowser({
title: 'Stack Navigator',
examples: {
iphone: '/assets/iphone-stack.gif',
android: '/assets/android-stack.gif',
const StackExampleBrowser = ExampleCodeBrowser(
{
title: 'Stack Navigator',
examples: {
iphone: '/assets/iphone-stack.gif',
android: '/assets/android-stack.gif',
},
},
}, {
'BasicApp.js': `\
{
'BasicApp.js': `\
import {
StackNavigator,
} from 'react-navigation';
@@ -68,7 +68,7 @@ const BasicApp = StackNavigator({
Profile: {screen: ProfileScreen},
});
`,
'MainScreen.js': `\
'MainScreen.js': `\
class MainScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
@@ -85,7 +85,7 @@ class MainScreen extends React.Component {
);
}
}`,
'ProfileScreen.js': `\
'ProfileScreen.js': `\
class ProfileScreen extends React.Component {
static navigationOptions = ({navigation}) => ({
title: navigation.state.params.name,
@@ -100,16 +100,19 @@ class ProfileScreen extends React.Component {
);
}
}`,
});
}
);
const TabExampleBrowser = ExampleCodeBrowser({
title: 'Tab Navigator',
examples: {
iphone: '/assets/iphone-tabs.gif',
android: '/assets/android-tabs.gif',
const TabExampleBrowser = ExampleCodeBrowser(
{
title: 'Tab Navigator',
examples: {
iphone: '/assets/iphone-tabs.gif',
android: '/assets/android-tabs.gif',
},
},
}, {
'BasicApp.js': `\
{
'BasicApp.js': `\
import {
TabNavigator,
} from 'react-navigation';
@@ -119,7 +122,7 @@ const BasicApp = TabNavigator({
Setup: {screen: SetupScreen},
});
`,
'MainScreen.js': `\
'MainScreen.js': `\
class MainScreen extends React.Component {
static navigationOptions = {
tabBarLabel: 'Home',
@@ -134,7 +137,7 @@ class MainScreen extends React.Component {
);
}
}`,
'SetupScreen.js': `\
'SetupScreen.js': `\
class SetupScreen extends React.Component {
static navigationOptions = {
tabBarLabel: 'Setup',
@@ -149,7 +152,8 @@ class SetupScreen extends React.Component {
);
}
}`,
});
}
);
class HomePage extends Component {
static navigationOptions = {
@@ -164,35 +168,47 @@ class HomePage extends Component {
<div className="hero">
<h1>Navigation for React Native</h1>
<div className="video">
<iframe src="https://player.vimeo.com/video/201061589" width="720" height="410" frameBorder="0" allowFullScreen></iframe>
<iframe
src="https://player.vimeo.com/video/201061589"
width="720"
height="410"
frameBorder="0"
allowFullScreen
/>
</div>
<GettingStartedButton />
</div>
<div className="section">
<div className="section-inner">
<h1>Easy-to-Use Navigators</h1>
<h3>Start quickly with built-in navigators that deliver a seamless out-of-the box experience.</h3>
<div className="section-inner">
<h1>Easy-to-Use Navigators</h1>
<h3>
Start quickly with built-in navigators that deliver a seamless out-of-the box experience.
</h3>
<StackExampleBrowser />
</div>
<StackExampleBrowser />
</div>
</div>
<div className="section alt">
<div className="section-inner">
<h1>Components built for iOS and Android</h1>
<h3>Navigation views that deliver 60fps animations, and utilize native components to deliver a great look and feel.</h3>
<div className="section-inner">
<h1>Components built for iOS and Android</h1>
<h3>
Navigation views that deliver 60fps animations, and utilize native components to deliver a great look and feel.
</h3>
<TabExampleBrowser alt />
</div>
<TabExampleBrowser alt />
</div>
</div>
<div className="section">
<div className="section-inner">
<h1>Routers built for the future</h1>
<h3>Routers define the relationship between URIs, actions, and navigation state. Share navigation logic between mobile apps, web apps, and server rendering.</h3>
<GettingStartedButton />
</div>
<div className="section-inner">
<h1>Routers built for the future</h1>
<h3>
Routers define the relationship between URIs, actions, and navigation state. Share navigation logic between mobile apps, web apps, and server rendering.
</h3>
<GettingStartedButton />
</div>
</div>
<Footer />

View File

@@ -1,22 +1,19 @@
import React, { PropTypes, Component } from 'react';
import { NavigationActions } from 'react-navigation'
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { NavigationActions } from 'react-navigation';
const isModifiedEvent = (event) =>
const isModifiedEvent = event =>
!!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
const Linkable = (Inner) => {
const Linkable = Inner => {
class LinkableWrapped extends Component {
render() {
return (
<Inner
href={this.getURL()}
onClick={this.onClick}
{...this.props}
/>
<Inner href={this.getURL()} onClick={this.onClick} {...this.props} />
);
}
getAction = () => {
const {to, href} = this.props;
const { to, href } = this.props;
if (typeof to === 'string') {
return NavigationActions.navigate({ routeName: to });
} else if (typeof to === 'object' && typeof to.type === 'string') {
@@ -35,7 +32,7 @@ const Linkable = (Inner) => {
}
return null;
}
}
};
onClick = e => {
const action = this.getAction();
if (!isModifiedEvent(e) && action) {
@@ -55,7 +52,7 @@ const Linkable = (Inner) => {
};
}
return LinkableWrapped;
}
};
const Link = Linkable(props => <a {...props} />);

View File

@@ -1,4 +1,3 @@
import React from 'react';
const Markdown = require('react-markdown');
const DocsMD = require('../docs-dist.json');
@@ -7,9 +6,14 @@ import PhoneGraphic from './PhoneGraphic';
const slugify = require('slugify');
import CodeBlock from './CodeBlock';
const safeString = s => slugify(s).replace(/\)/g, '-').replace(/\(/g, '-').replace(/^-/,'').replace(/-$/,'');
const safeString = s =>
slugify(s)
.replace(/\)/g, '-')
.replace(/\(/g, '-')
.replace(/^-/, '')
.replace(/-$/, '');
const getHeadingForLevel = (level) => {
const getHeadingForLevel = level => {
switch (level) {
case 2:
return 'h2';
@@ -29,12 +33,12 @@ const getHeadingForLevel = (level) => {
}
};
const MDPage = ({navigation, docPath}) => (
const MDPage = ({ navigation, docPath }) => (
<Markdown
source={DocsMD[docPath]}
className="md-section"
renderers={{
CodeBlock: ({literal, language}) => {
CodeBlock: function CodeBlock({ literal, language }) {
if (language === 'phone-example') {
const graphicName = literal.trim();
return (
@@ -47,18 +51,18 @@ const MDPage = ({navigation, docPath}) => (
/>
);
}
return (
<CodeBlock code={literal} />
);
return <CodeBlock code={literal} />;
},
Heading: ({level, children}) => {
let id = React.Children.map(children, (child) => {
if (typeof child === 'string') {
return safeString(child);
} else if (typeof child.props.children === 'string') {
return safeString(child.props.children);
}
}).join('-');
Heading: function Heading({ level, children }) {
let id = React.Children
.map(children, child => {
if (typeof child === 'string') {
return safeString(child);
} else if (typeof child.props.children === 'string') {
return safeString(child.props.children);
}
})
.join('-');
const Header = getHeadingForLevel(level);
return (
<Header id={id} className="md-header">
@@ -66,17 +70,11 @@ const MDPage = ({navigation, docPath}) => (
</Header>
);
},
link: ({children, href}) => {
link: function link({ children, href }) {
if (href.indexOf('PhoneGraphic:') === 0) {
const graphicName = href.split('PhoneGraphic:')[1];
}
return (
<Link
children={children}
href={href}
/>
);
return <Link href={href}>{children}</Link>;
},
}}
/>

View File

@@ -1,6 +1,6 @@
import React, { Component } from 'react';
import Link from "./Link";
import Link from './Link';
import { NavigationActions, addNavigationHelpers } from 'react-navigation';
@@ -16,8 +16,8 @@ function getConfig(router, state, action, configName) {
class PageWithSidebar extends Component {
render() {
const {router, navigation} = this.props;
const {dispatch, state} = navigation;
const { router, navigation } = this.props;
const { dispatch, state } = navigation;
const ActiveScreen = router.getComponentForState(state);
let prevAction = null;
if (state.routes[state.index].index > 0) {
@@ -31,12 +31,17 @@ class PageWithSidebar extends Component {
prevAction = NavigationActions.navigate({
routeName: state.routes[prev].routeName,
action: NavigationActions.navigate({
routeName: state.routes[prev].routes[state.routes[prev].routes.length - 1].routeName,
})
routeName: state.routes[prev].routes[
state.routes[prev].routes.length - 1
].routeName,
}),
});
}
let nextAction = null;
if (state.routes[state.index].index < state.routes[state.index].routes.length - 1) {
if (
state.routes[state.index].index <
state.routes[state.index].routes.length - 1
) {
const next = state.routes[state.index].index + 1;
nextAction = NavigationActions.navigate({
routeName: state.routes[state.index].routes[next].routeName,
@@ -48,64 +53,96 @@ class PageWithSidebar extends Component {
routeName: state.routes[next].routeName,
});
}
let prevName = prevAction && getConfig(router, state, prevAction, 'linkName');
let nextName = nextAction && getConfig(router, state, nextAction, 'linkName');
const docPath = getConfig(router, state, null, 'doc')+'.md';
let prevName =
prevAction && getConfig(router, state, prevAction, 'linkName');
let nextName =
nextAction && getConfig(router, state, nextAction, 'linkName');
const docPath = getConfig(router, state, null, 'doc') + '.md';
return (
<div className="page-body"><div className="inner-page-body">
<div className="page-body">
<div className="inner-page-body">
<div className="left-sidebar">
<ul className="pt-menu pt-elevation-1 navmenu">
{state.routes &&
state.routes.map((route, i) => {
const DocComponent = router.getComponentForRouteName(
route.routeName
);
const childNavigation = addNavigationHelpers({
state: route,
dispatch,
});
const options = router.getScreenOptions(childNavigation, {});
const isActive = state.index === i;
return (
<span key={i}>
<LinkableLi
to={route.routeName}
className={
'pt-menu-header ' +
options.icon +
' ' +
(isActive ? 'active' : '')
}
>
<h6>{options.linkName}</h6>
</LinkableLi>
<div>
{route.routes &&
route.routes.map((childRoute, childI) => {
const isChildActive =
isActive && route.index === childI;
const secondChildNavigation = addNavigationHelpers({
state: childRoute,
dispatch,
});
const secondOptions =
DocComponent.router &&
DocComponent.router.getScreenOptions(
secondChildNavigation,
{}
);
const routerLinkName =
secondOptions && secondOptions.linkName;
const linkName =
routerLinkName || childRoute.routeName;
return (
<Link
to={childRoute.routeName}
className={`pt-menu-item page ${isChildActive ? 'active' : ''}`}
key={childI}
>
{linkName}
</Link>
);
})}
</div>
</span>
);
})}
</ul>
</div>
<div className="main-section">
<ActiveScreen navigation={this.props.navigation} />
<hr />
{state.routeName === 'Docs' &&
<Link
href={`https://github.com/react-community/react-navigation/tree/master/docs/${docPath}`}
className="editLink"
>
{' '}Edit on GitHub
</Link>}
{prevAction && <Link to={prevAction}>Previous: {prevName}</Link>}
{nextAction &&
<Link to={nextAction} className="nextLink">
Next: {nextName}
</Link>}
</div>
<div className="left-sidebar">
<ul className="pt-menu pt-elevation-1 navmenu">
{state.routes && state.routes.map((route, i) => {
const DocComponent = router.getComponentForRouteName(route.routeName);
const childNavigation = addNavigationHelpers({
state: route,
dispatch,
});
const options = router.getScreenOptions(childNavigation, {});
const isActive = state.index === i;
return (
<span key={i}>
<LinkableLi
to={route.routeName}
className={"pt-menu-header "+options.icon+' '+(isActive?'active':'')}>
<h6>{options.linkName}</h6>
</LinkableLi>
<div>
{route.routes && route.routes.map((childRoute, childI) => {
const isChildActive = isActive && route.index === childI;
const secondChildNavigation = addNavigationHelpers({
state: childRoute,
dispatch,
});
const secondOptions = DocComponent.router && DocComponent.router.getScreenOptions(secondChildNavigation, {});
const routerLinkName = secondOptions && secondOptions.linkName;
const linkName = routerLinkName || childRoute.routeName;
return (
<Link
to={childRoute.routeName}
className={`pt-menu-item page ${(isChildActive) ? 'active' : ''}`}
key={childI}>
{linkName}
</Link>
);
})}
</div>
</span>
);
})}
</ul>
</div>
<div className="main-section">
<ActiveScreen navigation={this.props.navigation} />
<hr />
{state.routeName === 'Docs' && <Link href={`https://github.com/react-community/react-navigation/tree/master/docs/${docPath}`} className="editLink"> Edit on GitHub</Link>}
{prevAction && <Link to={prevAction}>Previous: {prevName}</Link>}
{nextAction && <Link to={nextAction} className="nextLink">Next: {nextName}</Link>}
</div>
</div></div>
</div>
);
}
}

View File

@@ -1,30 +1,36 @@
/**
* @flow
*/
import React, { Component } from 'react';
export default class PhoneGraphic extends Component {
props: { sources: { android: string, iphone: string } };
state = { activeExample: this.props.alt ? 'android' : 'iphone' };
render() {
const {activeExample} = this.state;
const { activeExample } = this.state;
return (
<div className="example-section">
<div className="buttonbar">
<a
className={activeExample === 'android'}
onClick={() => this.setState({ activeExample: 'android' })}>
onClick={() => this.setState({ activeExample: 'android' })}
>
Android
</a>
<a
className={activeExample === 'iphone'}
onClick={() => this.setState({ activeExample: 'iphone' })}>
onClick={() => this.setState({ activeExample: 'iphone' })}
>
iPhone
</a>
</div>
<div className="phone">
<div className={`android ${activeExample === 'android'}`}>
<div className={`android ${String(activeExample === 'android')}`}>
<img src={this.props.sources.android} role="presentation" />
</div>
<div className="phone-example-spacer" />
<div className={`iphone ${activeExample === 'iphone'}`}>
<div className={`iphone ${String(activeExample === 'iphone')}`}>
<img src={this.props.sources.iphone} role="presentation" />
</div>
</div>

View File

@@ -1,8 +1,8 @@
const path = require('path');
const express = require('express');
const fs = require('fs');
const React = require('react');
const PropTypes = require('prop-types');
const join = require('path').join;
const basicAuth = require('basic-auth-connect');
const server = require('express');
@@ -14,14 +14,14 @@ import { NavigationActions, addNavigationHelpers } from 'react-navigation';
class ServerApp extends React.Component {
static childContextTypes = {
getURIForAction: React.PropTypes.func.isRequired,
getActionForPathAndParams: React.PropTypes.func.isRequired,
dispatch: React.PropTypes.func.isRequired,
getURIForAction: PropTypes.func.isRequired,
getActionForPathAndParams: PropTypes.func.isRequired,
dispatch: PropTypes.func.isRequired,
};
getChildContext() {
return {
dispatch: this.props.navigation.dispatch,
getURIForAction: (action) => {
getURIForAction: action => {
const state = App.router.getStateForAction(action);
let { path } = App.router.getPathAndParamsForState(state);
return `/${path}`;
@@ -34,19 +34,24 @@ class ServerApp extends React.Component {
}
}
const indexHtml = fs.readFileSync(join(__dirname, '../public/index.html'), { encoding: 'utf8' });
const indexHtml = fs.readFileSync(join(__dirname, '../public/index.html'), {
encoding: 'utf8',
});
function AppHandler(req, res) {
let status = 200;
const path = req.url.substr(1)
const path = req.url.substr(1);
let initAction = App.router.getActionForPathAndParams(path);
if (!initAction) {
initAction = NavigationActions.navigate({ routeName: 'NotFound', params: { path } });
initAction = NavigationActions.navigate({
routeName: 'NotFound',
params: { path },
});
status = 404;
}
const topNavigation = addNavigationHelpers({
state: App.router.getStateForAction(initAction),
dispatch: (action) => false,
dispatch: action => false,
});
const screenNavigation = addNavigationHelpers({
state: topNavigation.state.routes[topNavigation.state.index],
@@ -58,7 +63,9 @@ function AppHandler(req, res) {
const app = <ServerApp navigation={topNavigation} />;
const body = ReactDOMServer.renderToString(app);
let html = indexHtml;
html = html.split('<div id="root"></div>').join(`<div id="root">${body}</div>`)
html = html
.split('<div id="root"></div>')
.join(`<div id="root">${body}</div>`);
if (title) {
html = html.split('<title></title>').join(`<title>${title}</title>`);
}

View File

@@ -9,7 +9,4 @@ import '@blueprintjs/core/dist/blueprint.css';
const ClientApp = BrowserAppContainer(App);
ReactDOM.render(
<ClientApp />,
document.getElementById('root')
);
ReactDOM.render(<ClientApp />, document.getElementById('root'));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff