diff --git a/types/react-navigation/index.d.ts b/types/react-navigation/index.d.ts index 8e743465c6..aead3c0ce6 100644 --- a/types/react-navigation/index.d.ts +++ b/types/react-navigation/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for react-navigation 2.13 +// Type definitions for react-navigation 3.0 // Project: https://github.com/react-navigation/react-navigation // Definitions by: Huhuanming // mhcgrq @@ -29,11 +29,12 @@ // Jason Killian // Jeroen Vervaeke // Fellipe Chagas +// Deniss Borisovs // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.8 /** - * Reference: https://github.com/react-navigation/react-navigation/tree/a37473c5e4833f48796ee6c7c9cb4a8ac49d9c06 + * Reference: https://github.com/react-navigation/react-navigation/tree/4fb6b163acc4e57bb9d0be169b90b07a7d9bf4a8 * * NOTE: Please update the commit/link above when updating to a new Flow * react-navigation/flow/react-navigation.js reference, so we can conveniently just look at diffs on @@ -416,7 +417,7 @@ export interface NavigationSwitchRouterConfig { initialRouteName?: string; initialRouteParams?: NavigationParams; paths?: NavigationPathsConfig; - navigationOptions?: NavigationScreenConfig; + defaultNavigationOptions?: NavigationScreenConfig; order?: string[]; backBehavior?: 'none' | 'initialRoute'; // defaults to `'none'` resetOnBlur?: boolean; // defaults to `true` @@ -456,6 +457,7 @@ export interface NavigationStackRouterConfig { initialRouteName?: string; initialRouteParams?: NavigationParams; paths?: NavigationPathsConfig; + defaultNavigationOptions?: NavigationScreenConfig; navigationOptions?: NavigationScreenConfig; initialRouteKey?: string; } @@ -519,10 +521,12 @@ interface NavigationTabRouterConfigBase { backBehavior?: 'none' | 'initialRoute'; // defaults `initialRoute` } export interface NavigationTabRouterConfig extends NavigationTabRouterConfigBase { - navigationOptions?: NavigationScreenConfig; + defaultNavigationOptions?: NavigationScreenConfig; + navigationOptions?: NavigationTabRouterConfigBase; } export interface NavigationBottomTabRouterConfig extends NavigationTabRouterConfigBase { - navigationOptions?: NavigationScreenConfig; + defaultNavigationOptions?: NavigationScreenConfig; + navigationOptions?: NavigationTabRouterConfigBase; } export interface TabScene { route: NavigationRoute; @@ -1250,6 +1254,16 @@ export function createNavigator( export function createNavigationContainer( Component: NavigationNavigator ): NavigationContainer; + +/** + * Create an app container to wrap the root navigator + * + * @see https://github.com/react-navigation/react-navigation-native/blob/098e2e52b349d37357109d5aee545fa74699d3d4/src/createAppContainer.js#L64 + */ +export function createAppContainer( + Component: NavigationNavigator +): NavigationContainer; + /** * END MANUAL DEFINITIONS OUTSIDE OF TYPEDEFINITION.JS */ diff --git a/types/react-navigation/react-navigation-tests.tsx b/types/react-navigation/react-navigation-tests.tsx index aaa69bc35b..3409bbd32d 100644 --- a/types/react-navigation/react-navigation-tests.tsx +++ b/types/react-navigation/react-navigation-tests.tsx @@ -6,6 +6,7 @@ import { ViewStyle, } from 'react-native'; import { + createAppContainer, createDrawerNavigator, createBottomTabNavigator, DrawerItems, @@ -174,7 +175,13 @@ export const AppNavigator = createStackNavigator( initialRouteKey: ROUTE_KEY_START_SCREEN, headerLayoutPreset: 'center', initialRouteParams, - navigationOptions, + defaultNavigationOptions: navigationOptions, + navigationOptions: { + headerTintColor: '#fff', + headerStyle: { + backgroundColor: '#000', + }, + } }, ); @@ -211,10 +218,13 @@ const tabNavigatorConfig: TabNavigatorConfig = { lazy: true, tabBarComponent: TabBarTop, tabBarOptions: { activeBackgroundColor: "blue" }, - navigationOptions: () => ({ + defaultNavigationOptions: () => ({ tabBarOnPress: ({ scene, jumpToIndex }) => jumpToIndex(scene.index), tabBarIcon: ({ horizontal }) => , - }) + }), + navigationOptions: { + backBehavior: 'none' + } }; const tabNavigatorConfigWithInitialLayout: TabNavigatorConfig = { @@ -224,7 +234,7 @@ const tabNavigatorConfigWithInitialLayout: TabNavigatorConfig = { const tabNavigatorConfigWithNavigationOptions: TabNavigatorConfig = { ...tabNavigatorConfig, - navigationOptions: { + defaultNavigationOptions: { tabBarOnPress: ({scene, jumpToIndex}) => { jumpToIndex(scene.index); }, @@ -259,7 +269,7 @@ const stackNavigatorScreenOptions: NavigationStackScreenOptions = { const stackNavigatorConfig: StackNavigatorConfig = { mode: "card", headerMode: "screen", - navigationOptions: stackNavigatorScreenOptions, + defaultNavigationOptions: stackNavigatorScreenOptions, }; const BasicStackNavigator = createStackNavigator( @@ -279,7 +289,7 @@ function renderBasicStackNavigator(): JSX.Element { const stackNavigatorConfigWithNavigationOptionsAsFunction: StackNavigatorConfig = { mode: "card", headerMode: "screen", - navigationOptions: ({navigationOptions, navigation, screenProps}) => (stackNavigatorScreenOptions), + defaultNavigationOptions: ({navigationOptions, navigation, screenProps}) => (stackNavigatorScreenOptions), }; const AdvancedStackNavigator = createStackNavigator( @@ -359,7 +369,7 @@ const drawerNavigatorConfig: DrawerNavigatorConfig = { const BasicDrawerNavigator = createDrawerNavigator( routeConfigMap, - stackNavigatorConfig, + drawerNavigatorConfig, ); const Drawer = (props: DrawerItemsProps) => ( @@ -527,7 +537,7 @@ const BottomStack = createBottomTabNavigator({ } } }, { - navigationOptions: () => ({ + defaultNavigationOptions: () => ({ tabBarOnPress: ({ defaultHandler }) => defaultHandler() }) }); @@ -537,7 +547,7 @@ const CustomHeaderStack = createStackNavigator({ Page2: { screen: Page2 } }, { - navigationOptions: { + defaultNavigationOptions: { header: headerProps => { const { scene } = headerProps; const { options } = scene.descriptor; @@ -658,6 +668,10 @@ createStackNavigator( {transitionConfig: () => ({screenInterpolator: StackViewTransitionConfigs.SlideFromRightIOS.screenInterpolator})} ); +// Test createAppContainer + +export const AppContainer = createAppContainer(AppNavigator); + // Test NavigationEvents component const ViewWithNavigationEvents = ( +// mhcgrq +// fangpenlin +// petejkim +// Kyle Roach +// phanalpha +// charlesfamu +// Tim Wang +// Qibang Sun +// Sergei Butko: +// Veit Lehmann: +// Steven Miller +// Armando Assuncao +// Ciaran Liedeman +// Jérémy Magrin +// Luca Campana +// Ullrich Schaefer +// Linus Unnebäck +// Yosuke Seki +// Jake +// Gustavo Brunoro +// Denis Frezzato +// Mickael Wegerich +// Max Davidson +// Alec Hill +// Lachlan Young +// Jason Killian +// Jeroen Vervaeke +// Fellipe Chagas +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 + +/** + * Reference: https://github.com/react-navigation/react-navigation/tree/a37473c5e4833f48796ee6c7c9cb4a8ac49d9c06 + * + * NOTE: Please update the commit/link above when updating to a new Flow + * react-navigation/flow/react-navigation.js reference, so we can conveniently just look at diffs on + * react-navigation/flow/react-navigation.js between this latest reference point and the one you are + * using when making new updates. + */ + +import * as React from 'react'; +import { + Animated, + TextStyle, + ViewProps, + ViewStyle, + StyleProp, +} from 'react-native'; + +// @todo when we split types into common, native and web, +// we can properly change Animated.Value to its real value +export type AnimatedValue = any; + +export type HeaderMode = 'float' | 'screen' | 'none'; + +export interface HeaderForceInset { + horizontal?: string; + vertical?: string; + left?: string; + right?: string; + top?: string; + bottom?: string; +} + +export interface HeaderProps extends NavigationSceneRendererProps { + mode: HeaderMode; + router: NavigationRouter; + getScreenDetails: ( + navigationScene: NavigationScene + ) => NavigationScreenDetails; + leftInterpolator: (props: NavigationSceneRendererProps) => {}; + titleInterpolator: (props: NavigationSceneRendererProps) => {}; + rightInterpolator: (props: NavigationSceneRendererProps) => {}; + style: StyleProp; +} + +/** + * NavigationState is a tree of routes for a single navigator, where each child + * route may either be a NavigationScreenRoute or a NavigationRouterRoute. + * NavigationScreenRoute represents a leaf screen, while the + * NavigationRouterRoute represents the state of a child navigator. + * + * NOTE: NavigationState is a state tree local to a single navigator and + * its child navigators (via the routes field). + * If we're in navigator nested deep inside the app, the state will only be the + * state for that navigator. + * The state for the root navigator of our app represents the whole navigation + * state for the whole app. + */ +export interface NavigationState { + /** + * Index refers to the active child route in the routes array. + */ + index: number; + routes: NavigationRoute[]; + isTransitioning: boolean; + key: string; + params: NavigationParams; +} + +export interface DrawerNavigationState extends NavigationState { + isDrawerOpen: boolean; + isTransitioning: boolean; +} + +export type NavigationRoute = + | NavigationLeafRoute + | NavigationStateRoute; + +export interface NavigationLeafRoute { + /** + * React's key used by some navigators. No need to specify these manually, + * they will be defined by the router. + */ + key: string; + /** + * Index that represents the depth of the stack + */ + index: number; + /** + * For example 'Home'. + * This is used as a key in a route config when creating a navigator. + */ + routeName: string; + /** + * Path is an advanced feature used for deep linking and on the web. + */ + path?: string; + /** + * Params passed to this route when navigating to it, + * e.g. `{ car_id: 123 }` in a route that displays a car. + */ + params?: Params; + /** + * Array containing the navigator's routes + */ + routes: NavigationRoute[]; + /** + * Flag that indicates the transition state of the route + */ + isTransitioning: boolean; +} + +export type NavigationStateRoute< + NavigationLeafRouteParams + > = NavigationLeafRoute & NavigationState; + +export type NavigationScreenOptionsGetter = ( + navigation: NavigationScreenProp>, + screenProps?: { [key: string]: any } +) => Options; + +export interface NavigationRouter { + /** + * The reducer that outputs the new navigation state for a given action, with + * an optional previous state. When the action is considered handled but the + * state is unchanged, the output state is null. + */ + getStateForAction: ( + action: NavigationAction, + lastState?: State + ) => State | null; + + /** + * Maps a URI-like string to an action. This can be mapped to a state + * using `getStateForAction`. + */ + getActionForPathAndParams: ( + path: string, + params?: NavigationParams + ) => NavigationAction | null; + + getPathAndParamsForState: ( + state: State + ) => { + path: string; + params?: NavigationParams; + }; + + getComponentForRouteName: (routeName: string) => NavigationComponent; + + getComponentForState: (state: State) => NavigationComponent; + + /** + * Gets the screen navigation options for a given screen. + * + * For example, we could get the config for the 'Foo' screen when the + * `navigation.state` is: + * + * {routeName: 'Foo', key: '123'} + */ + getScreenOptions: NavigationScreenOptionsGetter; +} + +export type NavigationScreenOption = + | T + | ((navigation: NavigationScreenProp, config: T) => T); + +export interface NavigationScreenDetails { + options: T; + state: NavigationRoute; + navigation: NavigationScreenProp; +} + +export type NavigationScreenOptions = NavigationStackScreenOptions & + NavigationTabScreenOptions & + NavigationDrawerScreenOptions; + +export interface NavigationScreenConfigProps { + navigation: NavigationScreenProp; + screenProps: { [key: string]: any }; +} + +export type NavigationScreenConfig = + | Options + | (( + navigationOptionsContainer: NavigationScreenConfigProps & { + navigationOptions: NavigationScreenProp; + } + ) => Options); + +export type NavigationComponent = + | NavigationScreenComponent + | NavigationNavigator + | any; + +export type NavigationScreenComponent< + Params = NavigationParams, + Options = {}, + Props = {} + > = React.ComponentType & Props> & { + navigationOptions?: NavigationScreenConfig; + }; + +export type NavigationNavigator< + State = NavigationState, + Options = {}, + Props = {} + > = React.ComponentType & Props> & { + router: NavigationRouter; + navigationOptions?: NavigationScreenConfig; + }; + +export interface NavigationParams { + [key: string]: any; +} + +export interface NavigationNavigateActionPayload { + routeName: string; + params?: NavigationParams; + + // The action to run inside the sub-router + action?: NavigationNavigateAction; + + key?: string; +} + +export interface NavigationNavigateAction + extends NavigationNavigateActionPayload { + type: 'Navigation/NAVIGATE'; +} + +export interface NavigationBackActionPayload { + key?: string | null; +} + +export interface NavigationBackAction extends NavigationBackActionPayload { + type: 'Navigation/BACK'; +} + +export interface NavigationSetParamsActionPayload { + // The key of the route where the params should be set + key: string; + + // The new params to merge into the existing route params + params?: NavigationParams; +} + +export interface NavigationSetParamsAction + extends NavigationSetParamsActionPayload { + type: 'Navigation/SET_PARAMS'; +} + +export interface NavigationInitActionPayload { + params?: NavigationParams; +} + +export interface NavigationInitAction extends NavigationInitActionPayload { + type: 'Navigation/INIT'; +} + +export interface NavigationReplaceActionPayload { + key?: string; + newKey?: string; + routeName: string; + params?: NavigationParams; + action?: NavigationNavigateAction; +} + +export interface NavigationReplaceAction { + type: 'Navigation/REPLACE'; + key: string; + routeName: string; + params?: NavigationParams; + action?: NavigationNavigateAction; +} + +export interface NavigationCompleteTransitionActionPayload { + key?: string; +} + +export interface NavigationCompleteTransitionAction { + type: 'Navigation/COMPLETE_TRANSITION'; + key: string; +} + +export interface NavigationResetActionPayload { + index: number; + key?: string | null; + actions: NavigationNavigateAction[]; +} + +export interface NavigationResetAction extends NavigationResetActionPayload { + type: 'Navigation/RESET'; +} + +export interface NavigationUriActionPayload { + uri: string; +} + +export interface NavigationUriAction extends NavigationUriActionPayload { + type: 'Navigation/URI'; +} + +export interface NavigationPopActionPayload { + // n: the number of routes to pop of the stack + n?: number; + immediate?: boolean; +} + +export interface NavigationPopAction extends NavigationPopActionPayload { + type: 'Navigation/POP'; +} + +export interface NavigationPopToTopActionPayload { + key?: string; + immediate?: boolean; +} + +export interface NavigationPopToTopAction + extends NavigationPopToTopActionPayload { + type: 'Navigation/POP_TO_TOP'; +} + +export interface NavigationPushActionPayload { + routeName: string; + params?: NavigationParams; + action?: NavigationNavigateAction; + key?: string; +} + +export interface NavigationPushAction { + type: 'Navigation/PUSH'; + routeName: string; + params?: NavigationParams; + action?: NavigationNavigateAction; + key?: string; +} + +export interface NavigationOpenDrawerAction { + key?: string; + type: 'Navigation/OPEN_DRAWER'; +} + +export interface NavigationCloseDrawerAction { + key?: string; + type: 'Navigation/CLOSE_DRAWER'; +} + +export interface NavigationToggleDrawerAction { + key?: string; + type: 'Navigation/TOGGLE_DRAWER'; +} + +export interface NavigationStackViewConfig { + mode?: 'card' | 'modal'; + headerMode?: HeaderMode; + headerBackTitleVisible?: boolean; + headerTransitionPreset?: 'fade-in-place' | 'uikit'; + headerLayoutPreset?: 'left' | 'center'; + cardStyle?: StyleProp; + transparentCard?: boolean; + transitionConfig?: ( + transitionProps: NavigationTransitionProps, + prevTransitionProps: NavigationTransitionProps, + isModal: boolean + ) => TransitionConfig; + onTransitionStart?: ( + transitionProps: NavigationTransitionProps, + prevTransitionProps?: NavigationTransitionProps + ) => Promise | void; + onTransitionEnd?: ( + transitionProps: NavigationTransitionProps, + prevTransitionProps?: NavigationTransitionProps + ) => void; +} + +/** + * Switch Navigator + */ + +export interface NavigationSwitchRouterConfig { + initialRouteName?: string; + initialRouteParams?: NavigationParams; + paths?: NavigationPathsConfig; + navigationOptions?: NavigationScreenConfig; + order?: string[]; + backBehavior?: 'none' | 'initialRoute'; // defaults to `'none'` + resetOnBlur?: boolean; // defaults to `true` +} + +export interface NavigationStackScreenOptions { + title?: string; + header?: + | React.ReactElement + | ((headerProps: HeaderProps) => React.ReactElement) + | null; + headerTransparent?: boolean; + headerTitle?: string | React.ReactElement; + headerTitleStyle?: StyleProp; + headerTitleAllowFontScaling?: boolean; + headerTintColor?: string; + headerLeft?: + | React.ReactElement + | ((backButtonProps: HeaderBackButtonProps) => React.ReactElement) + | null; + headerBackTitle?: string | null; + headerBackImage?: React.ReactElement; + headerTruncatedBackTitle?: string; + headerBackTitleStyle?: StyleProp; + headerPressColorAndroid?: string; + headerRight?: React.ReactElement | null; + headerStyle?: StyleProp; + headerForceInset?: HeaderForceInset; + headerBackground?: React.ReactNode | React.ReactType; + gesturesEnabled?: boolean; + gestureResponseDistance?: { vertical?: number; horizontal?: number }; + gestureDirection?: 'default' | 'inverted'; +} + +export interface NavigationStackRouterConfig { + headerTransitionPreset?: 'fade-in-place' | 'uikit'; + initialRouteName?: string; + initialRouteParams?: NavigationParams; + paths?: NavigationPathsConfig; + navigationOptions?: NavigationScreenConfig; + initialRouteKey?: string; +} + +export type NavigationStackAction = + | NavigationInitAction + | NavigationNavigateAction + | NavigationBackAction + | NavigationSetParamsAction + | NavigationResetAction + | NavigationReplaceAction + | NavigationPopAction + | NavigationPushAction + | NavigationPopToTopAction + | NavigationCompleteTransitionAction; + +export type NavigationTabAction = + | NavigationInitAction + | NavigationNavigateAction + | NavigationBackAction; + +export type NavigationDrawerAction = + | NavigationOpenDrawerAction + | NavigationCloseDrawerAction + | NavigationToggleDrawerAction; + +export type NavigationAction = + | NavigationInitAction + | NavigationStackAction + | NavigationTabAction + | NavigationDrawerAction; + +export type NavigationRouteConfig = + | NavigationComponent + | ({ + navigationOptions?: NavigationScreenConfig; + path?: string; + } & NavigationScreenRouteConfig); + +export type NavigationScreenRouteConfig = + | NavigationComponent + | { + screen: NavigationComponent; + } + | { + getScreen: () => NavigationComponent; + }; + +export interface NavigationPathsConfig { + [routeName: string]: string; +} + +// tslint:disable-next-line:strict-export-declare-modifiers +interface NavigationTabRouterConfigBase { + initialRouteName?: string; + initialRouteParams?: NavigationParams; + paths?: NavigationPathsConfig; + order?: 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` +} +export interface NavigationTabRouterConfig extends NavigationTabRouterConfigBase { + navigationOptions?: NavigationScreenConfig; +} +export interface NavigationBottomTabRouterConfig extends NavigationTabRouterConfigBase { + navigationOptions?: NavigationScreenConfig; +} +export interface TabScene { + route: NavigationRoute; + focused: boolean; + index: number; + tintColor?: string; +} +// tslint:disable-next-line:strict-export-declare-modifiers +interface NavigationTabScreenOptionsBase { + title?: string; + tabBarIcon?: + | React.ReactElement + | (( + options: { tintColor: string | null; focused: boolean; horizontal: boolean } + ) => React.ReactElement | null); + tabBarLabel?: + | string + | React.ReactElement + | (( + options: { tintColor: string | null; focused: boolean } + ) => React.ReactElement | string | null); + tabBarVisible?: boolean; + tabBarTestIDProps?: { testID?: string; accessibilityLabel?: string }; +} +export interface NavigationTabScreenOptions + extends NavigationTabScreenOptionsBase { + swipeEnabled?: boolean; + tabBarOnPress?: ( + options: { + previousScene: TabScene; + scene: TabScene; + jumpToIndex: (index: number) => void; + } + ) => void; +} +export interface NavigationBottomTabScreenOptions + extends NavigationTabScreenOptionsBase { + tabBarOnPress?: ( + options: { + navigation: NavigationScreenProp; + defaultHandler: () => void; + } + ) => void; +} + +export type DrawerLockMode = 'unlocked' | 'locked-closed' | 'locked-open'; + +export interface NavigationDrawerScreenOptions { + title?: string; + drawerIcon?: + | React.ReactElement + | (( + options: { tintColor: string | null; focused: boolean } + ) => React.ReactElement | null); + drawerLabel?: + | string + | React.ReactElement + | (( + options: { tintColor: string | null; focused: boolean } + ) => React.ReactElement | null); + drawerLockMode?: DrawerLockMode; +} + +export interface NavigationRouteConfigMap { + [routeName: string]: NavigationRouteConfig; +} + +export type NavigationDispatch = (action: NavigationAction) => boolean; + +export interface NavigationProp { + state: S; + dispatch: NavigationDispatch; +} + +export type EventType = + | 'willFocus' + | 'didFocus' + | 'willBlur' + | 'didBlur' + | 'action'; + +export interface NavigationEventPayload { + type: EventType; + action: NavigationAction; + state: NavigationState; + lastState: NavigationState | null | undefined; +} + +export type NavigationEventCallback = (payload: NavigationEventPayload) => void; + +export interface NavigationEventSubscription { + remove: () => void; +} + +export interface NavigationEventsProps extends ViewProps { + navigation?: NavigationNavigator; + onWillFocus?: NavigationEventCallback; + onDidFocus?: NavigationEventCallback; + onWillBlur?: NavigationEventCallback; + onDidBlur?: NavigationEventCallback; +} + +export const NavigationEvents: React.ComponentType; + +export interface NavigationScreenProp { + state: S & { params?: P }; + dispatch: NavigationDispatch; + goBack: (routeKey?: string | null) => boolean; + dismiss: () => boolean; + navigate(options: { + routeName: string | { + routeName: string; + params?: NavigationParams; + action?: NavigationNavigateAction; + key?: string; + }; + params?: NavigationParams; + action?: NavigationAction; + key?: string; + }): boolean; + navigate( + routeNameOrOptions: string, + params?: NavigationParams, + action?: NavigationAction + ): boolean; + openDrawer: () => any; + closeDrawer: () => any; + toggleDrawer: () => any; + getParam(param: T, fallback: NonNullable): NonNullable; + getParam(param: T): P[T]; + setParams: (newParams: Partial

) => boolean; + addListener: ( + eventName: 'willBlur' | 'willFocus' | 'didFocus' | 'didBlur', + callback: NavigationEventCallback + ) => NavigationEventSubscription; + push: ( + routeName: string, + params?: NavigationParams, + action?: NavigationNavigateAction + ) => boolean; + replace: ( + routeName: string, + params?: NavigationParams, + action?: NavigationNavigateAction + ) => boolean; + pop: (n?: number, params?: { immediate?: boolean }) => boolean; + popToTop: (params?: { immediate?: boolean }) => boolean; + isFocused: () => boolean; + router?: NavigationRouter; + dangerouslyGetParent: () => NavigationScreenProp | undefined; +} + +export interface NavigationNavigatorProps { + detached?: boolean; + navigation?: NavigationProp; + screenProps?: { [key: string]: any }; + navigationOptions?: O; +} + +/** + * Gestures, Animations, and Interpolators + */ + +export type NavigationGestureDirection = 'horizontal' | 'vertical'; + +export interface NavigationLayout { + height: AnimatedValue; + initHeight: number; + initWidth: number; + isMeasured: boolean; + width: AnimatedValue; +} + +export interface NavigationScene { + index: number; + isActive: boolean; + isStale: boolean; + key: string; + route: NavigationRoute; + descriptor: NavigationDescriptor; +} + +export interface NavigationTransitionProps { + // The layout of the screen container + layout: NavigationLayout; + + // The destination navigation state of the transition + navigation: NavigationScreenProp; + + // The progressive index of the transitioner's navigation state. + position: AnimatedValue; + + // The value that represents the progress of the transition when navigation + // state changes from one to another. Its numberic value will range from 0 + // to 1. + // progress.__getAnimatedValue() < 1 : transtion is happening. + // progress.__getAnimatedValue() == 1 : transtion completes. + progress: AnimatedValue; + + // All the scenes of the transitioner. + scenes: NavigationScene[]; + + // The active scene, corresponding to the route at + // `navigation.state.routes[navigation.state.index]`. When rendering + // NavigationSceneRendererPropsIndex, the scene does not refer to the active + // scene, but instead the scene that is being rendered. The index always + // is the index of the scene + scene: NavigationScene; + index: number; + + screenProps?: { [key: string]: any }; +} + +// The scene renderer props are nearly identical to the props used for rendering +// a transition. The exception is that the passed scene is not the active scene +// but is instead the scene that the renderer should render content for. +export type NavigationSceneRendererProps = NavigationTransitionProps; + +export interface NavigationTransitionSpec { + duration?: number; + // An easing function from `Easing`. + easing?: (t: number) => number; + // A timing function such as `Animated.timing`. + timing?: (value: AnimatedValue, config: any) => any; + friction?: number; + tension?: number; + useNativeDriver?: boolean; +} + +/** + * Describes a visual transition from one screen to another. + */ +export interface TransitionConfig { + // The basics properties of the animation, such as duration and easing + transitionSpec?: NavigationTransitionSpec; + // How to animate position and opacity of the screen + // based on the value generated by the transitionSpec + screenInterpolator?: (props: NavigationSceneRendererProps) => any; + // How to animate position and opacity of the header componetns + // based on the value generated by the transitionSpec + headerLeftInterpolator?: (props: NavigationSceneRendererProps) => any; + headerTitleInterpolator?: (props: NavigationSceneRendererProps) => any; + headerRightInterpolator?: (props: NavigationSceneRendererProps) => any; + // The style of the container. Useful when a scene doesn't have + // 100% opacity and the underlying container is visible. + containerStyle?: StyleProp; +} + +export type TransitionConfigurer = ( + transitionProps: NavigationTransitionProps, + prevTransitionProps: NavigationTransitionProps, + isModal: boolean +) => TransitionConfig; + +export interface StackViewTransitionConfigsType { + defaultTransitionConfig: TransitionConfigurer; + getTransitionConfig: ( + transitionConfigurer: TransitionConfigurer, + transitionProps: NavigationTransitionProps, + prevTransitionProps: NavigationTransitionProps, + isModal: boolean + ) => TransitionConfig; + SlideFromRightIOS: TransitionConfig; + ModalSlideFromBottomIOS: TransitionConfig; + FadeInFromBottomAndroid: TransitionConfig; + FadeOutToBottomAndroid: TransitionConfig; +} + +export const StackViewTransitionConfigs: StackViewTransitionConfigsType; + +export type NavigationAnimationSetter = ( + position: AnimatedValue, + newState: NavigationState, + lastState: NavigationState +) => void; + +export type NavigationSceneRenderer = () => React.ReactElement | null; + +export type NavigationStyleInterpolator = ( + props: NavigationSceneRendererProps +) => ViewStyle; + +export interface LayoutEvent { + nativeEvent: { + layout: { + x: number; + y: number; + width: number; + height: number; + }; + }; +} + +export type NavigatorType = + | 'react-navigation/STACK' + | 'react-navigation/TABS' + | 'react-navigation/DRAWER'; + +export interface NavigationContainerProps { + uriPrefix?: string | RegExp; + onNavigationStateChange?: ( + prevNavigationState: NavigationState, + nextNavigationState: NavigationState, + action: NavigationAction + ) => void | null | undefined; + navigation?: NavigationScreenProp; + persistenceKey?: string | null; + renderLoadingExperimental?: React.ComponentType; + screenProps?: any; + navigationOptions?: O; + style?: StyleProp; +} + +export interface NavigationContainerComponent + extends React.Component< + NavigationContainerProps & NavigationNavigatorProps + > { + dispatch: NavigationDispatch; +} + +export interface NavigationContainer + extends React.ComponentClass< + NavigationContainerProps & NavigationNavigatorProps + > { + new( + props: NavigationContainerProps & NavigationNavigatorProps, + context?: any + ): NavigationContainerComponent; + + router: NavigationRouter; + screenProps: { [key: string]: any }; + navigationOptions: any; + state: { nav: NavigationState | null }; +} + +export interface StackNavigatorConfig + extends NavigationStackViewConfig, + NavigationStackRouterConfig { + containerOptions?: any; +} + +// Return createNavigationContainer +export function StackNavigator( + routeConfigMap: NavigationRouteConfigMap, + stackConfig?: StackNavigatorConfig +): NavigationContainer; + +export function createStackNavigator( + routeConfigMap: NavigationRouteConfigMap, + stackConfig?: StackNavigatorConfig +): NavigationContainer; + +export interface SwitchNavigatorConfig { + initialRouteName: string; + resetOnBlur?: boolean; + paths?: NavigationPathsConfig; + backBehavior?: 'none' | 'initialRoute'; +} + +// Return createNavigationContainer +export type _SwitchNavigatorConfig = NavigationSwitchRouterConfig; + +export function SwitchNavigator( + routeConfigMap: NavigationRouteConfigMap, + switchConfig?: SwitchNavigatorConfig +): NavigationContainer; + +export function createSwitchNavigator( + routeConfigMap: NavigationRouteConfigMap, + switchConfig?: SwitchNavigatorConfig +): NavigationContainer; + +// DrawerItems +export const DrawerItems: React.ComponentType; + +export interface DrawerItemsProps { + navigation: NavigationScreenProp; + items: NavigationRoute[]; + activeItemKey?: string; + activeTintColor?: string; + activeBackgroundColor?: string; + inactiveTintColor?: string; + inactiveBackgroundColor?: string; + getLabel: (scene: DrawerScene) => React.ReactNode | string; + renderIcon: (scene: DrawerScene) => React.ReactNode; + onItemPress: (info: DrawerItem) => void; + itemsContainerStyle?: StyleProp; + itemStyle?: StyleProp; + labelStyle?: StyleProp; + activeLabelStyle?: StyleProp; + inactiveLabelStyle?: StyleProp; + iconContainerStyle?: StyleProp; + drawerPosition: 'left' | 'right'; +} +export interface DrawerScene { + route: NavigationRoute; + focused: boolean; + index: number; + tintColor?: string; +} +export interface DrawerItem { + route: NavigationRoute; + focused: boolean; +} + +/** + * Drawer Navigator + */ +export interface DrawerViewConfig { + drawerBackgroundColor?: string; + drawerWidth?: number; + drawerPosition?: 'left' | 'right'; + contentComponent?: React.ComponentType; + contentOptions?: any; + style?: StyleProp; +} +export interface DrawerNavigatorConfig + extends NavigationTabRouterConfig, + DrawerViewConfig { + containerConfig?: any; + contentOptions?: { + activeTintColor?: string; + activeBackgroundColor?: string; + inactiveTintColor?: string; + inactiveBackgroundColor?: string; + style?: StyleProp; + labelStyle?: StyleProp; + }; + drawerLockMode?: DrawerLockMode; +} + +export function DrawerNavigator( + routeConfigMap: NavigationRouteConfigMap, + drawerConfig?: DrawerNavigatorConfig +): NavigationContainer; + +export function createDrawerNavigator( + routeConfigMap: NavigationRouteConfigMap, + drawerConfig?: DrawerNavigatorConfig +): NavigationContainer; + +/** + * Tab Navigator + */ + +// From views/TabView/TabView.js +export interface TabViewConfig { + tabBarComponent?: React.ReactType; + tabBarPosition?: 'top' | 'bottom'; + tabBarOptions?: { + activeTintColor?: string; + allowFontScaling?: boolean; + activeBackgroundColor?: string; + inactiveTintColor?: string; + inactiveBackgroundColor?: string; + showLabel?: boolean; + style?: StyleProp; + labelStyle?: StyleProp; + iconStyle?: StyleProp; + // Top + showIcon?: boolean; + upperCaseLabel?: boolean; + pressColor?: string; + pressOpacity?: number; + scrollEnabled?: boolean; + tabStyle?: StyleProp; + indicatorStyle?: StyleProp; + }; + swipeEnabled?: boolean; + animationEnabled?: boolean; + lazy?: boolean; +} + +// From navigators/TabNavigator.js +export interface TabNavigatorConfig + extends NavigationTabRouterConfig, + TabViewConfig { + lazy?: boolean; + removeClippedSubviews?: boolean; + initialLayout?: { height: number; width: number }; +} +export interface BottomTabNavigatorConfig + extends NavigationBottomTabRouterConfig, + TabViewConfig { + lazy?: boolean; + removeClippedSubviews?: boolean; + initialLayout?: { height: number; width: number }; +} + +// From navigators/TabNavigator.js +export function TabNavigator( + routeConfigMap: NavigationRouteConfigMap, + drawConfig?: TabNavigatorConfig +): NavigationContainer; + +export function createTabNavigator( + routeConfigMap: NavigationRouteConfigMap, + drawConfig?: TabNavigatorConfig +): NavigationContainer; + +export function createBottomTabNavigator( + routeConfigMap: NavigationRouteConfigMap, + drawConfig?: BottomTabNavigatorConfig +): NavigationContainer; + +export function createMaterialTopTabNavigator( + routeConfigMap: NavigationRouteConfigMap, + drawConfig?: TabNavigatorConfig +): NavigationContainer; + +export interface TabBarTopProps { + activeTintColor: string; + inactiveTintColor: string; + indicatorStyle: StyleProp; + showIcon: boolean; + showLabel: boolean; + upperCaseLabel: boolean; + allowFontScaling: boolean; + position: AnimatedValue; + tabBarPosition: string; + navigation: NavigationScreenProp; + jumpToIndex: (index: number) => void; + getLabel: (scene: TabScene) => React.ReactNode | string; + getOnPress: ( + previousScene: NavigationRoute, + scene: TabScene + ) => ( + args: { + previousScene: NavigationRoute; + scene: TabScene; + jumpToIndex: (index: number) => void; + } + ) => void; + renderIcon: (scene: TabScene) => React.ReactElement; + labelStyle?: TextStyle; + iconStyle?: ViewStyle; +} + +export interface TabBarBottomProps { + activeTintColor: string; + activeBackgroundColor: string; + adaptive?: boolean; + inactiveTintColor: string; + inactiveBackgroundColor: string; + showLabel?: boolean; + allowFontScaling: boolean; + position: AnimatedValue; + navigation: NavigationScreenProp; + jumpToIndex: (index: number) => void; + getLabel: (scene: TabScene) => React.ReactNode | string; + getOnPress: ( + previousScene: NavigationRoute, + scene: TabScene + ) => ( + args: { + previousScene: NavigationRoute; + scene: TabScene; + jumpToIndex: (index: number) => void; + } + ) => void; + getTestIDProps: (scene: TabScene) => (scene: TabScene) => any; + renderIcon: (scene: TabScene) => React.ReactNode; + style?: ViewStyle; + animateStyle?: ViewStyle; + labelStyle?: TextStyle; + tabStyle?: ViewStyle; + showIcon?: boolean; +} + +export const TabBarTop: React.ComponentType; +export const TabBarBottom: React.ComponentType; + +/** + * NavigationActions + */ +export namespace NavigationActions { + const BACK: 'Navigation/BACK'; + const INIT: 'Navigation/INIT'; + const NAVIGATE: 'Navigation/NAVIGATE'; + const SET_PARAMS: 'Navigation/SET_PARAMS'; + + function init(options?: NavigationInitActionPayload): NavigationInitAction; + function navigate( + options: NavigationNavigateActionPayload + ): NavigationNavigateAction; + function back(options?: NavigationBackActionPayload): NavigationBackAction; + function setParams( + options: NavigationSetParamsActionPayload + ): NavigationSetParamsAction; +} + +/** + * DrawerActions + */ +export namespace DrawerActions { + const OPEN_DRAWER: 'Navigation/OPEN_DRAWER'; + const CLOSE_DRAWER: 'Navigation/CLOSE_DRAWER'; + const TOGGLE_DRAWER: 'Navigation/TOGGLE_DRAWER'; + + function openDrawer(): NavigationOpenDrawerAction; + function closeDrawer(): NavigationCloseDrawerAction; + function toggleDrawer(): NavigationToggleDrawerAction; +} + +/** + * StackActions + */ +export namespace StackActions { + const POP: 'Navigation/POP'; + const POP_TO_TOP: 'Navigation/POP_TO_TOP'; + const PUSH: 'Navigation/PUSH'; + const RESET: 'Navigation/RESET'; + const REPLACE: 'Navigation/REPLACE'; + const COMPLETE_TRANSITION: 'Navigation/COMPLETE_TRANSITION'; + + function pop(options: NavigationPopActionPayload): NavigationPopAction; + function popToTop( + options: NavigationPopToTopActionPayload + ): NavigationPopToTopAction; + + function push(options: NavigationPushActionPayload): NavigationPushAction; + function reset(options: NavigationResetActionPayload): NavigationResetAction; + + function replace( + options: NavigationReplaceActionPayload + ): NavigationReplaceAction; + + function completeTransition( + payload: NavigationCompleteTransitionActionPayload + ): NavigationCompleteTransitionAction; +} + +/** + * Transitioner + * @desc From react-navigation/src/views/Transitioner.js + */ +export interface TransitionerProps { + configureTransition: ( + transitionProps: NavigationTransitionProps, + prevTransitionProps?: NavigationTransitionProps + ) => NavigationTransitionSpec; + navigation: NavigationScreenProp; + onTransitionStart?: ( + transitionProps: NavigationTransitionProps, + prevTransitionProps?: NavigationTransitionProps + ) => Promise | void; + onTransitionEnd?: ( + transitionProps: NavigationTransitionProps, + prevTransitionProps?: NavigationTransitionProps + ) => void; + render: ( + transitionProps: NavigationTransitionProps, + prevTransitionProps?: NavigationTransitionProps + ) => any; + descriptors?: { [key: string]: NavigationDescriptor }; + style?: StyleProp; +} + +export interface TransitionerState { + layout: NavigationLayout; + position: Animated.Value; + progress: Animated.Value; + scenes: NavigationScene[]; +} + +export class Transitioner extends React.Component< + TransitionerProps, + TransitionerState + > { } + +/** + * Tab Router + * + * @desc from react-navigation/src/routers/TabRouter.js + */ +export function TabRouter( + routeConfigs: NavigationRouteConfigMap, + config: NavigationTabRouterConfig +): NavigationRouter; + +/** + * Stack Router + * + * @desc from react-navigation/src/routers/StackRouter.js + */ +export function StackRouter( + routeConfigs: NavigationRouteConfigMap, + config: NavigationTabRouterConfig +): NavigationRouter; + +/** + * Create Navigator + * + * @see https://github.com/react-navigation/react-navigation/blob/master/src/navigators/createNavigator.js + */ +export interface NavigationDescriptor { + key: string; + state: NavigationLeafRoute | NavigationStateRoute; + navigation: NavigationScreenProp; + options: NavigationScreenOptions; + getComponent: () => React.ComponentType; +} + +export type NavigationView = React.ComponentType<{ + descriptors: { [key: string]: NavigationDescriptor }; + navigationConfig: O; + screenProps?: { [key: string]: any }; +} & NavigationInjectedProps>; + +export function createNavigator( + view: NavigationView, + router: NavigationRouter, + navigatorConfig?: {} | null, + navigatorType?: NavigatorType +): any; + +/** + * Create an HOC that injects the navigation and manages the navigation state + * in case it's not passed from above. + * This allows to use e.g. the StackNavigator and TabNavigator as root-level + * components. + * + * @see https://github.com/react-navigation/react-navigation/blob/master/src/createNavigationContainer.js + */ +export function createNavigationContainer( + Component: NavigationNavigator +): NavigationContainer; +/** + * END MANUAL DEFINITIONS OUTSIDE OF TYPEDEFINITION.JS + */ + +/** + * BEGIN CUSTOM CONVENIENCE INTERFACES + */ + +export interface NavigationScreenProps< + Params = NavigationParams, + Options = any + > { + navigation: NavigationScreenProp, Params>; + screenProps?: { [key: string]: any }; + navigationOptions?: NavigationScreenConfig; +} + +/** + * END CUSTOM CONVENIENCE INTERFACES + */ + +/* + * Header + */ + +// src/views/HeaderBackButton.js + +export interface HeaderBackButtonProps { + onPress?: () => void; + pressColorAndroid?: string; + title?: string; + titleStyle?: StyleProp; + tintColor?: string; + truncatedTitle?: string; + width?: number; +} + +export const HeaderBackButton: React.ComponentClass; +/** + * Header Component + */ +export class Header extends React.Component { + static HEIGHT: number; +} + +export type Omit = Pick>; + +export type InferProps> = T extends React.ComponentType ? P : never; + +export interface NavigationInjectedProps

{ + navigation: NavigationScreenProp, P>; +} + +// If the wrapped component is a class, we can get a ref to it +export function withNavigation

>( + Component: T & React.ComponentClass

, +): React.ComponentType & { onRef?: React.Ref> }>; + +export function withNavigation

( + Component: React.ComponentType

, +): React.ComponentType>; + +// For backwards compatibility +export function withNavigation( + Component: React.ComponentType>, +): React.ComponentType>> }>; + +export interface NavigationFocusInjectedProps

extends NavigationInjectedProps

{ + isFocused: boolean; +} + +// If the wrapped component is a class, we can get a ref to it +export function withNavigationFocus

>( + Component: T & React.ComponentClass

, +): React.ComponentType & { onRef?: React.Ref> }>; + +export function withNavigationFocus

( + Component: React.ComponentType

, +): React.ComponentType>; + +// For backwards compatibility +export function withNavigationFocus( + Component: React.ComponentType>, +): React.ComponentType>> }>; + +/** + * SafeAreaView Component + */ +export type SafeAreaViewForceInsetValue = 'always' | 'never'; +export interface SafeAreaViewProps extends ViewProps { + forceInset?: { + top?: SafeAreaViewForceInsetValue; + bottom?: SafeAreaViewForceInsetValue; + left?: SafeAreaViewForceInsetValue; + right?: SafeAreaViewForceInsetValue; + horizontal?: SafeAreaViewForceInsetValue; + vertical?: SafeAreaViewForceInsetValue; + }; + children?: React.ReactNode; +} + +export const SafeAreaView: React.ComponentClass; diff --git a/types/react-navigation/v2/react-navigation-tests.tsx b/types/react-navigation/v2/react-navigation-tests.tsx new file mode 100644 index 0000000000..aaa69bc35b --- /dev/null +++ b/types/react-navigation/v2/react-navigation-tests.tsx @@ -0,0 +1,669 @@ +import * as React from 'react'; +import { + Text, + TouchableOpacity, + View, + ViewStyle, +} from 'react-native'; +import { + createDrawerNavigator, + createBottomTabNavigator, + DrawerItems, + DrawerItemsProps, + DrawerNavigatorConfig, + NavigationAction, + NavigationActions, + NavigationEvents, + NavigationBackAction, + NavigationInitAction, + NavigationNavigateAction, + NavigationProp, + NavigationResetAction, + NavigationRoute, + NavigationRouteConfigMap, + NavigationScreenProp, + NavigationScreenProps, + NavigationSetParamsAction, + NavigationStackAction, + NavigationStackScreenOptions, + NavigationStateRoute, + NavigationTabScreenOptions, + NavigationTransitionProps, + StackViewTransitionConfigs, + createStackNavigator, + StackNavigatorConfig, + createSwitchNavigator, + SwitchNavigatorConfig, + TabBarTop, + createTabNavigator, + TabNavigatorConfig, + Transitioner, + HeaderBackButton, + Header, + NavigationContainer, + NavigationParams, + NavigationPopAction, + NavigationPopToTopAction, + NavigationScreenComponent, + NavigationContainerComponent, + withNavigation, + NavigationInjectedProps, + withNavigationFocus, + NavigationFocusInjectedProps +} from 'react-navigation'; + +// Constants +const viewStyle: ViewStyle = { + flex: 1, + margin: 42, + padding: 0, + backgroundColor: "white", +}; + +const ROUTE_NAME_START_SCREEN = "StartScreen"; +const ROUTE_KEY_START_SCREEN = "StartScreen-key"; + +interface StartScreenNavigationParams { + id: number; + s: string; +} + +/** + * @desc Simple screen component class with typed component props that should + * receive the navigation prop from the AppNavigator. + */ +class StartScreen extends React.Component> { + render() { + // Injected type checks + const props: NavigationInjectedProps = this.props; + // route state... + const navigationState: NavigationRoute = this.props.navigation.state; + const index: number = navigationState.index; + const key: string = navigationState.key; + const routeName: string = navigationState.routeName; + const path: string | undefined = navigationState.path; + let routes: NavigationRoute[]; + if (isNavigationStateRoute(navigationState)) { + routes = navigationState.routes; + } + // params... + const navigationStateParams: StartScreenNavigationParams | undefined = this.props.navigation.state.params; + const id: number | undefined = this.props.navigation.state.params && this.props.navigation.state.params.id; + const s: string | undefined = this.props.navigation.state.params && this.props.navigation.state.params.s; + + return ( + + + + + ); + } + private readonly navigateToNextScreen = (): void => { + const params = { + id: this.props.navigation.state.params && this.props.navigation.state.params.id, + name: this.props.navigation.state.params && this.props.navigation.state.params.s, + }; + this.props.navigation.navigate(ROUTE_NAME_NEXT_SCREEN, params); + } + private readonly navigateDifferentlyToNextScreen = (): void => { + const params = { + id: this.props.navigation.state.params && this.props.navigation.state.params.id, + name: this.props.navigation.state.params && this.props.navigation.state.params.s, + }; + this.props.navigation.navigate({routeName: ROUTE_NAME_NEXT_SCREEN, params}); + } +} + +const ROUTE_NAME_NEXT_SCREEN = "NextScreen"; + +interface NextScreenNavigationParams { + id: number; + name: string; +} + +class NextScreen extends React.Component> { + render() { + // Injected type checks + const props: NavigationInjectedProps = this.props; + // route state... + const navigationState: NavigationRoute = this.props.navigation.state; + const index: number = navigationState.index; + const key: string = navigationState.key; + const routeName: string = navigationState.routeName; + const path: string | undefined = navigationState.path; + let routes: NavigationRoute[]; + if (isNavigationStateRoute(navigationState)) { + routes = navigationState.routes; + } + // params... + const navigationStateParams: NextScreenNavigationParams | undefined = navigationState.params; + const id = this.props.navigation.state.params && this.props.navigation.state.params.id; + const name = this.props.navigation.getParam('name', 'Peter'); + return ( + + ); + } +} + +function isNavigationStateRoute

(route: NavigationRoute

): route is NavigationStateRoute

{ + return !!(route as NavigationStateRoute

).routes; +} + +const navigationOptions = { + headerBackTitle: null, +}; +const initialRouteParams: StartScreenNavigationParams = { + id: 1, + s: "Start", +}; + +const routeConfigMap: NavigationRouteConfigMap = { + [ROUTE_NAME_START_SCREEN]: { + path: "start", + screen: StartScreen, + }, + [ROUTE_NAME_NEXT_SCREEN]: { + path: "next", + screen: NextScreen, + }, +}; +export const AppNavigator = createStackNavigator( + routeConfigMap, + { + initialRouteName: ROUTE_NAME_START_SCREEN, + initialRouteKey: ROUTE_KEY_START_SCREEN, + headerLayoutPreset: 'center', + initialRouteParams, + navigationOptions, + }, +); + +interface StatelessScreenParams { + testID: string; +} + +const StatelessScreen: NavigationScreenComponent = (props) => + ; + +StatelessScreen.navigationOptions = { title: 'Stateless' }; + +const SimpleStackNavigator = createStackNavigator( + { + simple: { + screen: StatelessScreen, + }, + } +); + +/** + * Tab navigator. + */ + +const tabNavigatorScreenOptions: NavigationTabScreenOptions = { + title: 'title', + tabBarVisible: true, + tabBarIcon: , + tabBarLabel: 'label', + tabBarOnPress: ({scene, jumpToIndex}) => {} +}; + +const tabNavigatorConfig: TabNavigatorConfig = { + lazy: true, + tabBarComponent: TabBarTop, + tabBarOptions: { activeBackgroundColor: "blue" }, + navigationOptions: () => ({ + tabBarOnPress: ({ scene, jumpToIndex }) => jumpToIndex(scene.index), + tabBarIcon: ({ horizontal }) => , + }) +}; + +const tabNavigatorConfigWithInitialLayout: TabNavigatorConfig = { + ...tabNavigatorConfig, + initialLayout: { height: 0, width: 100 }, +}; + +const tabNavigatorConfigWithNavigationOptions: TabNavigatorConfig = { + ...tabNavigatorConfig, + navigationOptions: { + tabBarOnPress: ({scene, jumpToIndex}) => { + jumpToIndex(scene.index); + }, + headerStyle: { + backgroundColor: 'red', + }, + }, +}; + +const BasicTabNavigator = createTabNavigator( + routeConfigMap, + tabNavigatorConfig, +); + +function renderBasicTabNavigator(): JSX.Element { + return ( + { }} + style={[viewStyle, undefined]} // Test that we are using StyleProp + /> + ); +} + +/** + * Stack navigator. + */ + +const stackNavigatorScreenOptions: NavigationStackScreenOptions = { + title: 'title', +}; + +const stackNavigatorConfig: StackNavigatorConfig = { + mode: "card", + headerMode: "screen", + navigationOptions: stackNavigatorScreenOptions, +}; + +const BasicStackNavigator = createStackNavigator( + routeConfigMap, + stackNavigatorConfig, +); + +function renderBasicStackNavigator(): JSX.Element { + return ( + { }} + style={viewStyle} + /> + ); +} + +const stackNavigatorConfigWithNavigationOptionsAsFunction: StackNavigatorConfig = { + mode: "card", + headerMode: "screen", + navigationOptions: ({navigationOptions, navigation, screenProps}) => (stackNavigatorScreenOptions), +}; + +const AdvancedStackNavigator = createStackNavigator( + routeConfigMap, + stackNavigatorConfigWithNavigationOptionsAsFunction +); + +function renderAdvancedStackNavigator(): JSX.Element { + return ( + { }} + style={viewStyle} + /> + ); +} + +/** + * Switch navigator. + */ + +const switchNavigatorConfig: SwitchNavigatorConfig = { + initialRouteName: 'screen', + resetOnBlur: false, + backBehavior: 'none' +}; + +const BasicSwitchNavigator = createSwitchNavigator( + routeConfigMap, + switchNavigatorConfig, +); + +function renderBasicSwitchNavigator(): JSX.Element { + return ( + { }} + style={viewStyle} + /> + ); +} + +const switchNavigatorConfigWithInitialRoute: SwitchNavigatorConfig = { + initialRouteName: 'screen', + resetOnBlur: false, + backBehavior: 'initialRoute' +}; + +const SwitchNavigatorWithInitialRoute = createSwitchNavigator( + routeConfigMap, + switchNavigatorConfigWithInitialRoute, +); + +function renderSwitchNavigatorWithInitialRoute(): JSX.Element { + return ( + { }} + style={viewStyle} + /> + ); +} + +/** + * Drawer navigator. + */ + +const drawerNavigatorScreenOptions: NavigationTabScreenOptions = { + title: 'title', +}; + +const drawerNavigatorConfig: DrawerNavigatorConfig = { + drawerBackgroundColor: '#777777', + contentOptions: { + activeTintColor: '#7A9B49', + inactiveTintColor: '#FFFFFF', + }, + drawerLockMode: 'locked-open', +}; + +const BasicDrawerNavigator = createDrawerNavigator( + routeConfigMap, + stackNavigatorConfig, +); + +const Drawer = (props: DrawerItemsProps) => ( + +); + +const DrawerNavigatorWithCustomDrawer = createDrawerNavigator( + routeConfigMap, + { + contentComponent: Drawer, + } +); + +function renderBasicDrawerNavigator(): JSX.Element { + return ( + { }} + style={viewStyle} + /> + ); +} + +interface ParamsOnStateProps { + navigation: NavigationScreenProp<{}, { foobar: string }>; +} + +class ParamsOnState extends React.Component { + render() { + if (this.props.navigation.state.params) { + // $ExpectType string + this.props.navigation.state.params.foobar; + } else { + // $ExpectType undefined + this.props.navigation.state.params; + } + + return ; + } +} + +interface CustomTransitionerProps { + navigation: NavigationScreenProp; +} +/** + * @desc Custom transitioner component. Follows react-navigation/src/views/CardStackTransitioner.js. + */ +class CustomTransitioner extends React.Component { + render() { + return ( + { + if (prev) { + prev.position.setValue(curr.navigation.state.index); + } + }} + onTransitionEnd={(curr, prev) => { + if (prev) { + prev.position.setValue(curr.navigation.state.index); + } + }} + /> + ); + } + _render = (props: NavigationTransitionProps, prevProps?: NavigationTransitionProps): React.ReactElement => { + return ( + + ); + } + _configureTransition = ( + _transitionProps: NavigationTransitionProps, + _prevTransitionProps?: NavigationTransitionProps + ) => { + return {}; + } +} + +/** + * Header + */ +const height = Header.HEIGHT; + +function renderHeaderBackButton(schema: string): JSX.Element { + switch (schema) { + case 'compact': + return ( + + ); + + default: + return ( + 'noop'} + pressColorAndroid="#ccc" + title="Press Me" + titleStyle={{ color: '#333' }} + tintColor="#2196f3" + truncatedTitle="Press" + width={85} + /> + ); + } +} + +const initAction: NavigationInitAction = NavigationActions.init({ + params: { + foo: "bar" + } +}); + +const navigateAction: NavigationNavigateAction = NavigationActions.navigate({ + routeName: "FooScreen", + params: { + foo: "bar" + }, + action: NavigationActions.navigate({ routeName: "BarScreen" }) +}); + +const backAction: NavigationBackAction = NavigationActions.back({ + key: "foo" +}); + +const setParamsAction: NavigationSetParamsAction = NavigationActions.setParams({ + key: "foo", + params: { + foo: "bar" + } +}); + +class Page1 extends React.Component { } + +const RootNavigator: NavigationContainer = createSwitchNavigator({ + default: { getScreen: () => Page1 }, +}); + +class Page2 extends React.Component { + navigatorRef: NavigationContainerComponent | null; + + componentDidMount() { + if (this.navigatorRef) { + this.navigatorRef.dispatch(NavigationActions.navigate({ routeName: 'default' })); + } + } + + render() { + return { this.navigatorRef = instance; }} />; + } +} + +const BottomStack = createBottomTabNavigator({ + Posts: { + screen: Page2, + navigationOptions: ({ navigation }: NavigationScreenProps) => { + let tabBarVisible = true; + + if (navigation.state.index > 0) { + tabBarVisible = false; + } + + return { + tabBarVisible + }; + } + } +}, { + navigationOptions: () => ({ + tabBarOnPress: ({ defaultHandler }) => defaultHandler() + }) +}); + +const CustomHeaderStack = createStackNavigator({ + Page1: { screen: Page1 }, + Page2: { screen: Page2 } +}, +{ + navigationOptions: { + header: headerProps => { + const { scene } = headerProps; + const { options } = scene.descriptor; + const { title, headerStyle, headerTitleStyle } = options; + return ( + + {title} + + ); + } + } +}); + +interface ScreenProps { + name: string; + optionalAge?: number; + onPlay(): void; +} + +class SetParamsTest extends React.Component> { + componentDidMount() { + this.props.navigation.setParams({ + onPlay: this.onPlay + }); + } + + onPlay = () => { + // + } + + render() { + const name = this.props.navigation.getParam('name'); + const age = this.props.navigation.getParam('optionalAge'); + + // $ExpectType number | undefined + this.props.navigation.getParam('optionalAge'); + + // $ExpectType number + this.props.navigation.getParam('optionalAge', 0); + + return ( + My name is {name} and I am {age} years old. + ); + } +} + +// Test withNavigation + +interface BackButtonProps { title: string; } +class MyBackButton extends React.Component { + triggerBack() { + console.log("Not implemented, すみません"); + } + render() { + return