diff --git a/README.md b/README.md index 11bccaa8..5fcfd594 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,11 @@ And then we can use it: ```js - + ``` diff --git a/example/StackNavigator.tsx b/example/StackNavigator.tsx index 6466330a..ac1cacbe 100644 --- a/example/StackNavigator.tsx +++ b/example/StackNavigator.tsx @@ -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 & { @@ -236,7 +243,10 @@ const StackRouter: Router = { }; export function StackNavigator(props: Props) { - const { state, descriptors } = useNavigationBuilder(StackRouter, props); + const { state, descriptors } = useNavigationBuilder( + StackRouter, + props + ); return (
@@ -277,4 +287,6 @@ export function StackNavigator(props: Props) { ); } -export default createNavigator(StackNavigator); +export default createNavigator( + StackNavigator +); diff --git a/example/TabNavigator.tsx b/example/TabNavigator.tsx index f7afcefa..aaf6e673 100644 --- a/example/TabNavigator.tsx +++ b/example/TabNavigator.tsx @@ -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 = NavigationProp< ParamList > & { @@ -196,4 +203,6 @@ export function TabNavigator(props: Props) { ); } -export default createNavigator(TabNavigator); +export default createNavigator( + TabNavigator +); diff --git a/example/index.tsx b/example/index.tsx index 34f5dd62..1d5432af 100644 --- a/example/index.tsx +++ b/example/index.tsx @@ -149,14 +149,14 @@ function App() { ({ + title: `Foo (${route.params ? route.params.author : ''})`, + })} initialParams={{ author: 'Jane' }} /> - + + {props => } + {() => ( diff --git a/src/SceneView.tsx b/src/SceneView.tsx index f320ce29..01e29663 100644 --- a/src/SceneView.tsx +++ b/src/SceneView.tsx @@ -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( diff --git a/src/createNavigator.tsx b/src/createNavigator.tsx index 0276f47e..152a0d5e 100644 --- a/src/createNavigator.tsx +++ b/src/createNavigator.tsx @@ -2,17 +2,19 @@ import * as React from 'react'; import { ParamListBase, RouteConfig, TypedNavigator } from './types'; import Screen from './Screen'; -export default function createNavigator>( - RawNavigator: N -) { +export default function createNavigator< + Options extends object, + N extends React.ComponentType +>(RawNavigator: N) { return function Navigator(): TypedNavigator< ParamList, + Options, typeof RawNavigator > { return { Navigator: RawNavigator, Screen: Screen as React.ComponentType< - RouteConfig + RouteConfig >, }; }; diff --git a/src/types.tsx b/src/types.tsx index ee45155a..235526f2 100644 --- a/src/types.tsx +++ b/src/types.tsx @@ -232,7 +232,7 @@ export type CompositeNavigationProp< (B extends NavigationProp ? U : never) >; -export type Descriptor = { +export type Descriptor = { /** * 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; + navigation: NavigationProp; + }) => 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 > = { Navigator: React.ComponentType< @@ -297,5 +295,5 @@ export type TypedNavigator< initialRouteName?: keyof ParamList; } >; - Screen: React.ComponentType>; + Screen: React.ComponentType>; }; diff --git a/src/useDescriptors.tsx b/src/useDescriptors.tsx index d10fedc2..74fccd6e 100644 --- a/src/useDescriptors.tsx +++ b/src/useDescriptors.tsx @@ -25,9 +25,7 @@ type Options = { onRouteFocus: (key: string) => void; }; -const EMPTY_OPTIONS = Object.freeze({}); - -export default function useDescriptors({ +export default function useDescriptors({ state, screens, navigation, @@ -73,10 +71,18 @@ export default function useDescriptors({ ); }, - 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 } ); } diff --git a/src/useNavigationBuilder.tsx b/src/useNavigationBuilder.tsx index 2bbacb0e..8f6e89c0 100644 --- a/src/useNavigationBuilder.tsx +++ b/src/useNavigationBuilder.tsx @@ -39,7 +39,7 @@ const getRouteConfigsFromChildren = (children: React.ReactNode) => ); }, []); -export default function useNavigationBuilder( +export default function useNavigationBuilder( router: Router, options: Options ) { @@ -156,7 +156,7 @@ export default function useNavigationBuilder( actionCreators: router.actionCreators, }); - const descriptors = useDescriptors({ + const descriptors = useDescriptors({ state, screens, navigation,