UNPKG

4.15 kBTypeScriptView Raw
1import {
2 createNavigatorFactory,
3 DefaultNavigatorOptions,
4 EventArg,
5 ParamListBase,
6 StackActionHelpers,
7 StackActions,
8 StackNavigationState,
9 StackRouter,
10 StackRouterOptions,
11 useNavigationBuilder,
12} from '@react-navigation/native';
13import * as React from 'react';
14import warnOnce from 'warn-once';
15
16import type {
17 StackHeaderMode,
18 StackNavigationConfig,
19 StackNavigationEventMap,
20 StackNavigationOptions,
21} from '../types';
22import StackView from '../views/Stack/StackView';
23
24type Props = DefaultNavigatorOptions<
25 ParamListBase,
26 StackNavigationState<ParamListBase>,
27 StackNavigationOptions,
28 StackNavigationEventMap
29> &
30 StackRouterOptions &
31 StackNavigationConfig;
32
33function StackNavigator({
34 id,
35 initialRouteName,
36 children,
37 screenListeners,
38 screenOptions,
39 ...rest
40}: Props) {
41 // @ts-expect-error: mode is deprecated
42 const mode = rest.mode as 'card' | 'modal' | undefined;
43
44 warnOnce(
45 mode != null,
46 `Stack Navigator: 'mode="${mode}"' is deprecated. Use 'presentation: "${mode}"' in 'screenOptions' instead.\n\nSee https://reactnavigation.org/docs/stack-navigator#presentation for more details.`
47 );
48
49 // @ts-expect-error: headerMode='none' is deprecated
50 const headerMode = rest.headerMode as StackHeaderMode | 'none' | undefined;
51
52 warnOnce(
53 headerMode === 'none',
54 `Stack Navigator: 'headerMode="none"' is deprecated. Use 'headerShown: false' in 'screenOptions' instead.\n\nSee https://reactnavigation.org/docs/stack-navigator/#headershown for more details.`
55 );
56
57 warnOnce(
58 headerMode != null && headerMode !== 'none',
59 `Stack Navigator: 'headerMode' is moved to 'options'. Moved it to 'screenOptions' to keep current behavior.\n\nSee https://reactnavigation.org/docs/stack-navigator/#headermode for more details.`
60 );
61
62 // @ts-expect-error: headerMode='none' is deprecated
63 const keyboardHandlingEnabled = rest.keyboardHandlingEnabled;
64
65 warnOnce(
66 keyboardHandlingEnabled !== undefined,
67 `Stack Navigator: 'keyboardHandlingEnabled' is moved to 'options'. Moved it to 'screenOptions' to keep current behavior.\n\nSee https://reactnavigation.org/docs/stack-navigator/#keyboardhandlingenabled for more details.`
68 );
69
70 const defaultScreenOptions: StackNavigationOptions = {
71 presentation: mode,
72 headerShown: headerMode ? headerMode !== 'none' : true,
73 headerMode: headerMode && headerMode !== 'none' ? headerMode : undefined,
74 keyboardHandlingEnabled,
75 };
76
77 const { state, descriptors, navigation, NavigationContent } =
78 useNavigationBuilder<
79 StackNavigationState<ParamListBase>,
80 StackRouterOptions,
81 StackActionHelpers<ParamListBase>,
82 StackNavigationOptions,
83 StackNavigationEventMap
84 >(StackRouter, {
85 id,
86 initialRouteName,
87 children,
88 screenListeners,
89 screenOptions,
90 defaultScreenOptions,
91 });
92
93 React.useEffect(
94 () =>
95 // @ts-expect-error: there may not be a tab navigator in parent
96 navigation.addListener?.('tabPress', (e) => {
97 const isFocused = navigation.isFocused();
98
99 // Run the operation in the next frame so we're sure all listeners have been run
100 // This is necessary to know if preventDefault() has been called
101 requestAnimationFrame(() => {
102 if (
103 state.index > 0 &&
104 isFocused &&
105 !(e as unknown as EventArg<'tabPress', true>).defaultPrevented
106 ) {
107 // When user taps on already focused tab and we're inside the tab,
108 // reset the stack to replicate native behaviour
109 navigation.dispatch({
110 ...StackActions.popToTop(),
111 target: state.key,
112 });
113 }
114 });
115 }),
116 [navigation, state.index, state.key]
117 );
118
119 return (
120 <NavigationContent>
121 <StackView
122 {...rest}
123 state={state}
124 descriptors={descriptors}
125 navigation={navigation}
126 />
127 </NavigationContent>
128 );
129}
130
131export default createNavigatorFactory<
132 StackNavigationState<ParamListBase>,
133 StackNavigationOptions,
134 StackNavigationEventMap,
135 typeof StackNavigator
136>(StackNavigator);