@react-navigation/native-stack 6.2.5 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/lib/commonjs/index.js +8 -0
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/navigators/createNativeStackNavigator.js +12 -10
  4. package/lib/commonjs/navigators/createNativeStackNavigator.js.map +1 -1
  5. package/lib/commonjs/views/HeaderConfig.js +62 -39
  6. package/lib/commonjs/views/HeaderConfig.js.map +1 -1
  7. package/lib/commonjs/views/NativeStackView.js +62 -40
  8. package/lib/commonjs/views/NativeStackView.js.map +1 -1
  9. package/lib/commonjs/views/NativeStackView.native.js +57 -41
  10. package/lib/commonjs/views/NativeStackView.native.js.map +1 -1
  11. package/lib/module/index.js +5 -0
  12. package/lib/module/index.js.map +1 -1
  13. package/lib/module/navigators/createNativeStackNavigator.js +12 -10
  14. package/lib/module/navigators/createNativeStackNavigator.js.map +1 -1
  15. package/lib/module/views/HeaderConfig.js +62 -39
  16. package/lib/module/views/HeaderConfig.js.map +1 -1
  17. package/lib/module/views/NativeStackView.js +61 -40
  18. package/lib/module/views/NativeStackView.js.map +1 -1
  19. package/lib/module/views/NativeStackView.native.js +59 -43
  20. package/lib/module/views/NativeStackView.native.js.map +1 -1
  21. package/lib/typescript/src/index.d.ts +5 -1
  22. package/lib/typescript/src/types.d.ts +40 -11
  23. package/lib/typescript/src/views/HeaderConfig.d.ts +2 -1
  24. package/package.json +6 -6
  25. package/src/index.tsx +6 -0
  26. package/src/navigators/createNativeStackNavigator.tsx +21 -18
  27. package/src/types.tsx +41 -9
  28. package/src/views/HeaderConfig.tsx +153 -103
  29. package/src/views/NativeStackView.native.tsx +65 -47
  30. package/src/views/NativeStackView.tsx +25 -3
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@react-navigation/native-stack",
3
3
  "description": "Native stack navigator using react-native-screens",
4
- "version": "6.2.5",
4
+ "version": "6.5.0",
5
5
  "keywords": [
6
6
  "react-native-component",
7
7
  "react-component",
@@ -41,16 +41,16 @@
41
41
  "clean": "del lib"
42
42
  },
43
43
  "dependencies": {
44
- "@react-navigation/elements": "^1.2.1",
44
+ "@react-navigation/elements": "^1.3.1",
45
45
  "warn-once": "^0.1.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@react-navigation/native": "^6.0.6",
48
+ "@react-navigation/native": "^6.0.8",
49
49
  "@testing-library/react-native": "^7.2.0",
50
50
  "@types/react": "^17.0.9",
51
51
  "@types/react-native": "~0.64.9",
52
- "react": "~16.13.1",
53
- "react-native": "~0.63.4",
52
+ "react": "17.0.1",
53
+ "react-native": "~0.64.3",
54
54
  "react-native-builder-bob": "^0.18.1",
55
55
  "react-native-screens": "^3.3.0",
56
56
  "typescript": "^4.3.2"
@@ -76,5 +76,5 @@
76
76
  ]
77
77
  ]
78
78
  },
79
- "gitHead": "e947943ace33086405210e9454329be47d76478f"
79
+ "gitHead": "7346aef7a10b19784e52bbc36a6db1154e2ec459"
80
80
  }
package/src/index.tsx CHANGED
@@ -3,11 +3,17 @@
3
3
  */
4
4
  export { default as createNativeStackNavigator } from './navigators/createNativeStackNavigator';
5
5
 
6
+ /**
7
+ * Views
8
+ */
9
+ export { default as NativeStackView } from './views/NativeStackView';
10
+
6
11
  /**
7
12
  * Types
8
13
  */
9
14
  export type {
10
15
  NativeStackHeaderProps,
16
+ NativeStackNavigationEventMap,
11
17
  NativeStackNavigationOptions,
12
18
  NativeStackNavigationProp,
13
19
  NativeStackScreenProps,
@@ -25,18 +25,19 @@ function NativeStackNavigator({
25
25
  screenOptions,
26
26
  ...rest
27
27
  }: NativeStackNavigatorProps) {
28
- const { state, descriptors, navigation } = useNavigationBuilder<
29
- StackNavigationState<ParamListBase>,
30
- StackRouterOptions,
31
- StackActionHelpers<ParamListBase>,
32
- NativeStackNavigationOptions,
33
- NativeStackNavigationEventMap
34
- >(StackRouter, {
35
- initialRouteName,
36
- children,
37
- screenListeners,
38
- screenOptions,
39
- });
28
+ const { state, descriptors, navigation, NavigationContent } =
29
+ useNavigationBuilder<
30
+ StackNavigationState<ParamListBase>,
31
+ StackRouterOptions,
32
+ StackActionHelpers<ParamListBase>,
33
+ NativeStackNavigationOptions,
34
+ NativeStackNavigationEventMap
35
+ >(StackRouter, {
36
+ initialRouteName,
37
+ children,
38
+ screenListeners,
39
+ screenOptions,
40
+ });
40
41
 
41
42
  React.useEffect(
42
43
  () =>
@@ -64,12 +65,14 @@ function NativeStackNavigator({
64
65
  );
65
66
 
66
67
  return (
67
- <NativeStackView
68
- {...rest}
69
- state={state}
70
- navigation={navigation}
71
- descriptors={descriptors}
72
- />
68
+ <NavigationContent>
69
+ <NativeStackView
70
+ {...rest}
71
+ state={state}
72
+ navigation={navigation}
73
+ descriptors={descriptors}
74
+ />
75
+ </NavigationContent>
73
76
  );
74
77
  }
75
78
 
package/src/types.tsx CHANGED
@@ -85,20 +85,23 @@ export type NativeStackHeaderProps = {
85
85
  navigation: NativeStackNavigationProp<ParamListBase>;
86
86
  };
87
87
 
88
- export type HeaderBackButtonProps = {
88
+ export type HeaderButtonProps = {
89
89
  /**
90
90
  * Tint color for the header.
91
91
  */
92
92
  tintColor?: string;
93
+ /**
94
+ * Whether it's possible to navigate back in stack.
95
+ */
96
+ canGoBack: boolean;
97
+ };
98
+
99
+ export type HeaderBackButtonProps = HeaderButtonProps & {
93
100
  /**
94
101
  * Label text for the button. Usually the title of the previous screen.
95
102
  * By default, this is only shown on iOS.
96
103
  */
97
104
  label?: string;
98
- /**
99
- * Whether it's possible to navigate back in stack.
100
- */
101
- canGoBack: boolean;
102
105
  };
103
106
 
104
107
  export type NativeStackNavigationOptions = {
@@ -179,6 +182,7 @@ export type NativeStackNavigationOptions = {
179
182
  *
180
183
  * For large title to collapse on scroll, the content of the screen should be wrapped in a scrollable view such as `ScrollView` or `FlatList`.
181
184
  * If the scrollable area doesn't fill the screen, the large title won't collapse on scroll.
185
+ * You also need to specify `contentInsetAdjustmentBehavior="automatic"` in your `ScrollView`, `FlatList` etc.
182
186
  *
183
187
  * Only supported on iOS.
184
188
  *
@@ -245,6 +249,12 @@ export type NativeStackNavigationOptions = {
245
249
  * Tint color for the header. Changes the color of back button and title.
246
250
  */
247
251
  headerTintColor?: string;
252
+ /**
253
+ * Function which returns a React Element to render as the background of the header.
254
+ * This is useful for using backgrounds such as an image, a gradient, blur effect etc.
255
+ * You can use this with `headerTransparent` to render content underneath a translucent header.
256
+ */
257
+ headerBackground?: () => React.ReactNode;
248
258
  /**
249
259
  * Function which returns a React Element to display on the left side of the header.
250
260
  * This replaces the back button. See `headerBackVisible` to show the back button along side left element.
@@ -253,7 +263,7 @@ export type NativeStackNavigationOptions = {
253
263
  /**
254
264
  * Function which returns a React Element to display on the right side of the header.
255
265
  */
256
- headerRight?: (props: { tintColor?: string }) => React.ReactNode;
266
+ headerRight?: (props: HeaderButtonProps) => React.ReactNode;
257
267
  /**
258
268
  * String or a function that returns a React Element to be used by the header.
259
269
  * Defaults to screen `title` or route name.
@@ -295,9 +305,11 @@ export type NativeStackNavigationOptions = {
295
305
  }
296
306
  >;
297
307
  /**
298
- * Options to render a native search bar on iOS.
308
+ * Options to render a native search bar.
309
+ * You also need to specify `contentInsetAdjustmentBehavior="automatic"` in your `ScrollView`, `FlatList` etc.
310
+ * If you don't have a `ScrollView`, specify `headerTransparent: false`.
299
311
  *
300
- * @platform ios
312
+ * Only supported on iOS and Android.
301
313
  */
302
314
  headerSearchBarOptions?: SearchBarProps;
303
315
  /**
@@ -340,6 +352,24 @@ export type NativeStackNavigationOptions = {
340
352
  * Style object for the scene content.
341
353
  */
342
354
  contentStyle?: StyleProp<ViewStyle>;
355
+ /**
356
+ * Whether the gesture to dismiss should use animation provided to `animation` prop. Defaults to `false`.
357
+ *
358
+ * Doesn't affect the behavior of screens presented modally.
359
+ *
360
+ * @platform ios
361
+ */
362
+ customAnimationOnGesture?: boolean;
363
+ /**
364
+ * Whether the gesture to dismiss should work on the whole screen. Using gesture to dismiss with this option results in the same
365
+ * transition animation as `simple_push`. This behavior can be changed by setting `customAnimationOnGesture` prop. Achieving the
366
+ * default iOS animation isn't possible due to platform limitations. Defaults to `false`.
367
+ *
368
+ * Doesn't affect the behavior of screens presented modally.
369
+ *
370
+ * @platform ios
371
+ */
372
+ fullScreenGestureEnabled?: boolean;
343
373
  /**
344
374
  * Whether you can use gestures to dismiss this screen. Defaults to `true`.
345
375
  *
@@ -364,7 +394,9 @@ export type NativeStackNavigationOptions = {
364
394
  * Supported values:
365
395
  * - "default": use the platform default animation
366
396
  * - "fade": fade screen in or out
367
- * - "flip": flip the screen, requires stackPresentation: "modal" (iOS only)
397
+ * - "flip": flip the screen, requires presentation: "modal" (iOS only)
398
+ * - "simple_push": use the platform default animation, but without shadow and native header transition (iOS only)
399
+ * - "slide_from_bottom": slide in the new screen from bottom
368
400
  * - "slide_from_right": slide in the new screen from right (Android only, uses default animation on iOS)
369
401
  * - "slide_from_left": slide in the new screen from left (Android only, uses default animation on iOS)
370
402
  * - "none": don't animate the screen
@@ -10,6 +10,7 @@ import {
10
10
  } from 'react-native';
11
11
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
12
12
  import {
13
+ isSearchBarAvailableForCurrentPlatform,
13
14
  ScreenStackHeaderBackButtonImage,
14
15
  ScreenStackHeaderCenterView,
15
16
  ScreenStackHeaderConfig,
@@ -23,11 +24,13 @@ import type { NativeStackNavigationOptions } from '../types';
23
24
  import { processFonts } from './FontProcessor';
24
25
 
25
26
  type Props = NativeStackNavigationOptions & {
27
+ headerHeight: number;
26
28
  route: Route<string>;
27
29
  canGoBack: boolean;
28
30
  };
29
31
 
30
32
  export default function HeaderConfig({
33
+ headerHeight,
31
34
  headerBackImageSource,
32
35
  headerBackButtonMenuEnabled,
33
36
  headerBackTitle,
@@ -39,6 +42,7 @@ export default function HeaderConfig({
39
42
  headerLargeTitle,
40
43
  headerLargeTitleShadowVisible,
41
44
  headerLargeTitleStyle,
45
+ headerBackground,
42
46
  headerLeft,
43
47
  headerRight,
44
48
  headerShown,
@@ -55,6 +59,7 @@ export default function HeaderConfig({
55
59
  canGoBack,
56
60
  }: Props): JSX.Element {
57
61
  const insets = useSafeAreaInsets();
62
+
58
63
  const { colors } = useTheme();
59
64
  const tintColor =
60
65
  headerTintColor ?? (Platform.OS === 'ios' ? colors.primary : colors.text);
@@ -96,20 +101,28 @@ export default function HeaderConfig({
96
101
 
97
102
  const headerLeftElement = headerLeft?.({
98
103
  tintColor,
104
+ canGoBack,
99
105
  label: headerBackTitle,
106
+ });
107
+ const headerRightElement = headerRight?.({
108
+ tintColor,
100
109
  canGoBack,
101
110
  });
102
- const headerRightElement = headerRight?.({ tintColor });
103
111
  const headerTitleElement =
104
112
  typeof headerTitle === 'function'
105
113
  ? headerTitle({ tintColor, children: titleText })
106
114
  : null;
107
115
 
108
- if (
109
- Platform.OS === 'ios' &&
110
- headerSearchBarOptions != null &&
111
- SearchBar == null
112
- ) {
116
+ const supportsHeaderSearchBar =
117
+ typeof isSearchBarAvailableForCurrentPlatform === 'boolean'
118
+ ? isSearchBarAvailableForCurrentPlatform
119
+ : // Fallback for older versions of react-native-screens
120
+ Platform.OS === 'ios' && SearchBar != null;
121
+
122
+ const hasHeaderSearchBar =
123
+ supportsHeaderSearchBar && headerSearchBarOptions != null;
124
+
125
+ if (headerSearchBarOptions != null && !supportsHeaderSearchBar) {
113
126
  throw new Error(
114
127
  `The current version of 'react-native-screens' doesn't support SearchBar in the header. Please update to the latest version to use this option.`
115
128
  );
@@ -124,105 +137,132 @@ export default function HeaderConfig({
124
137
  ? headerLeftElement != null
125
138
  : Platform.OS === 'android' && headerTitleElement != null;
126
139
 
140
+ const translucent =
141
+ headerBackground != null ||
142
+ headerTransparent ||
143
+ // When using a SearchBar or large title, the header needs to be translucent for it to work on iOS
144
+ ((hasHeaderSearchBar || headerLargeTitle) &&
145
+ Platform.OS === 'ios' &&
146
+ headerTransparent !== false);
147
+
127
148
  return (
128
- <ScreenStackHeaderConfig
129
- backButtonInCustomView={backButtonInCustomView}
130
- backgroundColor={
131
- headerStyleFlattened.backgroundColor ??
132
- (headerTransparent ? 'transparent' : colors.card)
133
- }
134
- backTitle={headerBackTitleVisible ? headerBackTitle : ' '}
135
- backTitleFontFamily={backTitleFontFamily}
136
- backTitleFontSize={headerBackTitleStyleFlattened.fontSize}
137
- blurEffect={headerBlurEffect}
138
- color={tintColor}
139
- direction={I18nManager.isRTL ? 'rtl' : 'ltr'}
140
- disableBackButtonMenu={headerBackButtonMenuEnabled === false}
141
- hidden={headerShown === false}
142
- hideBackButton={headerBackVisible === false}
143
- hideShadow={headerShadowVisible === false}
144
- largeTitle={headerLargeTitle}
145
- largeTitleBackgroundColor={headerLargeStyleFlattened.backgroundColor}
146
- largeTitleColor={headerLargeTitleStyleFlattened.color}
147
- largeTitleFontFamily={largeTitleFontFamily}
148
- largeTitleFontSize={headerLargeTitleStyleFlattened.fontSize}
149
- largeTitleFontWeight={headerLargeTitleStyleFlattened.fontWeight}
150
- largeTitleHideShadow={headerLargeTitleShadowVisible === false}
151
- title={typeof headerTitle === 'string' ? headerTitle : titleText}
152
- titleColor={titleColor}
153
- titleFontFamily={titleFontFamily}
154
- titleFontSize={titleFontSize}
155
- titleFontWeight={titleFontWeight}
156
- topInsetEnabled={insets.top !== 0}
157
- translucent={
158
- // This defaults to `true`, so we can't pass `undefined`
159
- headerTransparent === true
160
- }
161
- >
162
- {Platform.OS === 'ios' ? (
163
- <>
164
- {headerLeftElement != null ? (
165
- <ScreenStackHeaderLeftView>
166
- {headerLeftElement}
167
- </ScreenStackHeaderLeftView>
168
- ) : null}
169
- {headerTitleElement != null ? (
170
- <ScreenStackHeaderCenterView>
171
- {headerTitleElement}
172
- </ScreenStackHeaderCenterView>
173
- ) : null}
174
- </>
175
- ) : (
176
- <>
177
- {headerLeftElement != null || typeof headerTitle === 'function' ? (
178
- <ScreenStackHeaderLeftView>
179
- <View style={styles.row}>
180
- {headerLeftElement}
181
- {headerTitleAlign !== 'center' ? (
182
- typeof headerTitle === 'function' ? (
183
- headerTitleElement
184
- ) : (
185
- <HeaderTitle
186
- tintColor={tintColor}
187
- style={headerTitleStyleSupported}
188
- >
189
- {titleText}
190
- </HeaderTitle>
191
- )
192
- ) : null}
193
- </View>
194
- </ScreenStackHeaderLeftView>
195
- ) : null}
196
- {headerTitleAlign === 'center' ? (
197
- <ScreenStackHeaderCenterView>
198
- {typeof headerTitle === 'function' ? (
199
- headerTitleElement
200
- ) : (
201
- <HeaderTitle
202
- tintColor={tintColor}
203
- style={headerTitleStyleSupported}
204
- >
205
- {titleText}
206
- </HeaderTitle>
207
- )}
208
- </ScreenStackHeaderCenterView>
209
- ) : null}
210
- </>
211
- )}
212
- {headerBackImageSource !== undefined ? (
213
- <ScreenStackHeaderBackButtonImage source={headerBackImageSource} />
214
- ) : null}
215
- {headerRightElement != null ? (
216
- <ScreenStackHeaderRightView>
217
- {headerRightElement}
218
- </ScreenStackHeaderRightView>
219
- ) : null}
220
- {Platform.OS === 'ios' && headerSearchBarOptions != null ? (
221
- <ScreenStackHeaderSearchBarView>
222
- <SearchBar {...headerSearchBarOptions} />
223
- </ScreenStackHeaderSearchBarView>
149
+ <>
150
+ {headerBackground != null ? (
151
+ <View
152
+ style={[
153
+ styles.background,
154
+ headerTransparent ? styles.translucent : null,
155
+ { height: headerHeight },
156
+ ]}
157
+ >
158
+ {headerBackground()}
159
+ </View>
224
160
  ) : null}
225
- </ScreenStackHeaderConfig>
161
+ <ScreenStackHeaderConfig
162
+ backButtonInCustomView={backButtonInCustomView}
163
+ backgroundColor={
164
+ headerStyleFlattened.backgroundColor ??
165
+ (headerBackground != null || headerTransparent
166
+ ? 'transparent'
167
+ : colors.card)
168
+ }
169
+ backTitle={headerBackTitleVisible ? headerBackTitle : ' '}
170
+ backTitleFontFamily={backTitleFontFamily}
171
+ backTitleFontSize={headerBackTitleStyleFlattened.fontSize}
172
+ blurEffect={headerBlurEffect}
173
+ color={tintColor}
174
+ direction={I18nManager.isRTL ? 'rtl' : 'ltr'}
175
+ disableBackButtonMenu={headerBackButtonMenuEnabled === false}
176
+ hidden={headerShown === false}
177
+ hideBackButton={headerBackVisible === false}
178
+ hideShadow={
179
+ headerShadowVisible === false ||
180
+ headerBackground != null ||
181
+ headerTransparent
182
+ }
183
+ largeTitle={headerLargeTitle}
184
+ largeTitleBackgroundColor={headerLargeStyleFlattened.backgroundColor}
185
+ largeTitleColor={headerLargeTitleStyleFlattened.color}
186
+ largeTitleFontFamily={largeTitleFontFamily}
187
+ largeTitleFontSize={headerLargeTitleStyleFlattened.fontSize}
188
+ largeTitleFontWeight={headerLargeTitleStyleFlattened.fontWeight}
189
+ largeTitleHideShadow={headerLargeTitleShadowVisible === false}
190
+ title={typeof headerTitle === 'string' ? headerTitle : titleText}
191
+ titleColor={titleColor}
192
+ titleFontFamily={titleFontFamily}
193
+ titleFontSize={titleFontSize}
194
+ titleFontWeight={titleFontWeight}
195
+ topInsetEnabled={insets.top !== 0}
196
+ translucent={
197
+ // This defaults to `true`, so we can't pass `undefined`
198
+ translucent === true
199
+ }
200
+ >
201
+ {Platform.OS === 'ios' ? (
202
+ <>
203
+ {headerLeftElement != null ? (
204
+ <ScreenStackHeaderLeftView>
205
+ {headerLeftElement}
206
+ </ScreenStackHeaderLeftView>
207
+ ) : null}
208
+ {headerTitleElement != null ? (
209
+ <ScreenStackHeaderCenterView>
210
+ {headerTitleElement}
211
+ </ScreenStackHeaderCenterView>
212
+ ) : null}
213
+ </>
214
+ ) : (
215
+ <>
216
+ {headerLeftElement != null || typeof headerTitle === 'function' ? (
217
+ <ScreenStackHeaderLeftView>
218
+ <View style={styles.row}>
219
+ {headerLeftElement}
220
+ {headerTitleAlign !== 'center' ? (
221
+ typeof headerTitle === 'function' ? (
222
+ headerTitleElement
223
+ ) : (
224
+ <HeaderTitle
225
+ tintColor={tintColor}
226
+ style={headerTitleStyleSupported}
227
+ >
228
+ {titleText}
229
+ </HeaderTitle>
230
+ )
231
+ ) : null}
232
+ </View>
233
+ </ScreenStackHeaderLeftView>
234
+ ) : null}
235
+ {headerTitleAlign === 'center' ? (
236
+ <ScreenStackHeaderCenterView>
237
+ {typeof headerTitle === 'function' ? (
238
+ headerTitleElement
239
+ ) : (
240
+ <HeaderTitle
241
+ tintColor={tintColor}
242
+ style={headerTitleStyleSupported}
243
+ >
244
+ {titleText}
245
+ </HeaderTitle>
246
+ )}
247
+ </ScreenStackHeaderCenterView>
248
+ ) : null}
249
+ </>
250
+ )}
251
+ {headerBackImageSource !== undefined ? (
252
+ <ScreenStackHeaderBackButtonImage source={headerBackImageSource} />
253
+ ) : null}
254
+ {headerRightElement != null ? (
255
+ <ScreenStackHeaderRightView>
256
+ {headerRightElement}
257
+ </ScreenStackHeaderRightView>
258
+ ) : null}
259
+ {hasHeaderSearchBar ? (
260
+ <ScreenStackHeaderSearchBarView>
261
+ <SearchBar {...headerSearchBarOptions} />
262
+ </ScreenStackHeaderSearchBarView>
263
+ ) : null}
264
+ </ScreenStackHeaderConfig>
265
+ </>
226
266
  );
227
267
  }
228
268
 
@@ -231,4 +271,14 @@ const styles = StyleSheet.create({
231
271
  flexDirection: 'row',
232
272
  alignItems: 'center',
233
273
  },
274
+ translucent: {
275
+ position: 'absolute',
276
+ top: 0,
277
+ left: 0,
278
+ right: 0,
279
+ zIndex: 1,
280
+ },
281
+ background: {
282
+ overflow: 'hidden',
283
+ },
234
284
  });