mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2025-10-16 12:05:41 +00:00
696 lines
19 KiB
TypeScript
696 lines
19 KiB
TypeScript
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<NavigationScreenProps<StartScreenNavigationParams>> {
|
|
render() {
|
|
// Injected type checks
|
|
const props: NavigationInjectedProps<StartScreenNavigationParams> = this.props;
|
|
// route state...
|
|
const navigationState: NavigationRoute<StartScreenNavigationParams> = 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 (
|
|
<View>
|
|
<TouchableOpacity onPress={this.navigateToNextScreen} />
|
|
<TouchableOpacity onPress={this.navigateDifferentlyToNextScreen} />
|
|
</View>
|
|
);
|
|
}
|
|
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<NavigationScreenProps<NextScreenNavigationParams>> {
|
|
render() {
|
|
// Injected type checks
|
|
const props: NavigationInjectedProps<NextScreenNavigationParams> = this.props;
|
|
// route state...
|
|
const navigationState: NavigationRoute<NextScreenNavigationParams> = 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 (
|
|
<View />
|
|
);
|
|
}
|
|
}
|
|
|
|
function isNavigationStateRoute<P>(route: NavigationRoute<P>): route is NavigationStateRoute<P> {
|
|
return !!(route as NavigationStateRoute<P>).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<StatelessScreenParams> = (props) =>
|
|
<View testID={props.navigation.getParam('testID', 'fallback')}/>;
|
|
|
|
StatelessScreen.navigationOptions = { title: 'Stateless' };
|
|
|
|
const SimpleStackNavigator = createStackNavigator(
|
|
{
|
|
simple: {
|
|
screen: StatelessScreen,
|
|
},
|
|
}
|
|
);
|
|
|
|
/**
|
|
* Tab navigator.
|
|
*/
|
|
|
|
const tabNavigatorScreenOptions: NavigationTabScreenOptions = {
|
|
title: 'title',
|
|
tabBarVisible: true,
|
|
tabBarIcon: <View />,
|
|
tabBarLabel: 'label',
|
|
tabBarOnPress: ({scene, jumpToIndex}) => {}
|
|
};
|
|
|
|
const tabNavigatorConfig: TabNavigatorConfig = {
|
|
lazy: true,
|
|
tabBarComponent: TabBarTop,
|
|
tabBarOptions: { activeBackgroundColor: "blue" },
|
|
defaultNavigationOptions: () => ({
|
|
tabBarOnPress: ({ scene, jumpToIndex }) => jumpToIndex(scene.index),
|
|
tabBarIcon: ({ horizontal }) => <View />,
|
|
}),
|
|
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 (
|
|
<BasicTabNavigator
|
|
ref={(ref: any) => { }}
|
|
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 (
|
|
<BasicStackNavigator
|
|
ref={(ref: any) => { }}
|
|
style={viewStyle}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const stackNavigatorConfigWithNavigationOptionsAsFunction: StackNavigatorConfig = {
|
|
mode: "card",
|
|
headerMode: "screen",
|
|
defaultNavigationOptions: ({navigationOptions, navigation, screenProps}) => (stackNavigatorScreenOptions),
|
|
};
|
|
|
|
const AdvancedStackNavigator = createStackNavigator(
|
|
routeConfigMap,
|
|
stackNavigatorConfigWithNavigationOptionsAsFunction
|
|
);
|
|
|
|
function renderAdvancedStackNavigator(): JSX.Element {
|
|
return (
|
|
<AdvancedStackNavigator
|
|
ref={(ref: any) => { }}
|
|
style={viewStyle}
|
|
/>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Switch navigator.
|
|
*/
|
|
|
|
const switchNavigatorConfig: SwitchNavigatorConfig = {
|
|
initialRouteName: 'screen',
|
|
resetOnBlur: false,
|
|
backBehavior: 'none'
|
|
};
|
|
|
|
const BasicSwitchNavigator = createSwitchNavigator(
|
|
routeConfigMap,
|
|
switchNavigatorConfig,
|
|
);
|
|
|
|
function renderBasicSwitchNavigator(): JSX.Element {
|
|
return (
|
|
<BasicSwitchNavigator
|
|
ref={(ref: any) => { }}
|
|
style={viewStyle}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const switchNavigatorConfigWithInitialRoute: SwitchNavigatorConfig = {
|
|
initialRouteName: 'screen',
|
|
resetOnBlur: false,
|
|
backBehavior: 'initialRoute'
|
|
};
|
|
|
|
const SwitchNavigatorWithInitialRoute = createSwitchNavigator(
|
|
routeConfigMap,
|
|
switchNavigatorConfigWithInitialRoute,
|
|
);
|
|
|
|
function renderSwitchNavigatorWithInitialRoute(): JSX.Element {
|
|
return (
|
|
<SwitchNavigatorWithInitialRoute
|
|
ref={(ref: any) => { }}
|
|
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) => (
|
|
<DrawerItems {...props} />
|
|
);
|
|
|
|
const DrawerNavigatorWithCustomDrawer = createDrawerNavigator(
|
|
routeConfigMap,
|
|
{
|
|
contentComponent: Drawer,
|
|
}
|
|
);
|
|
|
|
function renderBasicDrawerNavigator(): JSX.Element {
|
|
return (
|
|
<BasicDrawerNavigator
|
|
ref={(ref: any) => { }}
|
|
style={viewStyle}
|
|
/>
|
|
);
|
|
}
|
|
|
|
interface ParamsOnStateProps {
|
|
navigation: NavigationScreenProp<{}, { foobar: string }>;
|
|
}
|
|
|
|
class ParamsOnState extends React.Component<ParamsOnStateProps> {
|
|
render() {
|
|
if (this.props.navigation.state.params) {
|
|
// $ExpectType string
|
|
this.props.navigation.state.params.foobar;
|
|
} else {
|
|
// $ExpectType undefined
|
|
this.props.navigation.state.params;
|
|
}
|
|
|
|
return <View />;
|
|
}
|
|
}
|
|
|
|
interface CustomTransitionerProps {
|
|
navigation: NavigationScreenProp<any, any>;
|
|
}
|
|
/**
|
|
* @desc Custom transitioner component. Follows react-navigation/src/views/CardStackTransitioner.js.
|
|
*/
|
|
class CustomTransitioner extends React.Component<CustomTransitionerProps, null> {
|
|
render() {
|
|
return (
|
|
<Transitioner
|
|
configureTransition={this._configureTransition}
|
|
navigation={this.props.navigation}
|
|
render={this._render}
|
|
onTransitionStart={(curr, prev) => {
|
|
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 (
|
|
<View />
|
|
);
|
|
}
|
|
_configureTransition = (
|
|
_transitionProps: NavigationTransitionProps,
|
|
_prevTransitionProps?: NavigationTransitionProps
|
|
) => {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Header
|
|
*/
|
|
const height = Header.HEIGHT;
|
|
|
|
function renderHeaderBackButton(schema: string): JSX.Element {
|
|
switch (schema) {
|
|
case 'compact':
|
|
return (
|
|
<HeaderBackButton />
|
|
);
|
|
|
|
default:
|
|
return (
|
|
<HeaderBackButton
|
|
onPress={() => '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 <RootNavigator ref={(instance: NavigationContainerComponent | null): void => { 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 (
|
|
<View style={headerStyle}>
|
|
<Text style={headerTitleStyle}>{title}</Text>
|
|
</View>
|
|
);
|
|
}
|
|
}
|
|
});
|
|
|
|
interface ScreenProps {
|
|
name: string;
|
|
optionalAge?: number;
|
|
onPlay(): void;
|
|
}
|
|
|
|
class SetParamsTest extends React.Component<NavigationScreenProps<ScreenProps>> {
|
|
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 (
|
|
<Text>My name is {name} and I am {age} years old.</Text>
|
|
);
|
|
}
|
|
}
|
|
|
|
// Test withNavigation
|
|
|
|
interface BackButtonProps { title: string; }
|
|
class MyBackButton extends React.Component<BackButtonProps & NavigationInjectedProps> {
|
|
triggerBack() {
|
|
console.log("Not implemented, すみません");
|
|
}
|
|
render() {
|
|
return <button title={this.props.title} onClick={() => { this.props.navigation.goBack(); }} />;
|
|
}
|
|
}
|
|
|
|
// withNavigation returns a component that wraps MyBackButton and passes in the navigation prop.
|
|
// If you have class methods, you should have a way to use them.
|
|
const BackButtonWithNavigation = withNavigation(MyBackButton);
|
|
const BackButtonInstance = <BackButtonWithNavigation
|
|
title="Back" onRef={ref => {
|
|
// ref is inferred as MyBackButton | null
|
|
if (!ref) return;
|
|
ref.triggerBack();
|
|
}}
|
|
/>;
|
|
|
|
function StatelessBackButton(props: BackButtonProps & NavigationInjectedProps) {
|
|
return <MyBackButton {...props} />;
|
|
}
|
|
|
|
// Wrapped stateless components don't accept an onRef
|
|
const StatelessBackButtonWithNavigation = withNavigation(StatelessBackButton);
|
|
const StatelessBackButtonInstance = <StatelessBackButtonWithNavigation title="Back" />;
|
|
|
|
// The old way of passing in the props should still work
|
|
const BackButtonWithNavigationWithExplicitProps = withNavigation<BackButtonProps>(MyBackButton);
|
|
const BackButtonWithExplicitPropsInstance = <BackButtonWithNavigationWithExplicitProps
|
|
title="Back" onRef={ref => {
|
|
if (!ref) return;
|
|
// We can't infer the component type if we pass in the props
|
|
(ref as MyBackButton).triggerBack();
|
|
}}
|
|
/>;
|
|
|
|
// Test withNavigationFocus
|
|
|
|
interface MyFocusedComponentProps { expectsFocus: boolean; }
|
|
class MyFocusedComponent extends React.Component<MyFocusedComponentProps & NavigationFocusInjectedProps> {
|
|
render() {
|
|
return <button title={`${this.props.expectsFocus} vs ${this.props.isFocused}`} onClick={() => { this.props.navigation.goBack(); }} />;
|
|
}
|
|
}
|
|
|
|
// withNavigationFocus returns a component that wraps MyFocusedComponent and passes in the
|
|
// navigation and isFocused prop
|
|
const MyFocusedComponentWithNavigationFocus = withNavigationFocus(MyFocusedComponent);
|
|
const MyFocusedComponentInstance = <MyFocusedComponentWithNavigationFocus
|
|
expectsFocus={true} onRef={ref => { const backButtonRef = ref; }}
|
|
/>;
|
|
|
|
// Test Screen with params
|
|
|
|
interface MyScreenParams { title: string; }
|
|
class MyScreen extends React.Component<NavigationInjectedProps<MyScreenParams>> {
|
|
render() {
|
|
const title = this.props.navigation.getParam('title');
|
|
return <button title={title} onClick={() => { this.props.navigation.goBack(); }} />;
|
|
}
|
|
}
|
|
|
|
// Test createStackNavigator
|
|
|
|
createStackNavigator(
|
|
routeConfigMap,
|
|
{transitionConfig: () => ({screenInterpolator: StackViewTransitionConfigs.SlideFromRightIOS.screenInterpolator})}
|
|
);
|
|
|
|
// Test createAppContainer
|
|
|
|
export const AppContainer = createAppContainer(AppNavigator);
|
|
|
|
// Test NavigationEvents component
|
|
const ViewWithNavigationEvents = (
|
|
<NavigationEvents
|
|
onWillFocus={console.log}
|
|
onDidFocus={console.log}
|
|
onWillBlur={console.log}
|
|
onDidBlur={console.log}
|
|
/>
|
|
);
|
|
|
|
// Test NavigationContext
|
|
const componentWithNavigationContext = (
|
|
<NavigationContext.Consumer>
|
|
{
|
|
navigationContext => (
|
|
<NavigationEvents navigation={navigationContext} />
|
|
)
|
|
}
|
|
</NavigationContext.Consumer>
|
|
);
|