Compare commits

..

38 Commits

Author SHA1 Message Date
Brent Vatne
cbe46d7303 Bump version 2018-03-31 12:13:16 -07:00
Brent Vatne
11a99c8aaf minHeight not needed, bump up minWidth 2018-03-31 12:12:35 -07:00
Brent Vatne
6b5100c335 Bump dependencies in NavigationPlayground 2018-03-31 12:11:09 -07:00
Brent Vatne
34dd1fe490 Better example for focus including tab bar top 2018-03-31 12:11:09 -07:00
Brent Vatne
0cc9070dcd Add min width and height to tab bar icon due to absolute position layout bug in 0.54 2018-03-31 12:11:09 -07:00
Eric Vicenti
e369c89b81 Add example for extending the Tab navigator (#3775) 2018-03-18 20:14:56 -04:00
Brent Vatne
99bf123ff2 Release 1.5.8 2018-03-16 07:45:42 -07:00
Brent Vatne
feb93411bc Use react-native-tab-view fork with cherry-picked ViewPagerAndroid fix 2018-03-16 07:43:52 -07:00
Brent Vatne
86f07175fb Release 1.5.7 2018-03-15 10:20:20 -07:00
Brent Vatne
8288853e3c Update snapshots 2018-03-15 10:20:09 -07:00
Brent Vatne
c4bd2db542 Another fix for frustrating tab bar icon layout issue 2018-03-15 10:19:40 -07:00
Brent Vatne
ee40dd7d24 Release 1.5.6 2018-03-14 21:50:20 -07:00
Brent Vatne
18a48105c2 Missed a case where we should not have flexGrow 2018-03-14 21:50:06 -07:00
Brent Vatne
fbac47b696 Release 1.5.5 2018-03-14 21:35:26 -07:00
Brent Vatne
9aab47dac2 Apply horizontal icon style whenever we should use horizontal tabs in icon 2018-03-14 21:35:07 -07:00
Brent Vatne
67309c00a6 Release 1.5.4 2018-03-14 11:21:15 -07:00
Moti Zilberman
86a724cfe3 Swap addListener out for isFocused prop on ResourceSavingSceneView (#3718)
This is a backport of 81a86fa091 from master.
2018-03-14 11:20:30 -07:00
Brent Vatne
eb78128439 Release 1.5.3 2018-03-14 11:16:19 -07:00
Brent Vatne
c39ec7a10c Use arrow function instead of bind 2018-03-14 11:16:01 -07:00
Chris
0ff3347e97 Update CardStack.js (#3749)
fix for https://github.com/react-navigation/react-navigation/issues/3729 , https://github.com/react-navigation/react-navigation/issues/3746
2018-03-14 11:08:26 -07:00
Brent Vatne
b9d55a6330 Release 1.5.2 2018-03-12 11:12:31 -07:00
Brent Vatne
315e43701b Fix tab icon height on horizontal / ipad 2018-03-12 11:12:22 -07:00
Hugo Dozois
1d573bc246 Fix isFocused from withNavigationFocus is a function (#3710)
Fixes #3709
2018-03-11 22:26:33 +01:00
Eric Vicenti
3bfb0b90d0 Fix onTransitionEnd props passthrough
Fixes #3647
2018-03-10 00:09:02 -08:00
Brent Vatne
8a129afe13 Release 1.5.1 2018-03-09 11:33:06 -08:00
Brent Vatne
ab2a63fe92 Update snapshot for tab icon changes 2018-03-09 11:32:53 -08:00
Brandon Smith
c411210ecc Pass initialRouteKey into StackRouter (#3540) (#3701) 2018-03-09 11:31:41 -08:00
Brent Vatne
01e7296520 Release 1.5.0 2018-03-07 17:42:38 -08:00
corupta
8f3e0997c5 Add activeLabelStyle and inactiveLabelStyle for DrawerItem (#3559)
* Add activeLabelStyle and inactiveLabelStyle

Adding activeLabelStyle, so that active items can be customized more.
My use case: Change font of the active item to bold.
Also, added inactiveLabelStyle which can be used for a similar purpose.

* prettier fix

* Update react-navigation.js

* prettier fix

* Update jest snapshot for DrawerNavigator - for adding a new style property to the styles array
2018-03-07 17:38:02 -08:00
Nicolas Beck
3f3ef6485c Add initialRouteKey for StackRouter (#3540)
* use initialRouteName as key when initializing StackRouter

* fix null headerLeft

* merge back

* fixed tests

* use config flag

* fixed snapshots

* implemented requested changes
2018-03-07 17:38:02 -08:00
Vishwesh Jainkuniya
b12abb553f Fix: tabBar icons are not visible. (#3650)
* Fix: tabBar icons are not visible.

* Fix: tests.
2018-03-07 17:38:02 -08:00
Ashoat Tevosyan
e02841a979 [Flow] Some updates, mostly from flow-typed (#3682)
1. Remove `NavigationComponent` from `NavigationScreenRouteConfig`. The only context `NavigationScreenRouteConfig` is used in is as an intersection with an object, and as such the only relevant portions of `NavigationScreenRouteConfig` are the object parts.
2. Add static `HEIGHT` variable to `Header` type.
3. In `NavigationContainerProps`, make `onNavigationStateChange` property value nullable.

PS: if in the future you guys would prefer that I separate these sort of PRs into their constituent parts, let me know.
2018-03-07 18:21:15 -05:00
Ben Styles
e147f34555 Allow passing null to onNavigationStateChange prop (#3683)
As seen here: react-navigation/react-navigation#360, we need to be able to pass null to turn off logging.
2018-03-07 18:20:58 -05:00
Sirui Li
81e0ce136e Flow type: SafeAreaView doesn't require children (#3670)
`children` prop should be optional.
2018-03-07 18:20:44 -05:00
Edward Drapkin
8ba727c2cf More specific injected Navigation props (#3645) 2018-03-07 18:19:37 -05:00
Yordis Prieto
9a86ef8362 Fix typespec of back action creator (#3659) 2018-03-07 18:19:26 -05:00
Ashoat Tevosyan
4fe7c92847 Fix NavigationEventPayload.lastState type (#3664)
Should be nullable, since it is initially called as `null` in `src/createNavigationContainer.js` (and in `react-navigation-redux-helpers`, where it is causing a Flow error)
2018-03-07 18:19:10 -05:00
Leon Miller-Out
afecaaed7f Call react-navigation-redux-helpers's initializeListeners() when mounting app. (#3666)
This makes the first navigation click work correctly, per
https://github.com/react-navigation/react-navigation-redux-helpers/issues/7
2018-03-05 15:02:34 -05:00
27 changed files with 3034 additions and 1522 deletions

View File

@@ -11,7 +11,7 @@
"splash": {
"image": "./assets/icons/splash.png"
},
"sdkVersion": "25.0.0",
"sdkVersion": "26.0.0",
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
"packagerOpts": {
"assetExts": [

View File

@@ -32,6 +32,7 @@ import SimpleStack from './SimpleStack';
import StackWithHeaderPreset from './StackWithHeaderPreset';
import StackWithTranslucentHeader from './StackWithTranslucentHeader';
import SimpleTabs from './SimpleTabs';
import CustomTabNavigator from './CustomTabNavigator';
import TabAnimations from './TabAnimations';
import TabsWithNavigationFocus from './TabsWithNavigationFocus';
@@ -72,9 +73,13 @@ const ExampleInfo = {
name: 'Drawer + Tabs Example',
description: 'A drawer combined with tabs',
},
CustomTabNavigator: {
name: 'Custom Tab Navigator Example',
description: 'Extending the tab navigator',
},
CustomTabs: {
name: 'Custom Tabs',
description: 'Custom tabs with tab router',
name: 'Custom Tabs View',
description: 'Custom tabs using TabRouter',
},
CustomTransitioner: {
name: 'Custom Transitioner',
@@ -137,6 +142,7 @@ const ExampleRoutes = {
StacksWithKeys,
StacksInTabs,
StacksOverTabs,
CustomTabNavigator,
LinkStack: {
screen: SimpleStack,
path: 'people/Jordan',

View File

@@ -0,0 +1,201 @@
/**
* @flow
*/
import type {
NavigationScreenProp,
NavigationEventSubscription,
} from 'react-navigation';
import React from 'react';
import {
Button,
Platform,
ScrollView,
StatusBar,
View,
Text,
StyleSheet,
TouchableOpacity,
} from 'react-native';
import { SafeAreaView, TabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import SampleText from './SampleText';
const MyNavScreen = ({ navigation, banner }) => (
<SafeAreaView forceInset={{ horizontal: 'always', top: 'always' }}>
<SampleText>{banner}</SampleText>
<Button
onPress={() => navigation.navigate('Home')}
title="Go to home tab"
/>
<Button
onPress={() => navigation.navigate('Settings')}
title="Go to settings tab"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
);
const MyHomeScreen = ({ navigation }) => (
<MyNavScreen banner="Home Tab" navigation={navigation} />
);
MyHomeScreen.navigationOptions = {
tabBarTestIDProps: {
testID: 'TEST_ID_HOME',
accessibilityLabel: 'TEST_ID_HOME_ACLBL',
},
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home-outline'}
size={26}
style={{ color: tintColor }}
/>
),
};
type MyPeopleScreenProps = {
navigation: NavigationScreenProp<*>,
};
class MyPeopleScreen extends React.Component<MyPeopleScreenProps> {
static navigationOptions = {
tabBarLabel: 'People',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-people' : 'ios-people-outline'}
size={26}
style={{ color: tintColor }}
/>
),
};
render() {
const { navigation } = this.props;
return <MyNavScreen banner="People Tab" navigation={navigation} />;
}
}
type MyChatScreenProps = {
navigation: NavigationScreenProp<*>,
};
class MyChatScreen extends React.Component<MyChatScreenProps> {
static navigationOptions = {
tabBarLabel: 'Chat',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-chatboxes' : 'ios-chatboxes-outline'}
size={26}
style={{ color: tintColor }}
/>
),
};
render() {
const { navigation } = this.props;
return <MyNavScreen banner="Chat Tab" navigation={navigation} />;
}
}
const MySettingsScreen = ({ navigation }) => (
<MyNavScreen banner="Settings Tab" navigation={navigation} />
);
MySettingsScreen.navigationOptions = {
tabBarLabel: 'Settings',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-settings' : 'ios-settings-outline'}
size={26}
style={{ color: tintColor }}
/>
),
};
const SimpleTabs = TabNavigator(
{
Home: {
screen: MyHomeScreen,
},
People: {
screen: MyPeopleScreen,
},
Chat: {
screen: MyChatScreen,
},
Settings: {
screen: MySettingsScreen,
},
},
{
navigationOptions: {
tabBarVisible: false,
},
}
);
type SimpleTabsContainerProps = {
navigation: NavigationScreenProp<*>,
};
const TabBarButton = ({ name, navigation }) => {
const currentName = navigation.state.routes[navigation.state.index].routeName;
return (
<TouchableOpacity
onPress={() => {
navigation.navigate(name);
}}
>
<Text
style={{ color: currentName === name ? 'blue' : 'black', fontSize: 32 }}
>
{name}
</Text>
</TouchableOpacity>
);
};
class CustomTabBar extends React.Component<*> {
render() {
return (
<View
style={{
height: 40,
flexDirection: 'row',
justifyContent: 'space-between',
borderTopWidth: StyleSheet.hairlineWidth,
}}
>
<TabBarButton navigation={this.props.navigation} name="Home" />
<TabBarButton navigation={this.props.navigation} name="People" />
<TabBarButton navigation={this.props.navigation} name="Chat" />
</View>
);
}
}
class SimpleTabsContainer extends React.Component<SimpleTabsContainerProps> {
static router = {
...SimpleTabs.router,
getStateForAction(action, lastState) {
// You can override the behavior navigation actions here, which are dispatched via navigation.dispatch, or via helpers like navigaiton.navigate.
// In this case we simply use the default behavior:
const newState = SimpleTabs.router.getStateForAction(action, lastState);
console.log('Tab router action:', action, newState);
return newState;
},
};
render() {
return (
<View style={{ flex: 1 }}>
<SimpleTabs navigation={this.props.navigation} />
<CustomTabBar navigation={this.props.navigation} />
</View>
);
}
}
export default SimpleTabsContainer;

View File

@@ -52,11 +52,6 @@ type MyPeopleScreenProps = {
navigation: NavigationScreenProp<*>,
};
class MyPeopleScreen extends React.Component<MyPeopleScreenProps> {
_s0: NavigationEventSubscription;
_s1: NavigationEventSubscription;
_s2: NavigationEventSubscription;
_s3: NavigationEventSubscription;
static navigationOptions = {
tabBarLabel: 'People',
tabBarIcon: ({ tintColor, focused }) => (
@@ -67,21 +62,6 @@ class MyPeopleScreen extends React.Component<MyPeopleScreenProps> {
/>
),
};
componentDidMount() {
this._s0 = this.props.navigation.addListener('willFocus', this._onEvent);
this._s1 = this.props.navigation.addListener('didFocus', this._onEvent);
this._s2 = this.props.navigation.addListener('willBlur', this._onEvent);
this._s3 = this.props.navigation.addListener('didBlur', this._onEvent);
}
componentWillUnmount() {
this._s0.remove();
this._s1.remove();
this._s2.remove();
this._s3.remove();
}
_onEvent = a => {
console.log('EVENT ON PEOPLE TAB', a.type, a);
};
render() {
const { navigation } = this.props;
return <MyNavScreen banner="People Tab" navigation={navigation} />;
@@ -92,11 +72,6 @@ type MyChatScreenProps = {
navigation: NavigationScreenProp<*>,
};
class MyChatScreen extends React.Component<MyChatScreenProps> {
_s0: NavigationEventSubscription;
_s1: NavigationEventSubscription;
_s2: NavigationEventSubscription;
_s3: NavigationEventSubscription;
static navigationOptions = {
tabBarLabel: 'Chat',
tabBarIcon: ({ tintColor, focused }) => (
@@ -107,21 +82,6 @@ class MyChatScreen extends React.Component<MyChatScreenProps> {
/>
),
};
componentDidMount() {
this._s0 = this.props.navigation.addListener('willFocus', this._onEvent);
this._s1 = this.props.navigation.addListener('didFocus', this._onEvent);
this._s2 = this.props.navigation.addListener('willBlur', this._onEvent);
this._s3 = this.props.navigation.addListener('didBlur', this._onEvent);
}
componentWillUnmount() {
this._s0.remove();
this._s1.remove();
this._s2.remove();
this._s3.remove();
}
_onEvent = a => {
console.log('EVENT ON CHAT TAB', a.type, a);
};
render() {
const { navigation } = this.props;
return <MyNavScreen banner="Chat Tab" navigation={navigation} />;
@@ -171,35 +131,4 @@ const SimpleTabs = TabNavigator(
}
);
type SimpleTabsContainerProps = {
navigation: NavigationScreenProp<*>,
};
class SimpleTabsContainer extends React.Component<SimpleTabsContainerProps> {
static router = SimpleTabs.router;
_s0: NavigationEventSubscription;
_s1: NavigationEventSubscription;
_s2: NavigationEventSubscription;
_s3: NavigationEventSubscription;
componentDidMount() {
this._s0 = this.props.navigation.addListener('willFocus', this._onAction);
this._s1 = this.props.navigation.addListener('didFocus', this._onAction);
this._s2 = this.props.navigation.addListener('willBlur', this._onAction);
this._s3 = this.props.navigation.addListener('didBlur', this._onAction);
}
componentWillUnmount() {
this._s0.remove();
this._s1.remove();
this._s2.remove();
this._s3.remove();
}
_onAction = a => {
console.log('TABS EVENT', a.type, a);
};
render() {
return <SimpleTabs navigation={this.props.navigation} />;
}
}
export default SimpleTabsContainer;
export default SimpleTabs;

View File

@@ -119,6 +119,9 @@ const StacksInTabs = TabNavigator(
tabBarPosition: 'bottom',
animationEnabled: false,
swipeEnabled: false,
tabBarOptions: {
showLabel: false,
},
}
);

View File

@@ -4,7 +4,12 @@
import React from 'react';
import { Button, SafeAreaView, Text } from 'react-native';
import { TabNavigator, withNavigationFocus } from 'react-navigation';
import {
TabNavigator,
TabBarTop,
StackNavigator,
withNavigationFocus,
} from 'react-navigation';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import SampleText from './SampleText';
@@ -92,10 +97,35 @@ const TabsWithNavigationFocus = TabNavigator(
},
},
{
tabBarPosition: 'bottom',
tabBarComponent: TabBarTop,
tabBarPosition: 'top',
animationEnabled: true,
swipeEnabled: true,
}
);
export default TabsWithNavigationFocus;
const Stack = StackNavigator(
{
TabsWithNavigationFocus,
},
{
navigationOptions: {
headerTitle: 'Navigation focus example',
headerLeft: null,
headerTitleStyle: {
flex: 1,
textAlign: 'left',
left: 0,
right: 0,
},
headerTintColor: '#fff',
headerStyle: {
backgroundColor: '#2196f3',
borderBottomWidth: 0,
elevation: 0,
},
},
}
);
export default Stack;

View File

@@ -11,9 +11,9 @@
"test": "node node_modules/jest/bin/jest.js && flow"
},
"dependencies": {
"expo": "^25.0.0",
"react": "16.2.0",
"react-native": "^0.52.0",
"expo": "^26.0.0",
"react": "16.3.0-alpha.1",
"react-native": "^0.54.0",
"react-native-iphone-x-helper": "^1.0.2",
"react-navigation": "link:../.."
},
@@ -22,9 +22,9 @@
"babel-plugin-transform-remove-console": "^6.9.0",
"flow-bin": "^0.61.0",
"jest": "^21.0.1",
"jest-expo": "^25.1.0",
"jest-expo": "^26.0.0",
"react-native-scripts": "^1.5.0",
"react-test-renderer": "16.0.0"
"react-test-renderer": "16.3.0-alpha.1"
},
"jest": {
"preset": "jest-expo",

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@
"react": "16.2.0",
"react-native": "^0.52.0",
"react-navigation": "link:../..",
"react-navigation-redux-helpers": "^1.0.0",
"react-navigation-redux-helpers": "^1.0.3",
"react-redux": "^5.0.6",
"redux": "^3.7.2"
},

View File

@@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { addNavigationHelpers, StackNavigator } from 'react-navigation';
import { initializeListeners } from 'react-navigation-redux-helpers';
import LoginScreen from '../components/LoginScreen';
import MainScreen from '../components/MainScreen';
@@ -20,6 +21,10 @@ class AppWithNavigationState extends React.Component {
nav: PropTypes.object.isRequired,
};
componentDidMount() {
initializeListeners('root', this.props.nav);
}
render() {
const { dispatch, nav } = this.props;
return (

View File

@@ -295,7 +295,6 @@ declare module 'react-navigation' {
} & NavigationScreenRouteConfig);
declare export type NavigationScreenRouteConfig =
| NavigationComponent
| {
screen: NavigationComponent,
}
@@ -361,6 +360,7 @@ declare module 'react-navigation' {
initialRouteParams?: NavigationParams,
paths?: NavigationPathsConfig,
navigationOptions?: NavigationScreenConfig<*>,
initialRouteKey?: string,
|};
declare export type NavigationStackViewConfig = {|
@@ -470,7 +470,7 @@ declare module 'react-navigation' {
type: EventType,
action: NavigationAction,
state: NavigationState,
lastState: NavigationState,
lastState: ?NavigationState,
};
declare export type NavigationEventCallback = (
@@ -553,7 +553,7 @@ declare module 'react-navigation' {
declare export type NavigationContainerProps<S: {}, O: {}> = $Shape<{
uriPrefix?: string | RegExp,
onNavigationStateChange?: (
onNavigationStateChange?: ?(
NavigationState,
NavigationState,
NavigationAction
@@ -724,7 +724,7 @@ declare module 'react-navigation' {
SET_PARAMS: 'Navigation/SET_PARAMS',
URI: 'Navigation/URI',
back: {
(payload: { key?: ?string }): NavigationBackAction,
(payload?: { key?: ?string }): NavigationBackAction,
toString: () => string,
},
init: {
@@ -925,12 +925,14 @@ declare module 'react-navigation' {
vertical?: _SafeAreaViewForceInsetValue,
horizontal?: _SafeAreaViewForceInsetValue,
},
children: React$Node,
children?: React$Node,
style?: AnimatedViewStyleProp,
};
declare export var SafeAreaView: React$ComponentType<_SafeAreaViewProps>;
declare export var Header: React$ComponentType<HeaderProps>;
declare export var Header: React$ComponentType<HeaderProps> & {
HEIGHT: number,
};
declare type _HeaderTitleProps = {
children: React$Node,
@@ -995,6 +997,8 @@ declare module 'react-navigation' {
itemsContainerStyle?: ViewStyleProp,
itemStyle?: ViewStyleProp,
labelStyle?: TextStyleProp,
activeLabelStyle?: TextStyleProp,
inactiveLabelStyle?: TextStyleProp,
iconContainerStyle?: ViewStyleProp,
drawerPosition: 'left' | 'right',
};
@@ -1075,7 +1079,7 @@ declare module 'react-navigation' {
declare export var TabBarBottom: React$ComponentType<_TabBarBottomProps>;
declare type _NavigationInjectedProps = {
navigation: NavigationScreenProp<NavigationState>,
navigation: NavigationScreenProp<NavigationStateRoute>,
};
declare export function withNavigation<T: {}>(
Component: React$ComponentType<T & _NavigationInjectedProps>

View File

@@ -1,6 +1,6 @@
{
"name": "react-navigation",
"version": "1.4.0",
"version": "1.5.9",
"description": "Routing and navigation for your React Native apps",
"main": "src/react-navigation.js",
"repository": {
@@ -32,9 +32,10 @@
"hoist-non-react-statics": "^2.2.0",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.5.10",
"react-lifecycles-compat": "^1.0.2",
"react-native-drawer-layout-polyfill": "^1.3.2",
"react-native-safe-area-view": "^0.7.0",
"react-native-tab-view": "^0.0.74"
"react-native-tab-view": "github:react-navigation/react-native-tab-view"
},
"devDependencies": {
"babel-cli": "^6.24.1",

View File

@@ -11,6 +11,7 @@ import NavigationActions from '../NavigationActions';
export default (routeConfigMap, stackConfig = {}) => {
const {
initialRouteKey,
initialRouteName,
initialRouteParams,
paths,
@@ -25,6 +26,7 @@ export default (routeConfigMap, stackConfig = {}) => {
} = stackConfig;
const stackRouterConfig = {
initialRouteKey,
initialRouteName,
initialRouteParams,
paths,
@@ -47,7 +49,7 @@ export default (routeConfigMap, stackConfig = {}) => {
onTransitionEnd={(lastTransition, transition) => {
const { state, dispatch } = props.navigation;
dispatch(NavigationActions.completeTransition({ key: state.key }));
onTransitionEnd && onTransitionEnd();
onTransitionEnd && onTransitionEnd(lastTransition, transition);
}}
/>
)

View File

@@ -224,6 +224,7 @@ exports[`DrawerNavigator renders successfully 1`] = `
"color": "#2196f3",
},
undefined,
undefined,
]
}
>

View File

@@ -137,9 +137,15 @@ exports[`TabNavigator renders successfully 1`] = `
>
<View
style={
Object {
"flexGrow": 1,
}
Array [
Object {
"height": 29,
},
false,
Object {
"flexGrow": 1,
},
]
}
>
<View
@@ -147,13 +153,12 @@ exports[`TabNavigator renders successfully 1`] = `
style={
Object {
"alignItems": "center",
"bottom": 0,
"alignSelf": "center",
"height": "100%",
"justifyContent": "center",
"left": 0,
"opacity": 1,
"position": "absolute",
"right": 0,
"top": 0,
"width": "100%",
}
}
/>
@@ -162,13 +167,12 @@ exports[`TabNavigator renders successfully 1`] = `
style={
Object {
"alignItems": "center",
"bottom": 0,
"alignSelf": "center",
"height": "100%",
"justifyContent": "center",
"left": 0,
"opacity": 0,
"position": "absolute",
"right": 0,
"top": 0,
"width": "100%",
}
}
/>

View File

@@ -92,11 +92,12 @@ export default (routeConfigs, stackConfig = {}) => {
...(action.params || {}),
...(initialRouteParams || {}),
};
const { initialRouteKey } = stackConfig;
route = {
...route,
...(params ? { params } : {}),
routeName: initialRouteName,
key: action.key || generateKey(),
key: action.key || (initialRouteKey || generateKey()),
};
return {
key: 'StackRouterRoot',

View File

@@ -576,6 +576,23 @@ describe('StackRouter', () => {
expect(state2.routes[1].routes[1].routes[1].routeName).toEqual('Corge');
});
test('Navigate to initial screen is possible', () => {
const TestRouter = StackRouter(
{
foo: { screen: () => <div /> },
bar: { screen: () => <div /> },
},
{ initialRouteKey: 'foo' }
);
const initState = TestRouter.getStateForAction(NavigationActions.init());
const pushedState = TestRouter.getStateForAction(
NavigationActions.navigate({ routeName: 'foo', key: 'foo' }),
initState
);
expect(pushedState.index).toEqual(0);
expect(pushedState.routes[0].routeName).toEqual('foo');
});
test('Navigate with key is idempotent', () => {
const TestRouter = StackRouter({
foo: { screen: () => <div /> },

View File

@@ -110,7 +110,7 @@ class CardStack extends React.Component {
}
_isRouteFocused = route => {
const { state } = this.props.navigation;
const { transitionProps: { navigation: { state } } } = this.props;
const focusedRoute = state.routes[state.index];
return route === focusedRoute;
};
@@ -129,7 +129,7 @@ class CardStack extends React.Component {
const screenNavigation = addNavigationHelpers({
dispatch: navigation.dispatch,
state: scene.route,
isFocused: this._isRouteFocused.bind(this, scene.route),
isFocused: () => this._isRouteFocused(scene.route),
addListener: this._childEventSubscribers[scene.route.key],
});
screenDetails = {

View File

@@ -21,6 +21,8 @@ const DrawerNavigatorItems = ({
itemsContainerStyle,
itemStyle,
labelStyle,
activeLabelStyle,
inactiveLabelStyle,
iconContainerStyle,
drawerPosition,
}) => (
@@ -34,6 +36,7 @@ const DrawerNavigatorItems = ({
const scene = { route, index, focused, tintColor: color };
const icon = renderIcon(scene);
const label = getLabel(scene);
const extraLabelStyle = focused ? activeLabelStyle : inactiveLabelStyle;
return (
<TouchableItem
key={route.key}
@@ -63,7 +66,9 @@ const DrawerNavigatorItems = ({
</View>
) : null}
{typeof label === 'string' ? (
<Text style={[styles.label, { color }, labelStyle]}>
<Text
style={[styles.label, { color }, labelStyle, extraLabelStyle]}
>
{label}
</Text>
) : (

View File

@@ -108,7 +108,7 @@ export default class DrawerView extends React.PureComponent {
this._screenNavigationProp = addNavigationHelpers({
dispatch: navigation.dispatch,
state: navigationState,
isFocused: this._isRouteFocused.bind(this, navigationState),
isFocused: () => this._isRouteFocused(navigationState),
addListener: this._childEventSubscribers[navigationState.key],
});
};

View File

@@ -1,40 +1,33 @@
import React from 'react';
import { Platform, StyleSheet, View } from 'react-native';
import PropTypes from 'prop-types';
import withLifecyclePolyfill from 'react-lifecycles-compat';
import SceneView from './SceneView';
const FAR_FAR_AWAY = 3000; // this should be big enough to move the whole view out of its container
export default class ResourceSavingSceneView extends React.PureComponent {
class ResourceSavingSceneView extends React.PureComponent {
constructor(props) {
super();
const key = props.childNavigation.state.key;
const focusedIndex = props.navigation.state.index;
const focusedKey = props.navigation.state.routes[focusedIndex].key;
const isFocused = key === focusedKey;
this.state = {
awake: props.lazy ? isFocused : true,
visible: isFocused,
awake: props.lazy ? props.isFocused : true,
};
}
componentWillMount() {
this._actionListener = this.props.navigation.addListener(
'action',
this._onAction
);
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.isFocused && !prevState.awake) {
return { awake: true };
}
componentWillUnmount() {
this._actionListener.remove();
return null;
}
render() {
const { awake, visible } = this.state;
const { awake } = this.state;
const {
isFocused,
childNavigation,
navigation,
removeClippedSubviews,
@@ -49,12 +42,12 @@ export default class ResourceSavingSceneView extends React.PureComponent {
removeClippedSubviews={
Platform.OS === 'android'
? removeClippedSubviews
: !visible && removeClippedSubviews
: !isFocused && removeClippedSubviews
}
>
<View
style={
this._mustAlwaysBeVisible() || visible
this._mustAlwaysBeVisible() || isFocused
? styles.innerAttached
: styles.innerDetached
}
@@ -68,33 +61,6 @@ export default class ResourceSavingSceneView extends React.PureComponent {
_mustAlwaysBeVisible = () => {
return this.props.animationEnabled || this.props.swipeEnabled;
};
_onAction = payload => {
// We do not care about transition complete events, they won't actually change the state
if (
payload.action.type == 'Navigation/COMPLETE_TRANSITION' ||
!payload.state
) {
return;
}
const { routes, index } = payload.state;
const key = this.props.childNavigation.state.key;
if (routes[index].key === key) {
if (!this.state.visible) {
let nextState = { visible: true };
if (!this.state.awake) {
nextState.awake = true;
}
this.setState(nextState);
}
} else {
if (this.state.visible) {
this.setState({ visible: false });
}
}
};
}
const styles = StyleSheet.create({
@@ -110,3 +76,5 @@ const styles = StyleSheet.create({
top: FAR_FAR_AWAY,
},
});
export default withLifecyclePolyfill(ResourceSavingSceneView);

View File

@@ -100,6 +100,9 @@ class TabBarBottom extends React.PureComponent {
if (showIcon === false) {
return null;
}
const horizontal = this._shouldUseHorizontalTabs();
return (
<TabBarIcon
position={position}
@@ -108,7 +111,11 @@ class TabBarBottom extends React.PureComponent {
inactiveTintColor={inactiveTintColor}
renderIcon={renderIcon}
scene={scene}
style={showLabel && this._shouldUseHorizontalTabs() ? {} : styles.icon}
style={[
styles.iconWithExplicitHeight,
showLabel === false && !horizontal && styles.iconWithoutLabel,
showLabel !== false && !horizontal && styles.iconWithLabel,
]}
/>
);
};
@@ -286,6 +293,9 @@ class TabBarBottom extends React.PureComponent {
}
}
const DEFAULT_HEIGHT = 49;
const COMPACT_HEIGHT = 29;
const styles = StyleSheet.create({
tabBar: {
backgroundColor: '#F7F7F7', // Default background color in iOS 10
@@ -294,10 +304,10 @@ const styles = StyleSheet.create({
flexDirection: 'row',
},
tabBarCompact: {
height: 29,
height: COMPACT_HEIGHT,
},
tabBarRegular: {
height: 49,
height: DEFAULT_HEIGHT,
},
tab: {
flex: 1,
@@ -311,9 +321,15 @@ const styles = StyleSheet.create({
justifyContent: 'center',
flexDirection: 'row',
},
icon: {
iconWithoutLabel: {
flex: 1,
},
iconWithLabel: {
flexGrow: 1,
},
iconWithExplicitHeight: {
height: Platform.isPad ? DEFAULT_HEIGHT : COMPACT_HEIGHT,
},
label: {
textAlign: 'center',
backgroundColor: 'transparent',

View File

@@ -23,6 +23,7 @@ export default class TabBarIcon extends React.PureComponent {
inputRange,
outputRange: inputRange.map(i => (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.
return (
@@ -54,11 +55,11 @@ const styles = StyleSheet.create({
// active and inactive one, so we can fade between them:
// Cover the whole iconContainer:
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
height: '100%',
width: '100%',
minWidth: 30,
},
});

View File

@@ -22,7 +22,10 @@ class TabView extends React.PureComponent {
};
_renderScene = ({ route }) => {
const { screenProps } = this.props;
const { screenProps, navigation } = this.props;
const focusedIndex = navigation.state.index;
const focusedKey = navigation.state.routes[focusedIndex].key;
const key = route.key;
const childNavigation = this.props.childNavigationProps[route.key];
const TabComponent = this.props.router.getComponentForRouteName(
route.routeName
@@ -31,6 +34,7 @@ class TabView extends React.PureComponent {
return (
<ResourceSavingSceneView
lazy={this.props.lazy}
isFocused={focusedKey === key}
removeClippedSubViews={this.props.removeClippedSubviews}
animationEnabled={this.props.animationEnabled}
swipeEnabled={this.props.swipeEnabled}

View File

@@ -83,9 +83,15 @@ exports[`TabBarBottom renders successfully 1`] = `
>
<View
style={
Object {
"flexGrow": 1,
}
Array [
Object {
"height": 29,
},
false,
Object {
"flexGrow": 1,
},
]
}
>
<View
@@ -93,13 +99,12 @@ exports[`TabBarBottom renders successfully 1`] = `
style={
Object {
"alignItems": "center",
"bottom": 0,
"alignSelf": "center",
"height": "100%",
"justifyContent": "center",
"left": 0,
"opacity": 1,
"position": "absolute",
"right": 0,
"top": 0,
"width": "100%",
}
}
/>
@@ -108,13 +113,12 @@ exports[`TabBarBottom renders successfully 1`] = `
style={
Object {
"alignItems": "center",
"bottom": 0,
"alignSelf": "center",
"height": "100%",
"justifyContent": "center",
"left": 0,
"opacity": 0,
"position": "absolute",
"right": 0,
"top": 0,
"width": "100%",
}
}
/>

View File

@@ -31,7 +31,7 @@ export default function withCachedChildNavigation(Comp) {
});
}
_isRouteFocused = route => () => {
_isRouteFocused = route => {
const { state } = this.props.navigation;
const focusedRoute = state.routes[state.index];
return route === focusedRoute;
@@ -58,7 +58,7 @@ export default function withCachedChildNavigation(Comp) {
this._childNavigationProps[route.key] = addNavigationHelpers({
dispatch: navigation.dispatch,
state: route,
isFocused: this._isRouteFocused.bind(this, route),
isFocused: () => this._isRouteFocused(route),
addListener: this._childEventSubscribers[route.key],
});
});

1180
yarn.lock

File diff suppressed because it is too large Load Diff