feat: improve types for options and support a function

This commit is contained in:
satyajit.happy
2019-07-22 12:21:25 +02:00
parent e1cf13e34d
commit 2b819e4310
9 changed files with 72 additions and 36 deletions

View File

@@ -173,7 +173,11 @@ And then we can use it:
```js
<Stack.Navigator initialRouteName="profile">
<Stack.Screen name="settings" component={Settings} />
<Stack.Screen name="profile" component={Profile} />
<Stack.Screen
name="profile"
component={Profile}
options={{ title: 'My profile' }}
/>
<Stack.Screen name="home" component={Home} />
</Stack.Navigator>
```

View File

@@ -28,6 +28,13 @@ type Action =
}
| { type: 'POP_TO_TOP' };
export type StackNavigationOptions = {
/**
* Title text for the screen.
*/
title?: string;
};
export type StackNavigationProp<
ParamList extends ParamListBase
> = NavigationProp<ParamList> & {
@@ -236,7 +243,10 @@ const StackRouter: Router<CommonAction | Action> = {
};
export function StackNavigator(props: Props) {
const { state, descriptors } = useNavigationBuilder(StackRouter, props);
const { state, descriptors } = useNavigationBuilder<StackNavigationOptions>(
StackRouter,
props
);
return (
<div style={{ position: 'relative' }}>
@@ -277,4 +287,6 @@ export function StackNavigator(props: Props) {
);
}
export default createNavigator(StackNavigator);
export default createNavigator<StackNavigationOptions, typeof StackNavigator>(
StackNavigator
);

View File

@@ -23,6 +23,13 @@ type Action = {
payload: { name?: string; key?: string; params?: object };
};
export type TabNavigationOptions = {
/**
* Title text for the screen.
*/
title?: string;
};
export type TabNavigationProp<ParamList extends ParamListBase> = NavigationProp<
ParamList
> & {
@@ -196,4 +203,6 @@ export function TabNavigator(props: Props) {
);
}
export default createNavigator(TabNavigator);
export default createNavigator<TabNavigationOptions, typeof TabNavigator>(
TabNavigator
);

View File

@@ -149,14 +149,14 @@ function App() {
<MyStack.Screen
name="first"
component={First}
options={{ title: 'Foo' }}
options={({ route }) => ({
title: `Foo (${route.params ? route.params.author : ''})`,
})}
initialParams={{ author: 'Jane' }}
/>
<MyStack.Screen
name="second"
component={Second}
options={{ title: 'Bar' }}
/>
<MyStack.Screen name="second" options={{ title: 'Bar' }}>
{props => <Second {...props} />}
</MyStack.Screen>
<MyStack.Screen name="third" options={{ title: 'Baz' }}>
{() => (
<MyTab.Navigator initialRouteName="fifth">

View File

@@ -19,8 +19,13 @@ type Props = {
setState: (state: NavigationState) => void;
};
export default function SceneView(props: Props) {
const { screen, route, navigation: helpers, getState, setState } = props;
export default function SceneView({
screen,
route,
navigation: helpers,
getState,
setState,
}: Props) {
const { performTransaction } = React.useContext(NavigationStateContext);
const navigation = React.useMemo(

View File

@@ -2,17 +2,19 @@ import * as React from 'react';
import { ParamListBase, RouteConfig, TypedNavigator } from './types';
import Screen from './Screen';
export default function createNavigator<N extends React.ComponentType<any>>(
RawNavigator: N
) {
export default function createNavigator<
Options extends object,
N extends React.ComponentType<any>
>(RawNavigator: N) {
return function Navigator<ParamList extends ParamListBase>(): TypedNavigator<
ParamList,
Options,
typeof RawNavigator
> {
return {
Navigator: RawNavigator,
Screen: Screen as React.ComponentType<
RouteConfig<ParamList, keyof ParamList>
RouteConfig<ParamList, keyof ParamList, Options>
>,
};
};

View File

@@ -232,7 +232,7 @@ export type CompositeNavigationProp<
(B extends NavigationProp<infer U> ? U : never)
>;
export type Descriptor = {
export type Descriptor<Options extends object> = {
/**
* Render the component associated with this route.
*/
@@ -244,18 +244,10 @@ export type Descriptor = {
options: Options;
};
export type Options = {
/**
* Title text for the screen.
*/
title?: string;
[key: string]: any;
};
export type RouteConfig<
ParamList extends ParamListBase = ParamListBase,
RouteName extends keyof ParamList = string
RouteName extends keyof ParamList = string,
Options extends object = object
> = {
/**
* Route name of this screen.
@@ -265,7 +257,12 @@ export type RouteConfig<
/**
* Navigator options for this screen.
*/
options?: Options;
options?:
| Options
| ((props: {
route: RouteProp<ParamList, RouteName>;
navigation: NavigationProp<ParamList>;
}) => Options);
/**
* Initial params object for the route.
@@ -287,6 +284,7 @@ export type RouteConfig<
export type TypedNavigator<
ParamList extends ParamListBase,
Options extends object,
Navigator extends React.ComponentType<any>
> = {
Navigator: React.ComponentType<
@@ -297,5 +295,5 @@ export type TypedNavigator<
initialRouteName?: keyof ParamList;
}
>;
Screen: React.ComponentType<RouteConfig<ParamList, keyof ParamList>>;
Screen: React.ComponentType<RouteConfig<ParamList, keyof ParamList, Options>>;
};

View File

@@ -25,9 +25,7 @@ type Options = {
onRouteFocus: (key: string) => void;
};
const EMPTY_OPTIONS = Object.freeze({});
export default function useDescriptors({
export default function useDescriptors<ScreenOptions extends object>({
state,
screens,
navigation,
@@ -73,10 +71,18 @@ export default function useDescriptors({
</NavigationBuilderContext.Provider>
);
},
options: screen.options || EMPTY_OPTIONS,
options: {
...(typeof screen.options === 'function'
? screen.options({
// @ts-ignore
route,
navigation,
})
: screen.options),
},
};
return acc;
},
{} as { [key: string]: Descriptor }
{} as { [key: string]: Descriptor<ScreenOptions> }
);
}

View File

@@ -39,7 +39,7 @@ const getRouteConfigsFromChildren = (children: React.ReactNode) =>
);
}, []);
export default function useNavigationBuilder(
export default function useNavigationBuilder<ScreenOptions extends object>(
router: Router<any>,
options: Options
) {
@@ -156,7 +156,7 @@ export default function useNavigationBuilder(
actionCreators: router.actionCreators,
});
const descriptors = useDescriptors({
const descriptors = useDescriptors<ScreenOptions>({
state,
screens,
navigation,