import * as React from 'react'; import { Text, TouchableOpacity, View, ViewStyle, } from 'react-native'; import { createAppContainer, 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, createMaterialTopTabNavigator, TabNavigatorConfig, Transitioner, HeaderBackButton, Header, NavigationContainer, NavigationContext, 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, defaultNavigationOptions: navigationOptions, navigationOptions: { headerTintColor: '#fff', headerStyle: { backgroundColor: '#000', }, } }, ); 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" }, defaultNavigationOptions: () => ({ tabBarOnPress: ({ scene, jumpToIndex }) => jumpToIndex(scene.index), tabBarIcon: ({ horizontal }) => , }), navigationOptions: { backBehavior: 'none' } }; const tabNavigatorConfigWithInitialLayout: TabNavigatorConfig = { ...tabNavigatorConfig, initialLayout: { height: 0, width: 100 }, }; const tabNavigatorConfigWithNavigationOptions: TabNavigatorConfig = { ...tabNavigatorConfig, defaultNavigationOptions: { tabBarOnPress: ({scene, jumpToIndex}) => { jumpToIndex(scene.index); }, headerStyle: { backgroundColor: 'red', }, }, }; const BasicTabNavigator = createMaterialTopTabNavigator( 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", defaultNavigationOptions: stackNavigatorScreenOptions, }; const BasicStackNavigator = createStackNavigator( routeConfigMap, stackNavigatorConfig, ); function renderBasicStackNavigator(): JSX.Element { return ( { }} style={viewStyle} /> ); } const stackNavigatorConfigWithNavigationOptionsAsFunction: StackNavigatorConfig = { mode: "card", headerMode: "screen", defaultNavigationOptions: ({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, drawerNavigatorConfig, ); 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 }; } } }, { defaultNavigationOptions: () => ({ tabBarOnPress: ({ defaultHandler }) => defaultHandler() }) }); const CustomHeaderStack = createStackNavigator({ Page1: { screen: Page1 }, Page2: { screen: Page2 } }, { defaultNavigationOptions: { 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