Implement default navigationOptions (#1)

* Bring back 222 impl.

* Add it for TabNavigator

* Fix eslint issues and flow in the file

* First attempt at the docs

* Include docs

* Fix some typos
This commit is contained in:
Mike Grabowski
2017-01-27 12:33:03 +01:00
parent 0826d244ae
commit 983ef1dd03
7 changed files with 82 additions and 34 deletions

View File

@@ -72,6 +72,7 @@ Options for the router:
- `initialRouteName` - Sets the default screen of the stack. Must match one of the keys in route configs.
- `initialRouteParams` - The params for the initial route
- `navigationOptions` - Default navigation options to use for screens
- `paths` - A mapping of overrides for the paths set in the route configs
Visual options:

View File

@@ -32,7 +32,6 @@ class ProfileScreen extends React.Component {
...
```
#### Generic Navigation Options
The `title` navigation option is generic between every navigator. It is used to set the title string for a given screen.
@@ -47,6 +46,54 @@ class MyScreen extends React.Component {
Unlike the other nav options which are only utilized by the navigator view, the title option can be used by the environment to update the title in the browser window or app switcher.
#### Default Navigation Options
You can configure the default `navigationOptions` for all the screens within particular navigator to save you needing
to specify same properties all over the place.
```js
StackNavigator(routeConfig, {
navigationOptions: {
header: {
visible: false,
},
},
});
```
The above example will automatically hide navigation bar on all screens.
To override it on per-screen basis, you could define `navigationOptions` on a component itself:
```js
class ProfileScreen extends React.Component {
static navigationOptions = {
header: {
title: 'Profile Screen',
},
}
...
}
```
When `navigationOptions` are present on a component like in the above example, default settings are completely ignored.
**Extending defaults:** In order to extend default config with screen-specific properties instead of overriding it, you
could dynamically configure an option:
```js
class ProfileScreen extends React.Component {
static navigationOptions = {
header: (navigation, defaultHeader) => ({
...defaultHeader,
title: 'Profile Screen',
}),
}
...
}
```
The 2nd argument passed to the function is the default config as found on the navigator.
## Tab Navigation Options

View File

@@ -248,6 +248,7 @@ export type NavigationStackRouterConfig = {
initialRouteName?: string,
initialRouteParams?: NavigationParams,
paths?: NavigationPathsConfig,
navigationOptions?: NavigationScreenOptions,
};
export type NavigationStackAction =
@@ -292,8 +293,9 @@ export type NavigationPathsConfig = {
export type NavigationTabRouterConfig = {
initialRouteName?: string,
paths?: NavigationPathsConfig,
navigationOptions?: NavigationScreenOptions,
order?: Array<string>, // todo: type these as the real route names rather than 'string'
// Does the back button cause the router to switch to the initial tab
backBehavior?: 'none' | 'initialRoute', // defaults `initialRoute`
};

View File

@@ -27,11 +27,13 @@ export default (routeConfigMap: NavigationRouteConfigMap, stackConfig: StackNavi
headerComponent,
headerMode,
mode,
navigationOptions,
} = stackConfig;
const stackRouterConfig = {
initialRouteName,
initialRouteParams,
paths,
navigationOptions,
};
const router = StackRouter(routeConfigMap, stackRouterConfig);
return createNavigationContainer(createNavigator(router)(props => (

View File

@@ -288,7 +288,7 @@ export default (
};
},
getScreenConfig: createConfigGetter(routeConfigs),
getScreenConfig: createConfigGetter(routeConfigs, stackConfig.navigationOptions),
};
};

View File

@@ -242,6 +242,6 @@ export default (
}).find(action => !!action) || null;
},
getScreenConfig: createConfigGetter(routeConfigs),
getScreenConfig: createConfigGetter(routeConfigs, config.navigationOptions),
};
};

View File

@@ -12,12 +12,18 @@ import type {
NavigationRoute,
NavigationAction,
NavigationRouteConfigMap,
NavigationScreenConfig,
NavigationScreenOptions,
} from '../TypeDefinition';
export default (routeConfigs: NavigationRouteConfigMap) =>
(navigation: NavigationScreenProp<NavigationRoute, NavigationAction>, optionName: string, config?: Object) => {
export default (
routeConfigs: NavigationRouteConfigMap,
defaultOptions?: NavigationScreenOptions
) =>
(
navigation: NavigationScreenProp<NavigationRoute, NavigationAction>,
optionName: string,
config?: Object
) => {
const route = navigation.state;
invariant(
route.routeName &&
@@ -30,7 +36,7 @@ export default (routeConfigs: NavigationRouteConfigMap) =>
let outputConfig = config || null;
if (Component.router) {
const {state, dispatch} = navigation;
const { state, dispatch } = navigation;
invariant(
state && state.routes && state.index != null,
`Expect nav state to have routes and index, ${JSON.stringify(route)}`
@@ -44,29 +50,19 @@ export default (routeConfigs: NavigationRouteConfigMap) =>
const routeConfig = routeConfigs[route.routeName];
if (
Component &&
Component.navigationOptions &&
Component.navigationOptions[optionName] !== undefined
) {
if (typeof Component.navigationOptions[optionName] === 'function') {
outputConfig = Component.navigationOptions[optionName](navigation, outputConfig);
} else {
outputConfig = Component.navigationOptions[optionName];
}
}
if (
routeConfig &&
routeConfig.navigationOptions &&
routeConfig.navigationOptions[optionName] !== undefined
) {
if (typeof routeConfig.navigationOptions[optionName] === 'function') {
outputConfig = routeConfig.navigationOptions[optionName](navigation, outputConfig);
} else {
outputConfig = routeConfig.navigationOptions[optionName];
}
}
return outputConfig;
return [
defaultOptions,
Component.navigationOptions,
routeConfig.navigationOptions,
].reduce(
(acc: Object, options: NavigationScreenOptions) => {
if (options && options[optionName] !== undefined) {
return typeof options[optionName] === 'function'
? options[optionName](navigation, acc)
: options[optionName];
}
return acc;
},
outputConfig,
);
};