diff --git a/packages/react-navigation/docs/api/navigators/StackNavigator.md b/packages/react-navigation/docs/api/navigators/StackNavigator.md index ab302762..81800af0 100644 --- a/packages/react-navigation/docs/api/navigators/StackNavigator.md +++ b/packages/react-navigation/docs/api/navigators/StackNavigator.md @@ -96,9 +96,9 @@ Visual options: Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel` -#### `headerVisible` +#### `header` -True or false to show or hide the header. Only works when `headerMode` is `screen`. Default value is `true`. +React Element or a function that given `HeaderProps` returns a React Element, to display as a header. Setting to `null` hides header. #### `headerTitle` diff --git a/packages/react-navigation/docs/guides/Screen-Nav-Options.md b/packages/react-navigation/docs/guides/Screen-Nav-Options.md index 7c6f6b6e..3930a414 100644 --- a/packages/react-navigation/docs/guides/Screen-Nav-Options.md +++ b/packages/react-navigation/docs/guides/Screen-Nav-Options.md @@ -67,12 +67,10 @@ Your `TabNavigator` represents one of the screens in the app, and is nested with StackNavigator({ route1: { screen: RouteOne }, route2: { screen: MyTabNavigator }, -}, { - headerMode: 'screen', }); ``` -Now, when `route2` is active, you would like to hide the header. It's easy to hide the header for `route1`, and it should also be easy to do it for `route2`. This is what Default Navigation Options are for - they are simply `navigationOptions` set on a navigator: +Now, when `route2` is active, you would like to change the tint color of a header. It's easy to do it for `route1`, and it should also be easy to do it for `route2`. This is what Default Navigation Options are for - they are simply `navigationOptions` set on a navigator: ```js const MyTabNavigator = TabNavigator({ @@ -80,25 +78,22 @@ const MyTabNavigator = TabNavigator({ ... }, { navigationOptions: { - headerVisible: false, + headerTintColor: 'blue', }, }); ``` -Note that you can still decide to **also** specify the `navigationOptions` on the screens at the leaf level - e.g. the `ProfileScreen` above. The `navigationOptions` from the screen will be merged key-by-key with the default options coming from the navigator. Whenever both the navigator and screen define the same option (e.g. `headerVisible`), the screen wins. Therefore, you could make the header visible again when `ProfileScreen` is active. +Note that you can still decide to **also** specify the `navigationOptions` on the screens at the leaf level - e.g. the `ProfileScreen` above. The `navigationOptions` from the screen will be merged key-by-key with the default options coming from the navigator. Whenever both the navigator and screen define the same option (e.g. `headerTintColor`), the screen wins. Therefore, you could change the tint color when `ProfileScreen` is active by doing the following: ```js class ProfileScreen extends React.Component { static navigationOptions = { - headerVisible: true, + headerTintColor: 'black', }; ... } ``` -The 2nd argument passed to the function are the default values for the `header` as defined on the navigator. - - ## Navigation Option Reference List of available navigation options depends on the `navigator` the screen is added to. diff --git a/packages/react-navigation/src/TypeDefinition.js b/packages/react-navigation/src/TypeDefinition.js index e7200c10..680e2b81 100644 --- a/packages/react-navigation/src/TypeDefinition.js +++ b/packages/react-navigation/src/TypeDefinition.js @@ -207,7 +207,6 @@ export type NavigationUriAction = { export type NavigationStackViewConfig = { mode?: 'card' | 'modal', headerMode?: HeaderMode, - headerComponent?: ReactClass>, cardStyle?: Style, transitionConfig?: () => TransitionConfig, onTransitionStart?: () => void, @@ -215,6 +214,7 @@ export type NavigationStackViewConfig = { }; export type NavigationStackScreenOptions = NavigationScreenOptions & { + header?: ?(React.Element<*> | ((HeaderProps) => React.Element<*>)), headerTitle?: string | React.Element<*>, headerTitleStyle?: Style, headerTintColor?: string, @@ -224,7 +224,6 @@ export type NavigationStackScreenOptions = NavigationScreenOptions & { headerPressColorAndroid?: string, headerRight?: React.Element<*>, headerStyle?: Style, - headerVisible?: boolean, gesturesEnabled?: boolean, }; diff --git a/packages/react-navigation/src/navigators/StackNavigator.js b/packages/react-navigation/src/navigators/StackNavigator.js index 9ebffeea..5c546ade 100644 --- a/packages/react-navigation/src/navigators/StackNavigator.js +++ b/packages/react-navigation/src/navigators/StackNavigator.js @@ -26,7 +26,6 @@ export default ( initialRouteName, initialRouteParams, paths, - headerComponent, headerMode, mode, cardStyle, @@ -52,7 +51,6 @@ export default ( )((props: *) => ( { class HomeScreen extends Component { static navigationOptions = ({ navigation }: *) => ({ title: `Welcome ${navigation.state.params ? navigation.state.params.user : 'anonymous'}`, - headerVisible: true, + gesturesEnabled: true, }); render() { @@ -25,7 +25,7 @@ test('should get config for screen', () => { class SettingsScreen extends Component { static navigationOptions = { title: 'Settings!!!', - headerVisible: false, + gesturesEnabled: false, }; render() { @@ -36,7 +36,7 @@ test('should get config for screen', () => { class NotificationScreen extends Component { static navigationOptions = ({ navigation }: *) => ({ title: '42', - headerVisible: navigation.state.params + gesturesEnabled: navigation.state.params ? !navigation.state.params.fullscreen : true, }); @@ -83,7 +83,7 @@ test('should get config for screen', () => { getScreenOptions( addNavigationHelpers({ state: routes[0], dispatch: () => false }), {}, - ).headerVisible, + ).gesturesEnabled, ).toEqual(true); expect( getScreenOptions( @@ -95,7 +95,7 @@ test('should get config for screen', () => { getScreenOptions( addNavigationHelpers({ state: routes[2], dispatch: () => false }), {}, - ).headerVisible, + ).gesturesEnabled, ).toEqual(false); expect( getScreenOptions( @@ -107,13 +107,13 @@ test('should get config for screen', () => { getScreenOptions( addNavigationHelpers({ state: routes[3], dispatch: () => false }), {}, - ).headerVisible, + ).gesturesEnabled, ).toEqual(true); expect( getScreenOptions( addNavigationHelpers({ state: routes[4], dispatch: () => false }), {}, - ).headerVisible, + ).gesturesEnabled, ).toEqual(false); }); @@ -123,7 +123,7 @@ test('should throw if the route does not exist', () => { const HomeScreen = () => null; HomeScreen.navigationOptions = { title: 'Home screen', - headerVisible: true, + gesturesEnabled: true, }; const getScreenOptions = createConfigGetter({ diff --git a/packages/react-navigation/src/routers/validateScreenOptions.js b/packages/react-navigation/src/routers/validateScreenOptions.js index 8fc3b592..9eb00580 100644 --- a/packages/react-navigation/src/routers/validateScreenOptions.js +++ b/packages/react-navigation/src/routers/validateScreenOptions.js @@ -3,7 +3,7 @@ import invariant from 'fbjs/lib/invariant'; import type { NavigationRoute } from '../TypeDefinition'; -const deprecatedKeys = ['tabBar', 'header']; +const deprecatedKeys = ['tabBar']; /** * Make sure screen options returned by the `getScreenOption` diff --git a/packages/react-navigation/src/views/CardStack.js b/packages/react-navigation/src/views/CardStack.js index c20999aa..108aec5b 100644 --- a/packages/react-navigation/src/views/CardStack.js +++ b/packages/react-navigation/src/views/CardStack.js @@ -13,6 +13,7 @@ import { } from 'react-native'; import Card from './Card'; +import Header from './Header'; import NavigationActions from '../NavigationActions'; import addNavigationHelpers from '../addNavigationHelpers'; import SceneView from './SceneView'; @@ -163,14 +164,24 @@ class CardStack extends Component { scene: NavigationScene, headerMode: HeaderMode, ): ?React.Element<*> { - return ( - - ); + const { header } = this._getScreenDetails(scene).options; + + if (typeof header !== 'undefined' && typeof header !== 'function') { + return header; + } + + const renderHeader = header || ((props: *) =>
); + + // We need to explicitly exclude `mode` since Flow doesn't see + // mode: headerMode override below and reports prop mismatch + const { mode, ...passProps } = this.props; + + return renderHeader({ + ...passProps, + scene, + mode: headerMode, + getScreenDetails: this._getScreenDetails, + }); } // eslint-disable-next-line class-methods-use-this @@ -369,10 +380,6 @@ class CardStack extends Component { const { screenProps } = this.props; const headerMode = this._getHeaderMode(); if (headerMode === 'screen') { - const isHeaderHidden = options.headerVisible === false; - const maybeHeader = isHeaderHidden - ? null - : this._renderHeader(scene, headerMode); return ( @@ -383,7 +390,7 @@ class CardStack extends Component { navigationOptions={options} /> - {maybeHeader} + {this._renderHeader(scene, headerMode)} ); } diff --git a/packages/react-navigation/src/views/CardStackTransitioner.js b/packages/react-navigation/src/views/CardStackTransitioner.js index 2e19191f..4e0755d4 100644 --- a/packages/react-navigation/src/views/CardStackTransitioner.js +++ b/packages/react-navigation/src/views/CardStackTransitioner.js @@ -7,7 +7,6 @@ import CardStack from './CardStack'; import CardStackStyleInterpolator from './CardStackStyleInterpolator'; import Transitioner from './Transitioner'; import TransitionConfigs from './TransitionConfigs'; -import Header from './Header'; import type { NavigationAction, @@ -28,7 +27,6 @@ const NativeAnimatedModule = NativeModules && type Props = { screenProps?: {}, headerMode: HeaderMode, - headerComponent?: ReactClass<*>, mode: 'card' | 'modal', navigation: NavigationScreenProp, router: NavigationRouter, @@ -44,7 +42,6 @@ type Props = { type DefaultProps = { mode: 'card' | 'modal', - headerComponent: ReactClass<*>, }; class CardStackTransitioner extends Component { @@ -52,7 +49,6 @@ class CardStackTransitioner extends Component { static defaultProps: DefaultProps = { mode: 'card', - headerComponent: Header, }; render() { @@ -99,7 +95,6 @@ class CardStackTransitioner extends Component { _render = (props: NavigationTransitionProps): React.Element<*> => { const { screenProps, - headerComponent, headerMode, mode, router, @@ -110,7 +105,6 @@ class CardStackTransitioner extends Component { return (