@react-navigation/bottom-tabs 8.0.0-alpha.2 → 8.0.0-alpha.21

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 (44) hide show
  1. package/lib/module/navigators/createBottomTabNavigator.js +1 -18
  2. package/lib/module/navigators/createBottomTabNavigator.js.map +1 -1
  3. package/lib/module/utils/useBottomTabAnimation.js +1 -1
  4. package/lib/module/utils/useBottomTabAnimation.js.map +1 -1
  5. package/lib/module/utils/useBottomTabBarHeight.js +1 -1
  6. package/lib/module/utils/useBottomTabBarHeight.js.map +1 -1
  7. package/lib/module/views/BottomTabBar.js +13 -10
  8. package/lib/module/views/BottomTabBar.js.map +1 -1
  9. package/lib/module/views/BottomTabItem.js +1 -1
  10. package/lib/module/views/BottomTabItem.js.map +1 -1
  11. package/lib/module/views/BottomTabViewCustom.js +64 -66
  12. package/lib/module/views/BottomTabViewCustom.js.map +1 -1
  13. package/lib/module/views/BottomTabViewNativeImpl.js +117 -29
  14. package/lib/module/views/BottomTabViewNativeImpl.js.map +1 -1
  15. package/lib/module/views/ScreenContent.js.map +1 -1
  16. package/lib/module/views/TabBarIcon.js +5 -14
  17. package/lib/module/views/TabBarIcon.js.map +1 -1
  18. package/lib/typescript/src/index.d.ts +1 -1
  19. package/lib/typescript/src/index.d.ts.map +1 -1
  20. package/lib/typescript/src/navigators/createBottomTabNavigator.d.ts.map +1 -1
  21. package/lib/typescript/src/types.d.ts +63 -100
  22. package/lib/typescript/src/types.d.ts.map +1 -1
  23. package/lib/typescript/src/views/BottomTabBar.d.ts.map +1 -1
  24. package/lib/typescript/src/views/BottomTabItem.d.ts +16 -16
  25. package/lib/typescript/src/views/BottomTabItem.d.ts.map +1 -1
  26. package/lib/typescript/src/views/BottomTabViewCustom.d.ts +1 -1
  27. package/lib/typescript/src/views/BottomTabViewCustom.d.ts.map +1 -1
  28. package/lib/typescript/src/views/BottomTabViewNativeImpl.d.ts.map +1 -1
  29. package/lib/typescript/src/views/ScreenContent.d.ts +2 -2
  30. package/lib/typescript/src/views/ScreenContent.d.ts.map +1 -1
  31. package/lib/typescript/src/views/TabBarIcon.d.ts +6 -6
  32. package/lib/typescript/src/views/TabBarIcon.d.ts.map +1 -1
  33. package/package.json +16 -17
  34. package/src/index.tsx +0 -1
  35. package/src/navigators/createBottomTabNavigator.tsx +0 -28
  36. package/src/types.tsx +65 -109
  37. package/src/utils/useBottomTabAnimation.tsx +1 -1
  38. package/src/utils/useBottomTabBarHeight.tsx +1 -1
  39. package/src/views/BottomTabBar.tsx +19 -11
  40. package/src/views/BottomTabItem.tsx +17 -19
  41. package/src/views/BottomTabViewCustom.tsx +119 -117
  42. package/src/views/BottomTabViewNativeImpl.tsx +192 -48
  43. package/src/views/ScreenContent.tsx +1 -2
  44. package/src/views/TabBarIcon.tsx +17 -24
package/src/types.tsx CHANGED
@@ -1,11 +1,12 @@
1
1
  import type {
2
2
  HeaderOptions,
3
+ Icon,
3
4
  PlatformPressable,
4
5
  } from '@react-navigation/elements';
6
+ import type { Screen } from '@react-navigation/elements/internal';
5
7
  import type {
6
8
  DefaultNavigatorOptions,
7
9
  Descriptor,
8
- MaterialSymbolProps,
9
10
  NavigationHelpers,
10
11
  NavigationProp,
11
12
  ParamListBase,
@@ -20,7 +21,6 @@ import type {
20
21
  Animated,
21
22
  ColorValue,
22
23
  GestureResponderEvent,
23
- ImageSourcePropType,
24
24
  StyleProp,
25
25
  TextStyle,
26
26
  ViewStyle,
@@ -30,7 +30,6 @@ import type {
30
30
  TabsScreenBlurEffect,
31
31
  TabsSystemItem,
32
32
  } from 'react-native-screens';
33
- import type { SFSymbol } from 'sf-symbols-typescript';
34
33
 
35
34
  export type Variant = 'uikit' | 'material';
36
35
 
@@ -114,79 +113,6 @@ export type TabBarVisibilityAnimationConfig =
114
113
 
115
114
  export type TabAnimationName = 'none' | 'fade' | 'shift';
116
115
 
117
- type IconImage = {
118
- /**
119
- * - `image` - Use a local image as the icon.
120
- */
121
- type: 'image';
122
- /**
123
- * Image source to use as the icon.
124
- * e.g., `require('./path/to/image.png')`
125
- */
126
- source: ImageSourcePropType;
127
- /**
128
- * Whether to apply tint color to the icon.
129
- * Defaults to `true`.
130
- *
131
- * @platform ios
132
- */
133
- tinted?: boolean;
134
- };
135
-
136
- type IconIOSSfSymbol = {
137
- /**
138
- * - `sfSymbol` - Use an SF Symbol as the icon on iOS.
139
- */
140
- type: 'sfSymbol';
141
- /**
142
- * Name of the SF Symbol to use as the icon.
143
- *
144
- * @platform ios
145
- */
146
- name: SFSymbol;
147
- };
148
-
149
- type IconMaterialSymbol = {
150
- /**
151
- * - `materialSymbol` - Use a Material Symbol as the icon on Android.
152
- */
153
- type: 'materialSymbol';
154
- /**
155
- * Name of the Material Symbol to use as the icon.
156
- *
157
- * @platform android
158
- */
159
- name: MaterialSymbolProps['name'];
160
- };
161
-
162
- type IconAndroidDrawable = {
163
- /**
164
- * - `drawableResource` - Use a drawable resource as the icon on Android.
165
- */
166
- type: 'drawableResource';
167
- /**
168
- * Name of the drawable resource to use as the icon.
169
- *
170
- * @platform android
171
- */
172
- name: string;
173
- /**
174
- * Whether to apply tint color to the icon.
175
- * Only supported with custom implementation.
176
- *
177
- * Defaults to `true`.
178
- *
179
- * @platform android
180
- */
181
- tinted?: boolean;
182
- };
183
-
184
- type IconIOS = IconIOSSfSymbol | IconImage;
185
-
186
- type IconAndroid = IconMaterialSymbol | IconAndroidDrawable | IconImage;
187
-
188
- export type BottomTabIcon = IconIOS | IconAndroid;
189
-
190
116
  type BottomTabCustomOptions = {
191
117
  /**
192
118
  * How the screen should animate when switching tabs.
@@ -224,7 +150,7 @@ type BottomTabCustomOptions = {
224
150
  *
225
151
  * Only supported with `custom` implementation.
226
152
  */
227
- tabBarLabelPosition?: LabelPosition;
153
+ tabBarLabelPosition?: LabelPosition | undefined;
228
154
 
229
155
  /**
230
156
  * Whether label font should scale to respect Text Size accessibility settings.
@@ -235,21 +161,6 @@ type BottomTabCustomOptions = {
235
161
  */
236
162
  tabBarAllowFontScaling?: boolean;
237
163
 
238
- /**
239
- * Accessibility label for the tab button. This is read by the screen reader when the user taps the tab.
240
- * It's recommended to set this if you don't have a label for the tab.
241
- *
242
- * Only supported with `custom` implementation.
243
- */
244
- tabBarAccessibilityLabel?: string;
245
-
246
- /**
247
- * ID to locate this tab button in tests.
248
- *
249
- * Only supported with `custom` implementation.
250
- */
251
- tabBarButtonTestID?: string;
252
-
253
164
  /**
254
165
  * Style object for the tab item container.
255
166
  *
@@ -467,6 +378,27 @@ type BottomTabNativeOptions = {
467
378
  right?: ScrollEdgeEffect;
468
379
  top?: ScrollEdgeEffect;
469
380
  };
381
+
382
+ /**
383
+ * Specifies whether `contentInsetAdjustmentBehavior` of the `ScrollView`
384
+ * in the screen is automatically adjusted.
385
+ *
386
+ * `react-native`'s `ScrollView`s has `contentInsetAdjustmentBehavior` set to `never` by default.
387
+ * To provide a better UX, it is overridden to `automatic` - so it respects the tab bar.
388
+ * Otherwise, content can get hidden behind the tab bar as it's translucent on iOS 26+.
389
+ *
390
+ * Note that this only affects the `ScrollView` in first descendant chain of the screen,
391
+ * i.e., first view of each nested view is checked until a `ScrollView` is found.
392
+ *
393
+ * To disable this behavior for specific screens, set this option to `false`.
394
+ *
395
+ * Only supported with `native` implementation.
396
+ *
397
+ * Defaults to `true`.
398
+ *
399
+ * @platform ios
400
+ */
401
+ overrideScrollViewContentInsetAdjustmentBehavior?: boolean;
470
402
  };
471
403
 
472
404
  export type BottomTabNavigationOptions = {
@@ -508,7 +440,7 @@ export type BottomTabNavigationOptions = {
508
440
  */
509
441
  tabBarLabelStyle?: Pick<
510
442
  TextStyle,
511
- 'fontFamily' | 'fontSize' | 'fontWeight' | 'fontStyle'
443
+ 'fontFamily' | 'fontSize' | 'fontWeight' | 'fontStyle' | 'color'
512
444
  >;
513
445
 
514
446
  /**
@@ -520,26 +452,30 @@ export type BottomTabNavigationOptions = {
520
452
  * - on all platforms with `custom` implementation
521
453
  * - on iOS with `native` implementation
522
454
  *
455
+ * With `native` implementation, `tinted` for `image` can only be disabled on iOS.
456
+ *
523
457
  * A React element is only supported with `custom` implementation.
524
458
  */
525
459
  tabBarIcon?:
526
- | BottomTabIcon
460
+ | Icon
527
461
  | ((props: {
528
462
  focused: boolean;
529
463
  color: ColorValue;
530
464
  size: number;
531
- }) => BottomTabIcon | React.ReactNode);
465
+ }) => Icon | React.ReactNode);
532
466
 
533
467
  /**
534
468
  * Text to show in a badge on the tab icon.
535
469
  */
536
- tabBarBadge?: number | string;
470
+ tabBarBadge?: number | string | undefined;
537
471
 
538
472
  /**
539
473
  * Custom style for the tab bar badge.
540
474
  * You can specify a background color or text color here.
541
475
  *
542
- * @platform android
476
+ * With `native` implementation, limited customization is supported:
477
+ * - on iOS, you can only set the background color.
478
+ * - on Android, you can set both background and text colors.
543
479
  */
544
480
  tabBarBadgeStyle?: {
545
481
  backgroundColor?: ColorValue;
@@ -549,7 +485,7 @@ export type BottomTabNavigationOptions = {
549
485
  /**
550
486
  * Color for the icon and label in the active tab.
551
487
  */
552
- tabBarActiveTintColor?: ColorValue;
488
+ tabBarActiveTintColor?: ColorValue | undefined;
553
489
 
554
490
  /**
555
491
  * Color for the icon and label in the inactive tabs.
@@ -582,6 +518,17 @@ export type BottomTabNavigationOptions = {
582
518
  */
583
519
  tabBarControllerMode?: 'auto' | 'tabBar' | 'tabSidebar';
584
520
 
521
+ /**
522
+ * Accessibility label for the tab button. This is read by the screen reader when the user taps the tab.
523
+ * It's recommended to set this if you don't have a label for the tab.
524
+ */
525
+ tabBarAccessibilityLabel?: string;
526
+
527
+ /**
528
+ * ID to locate this tab button in tests.
529
+ */
530
+ tabBarButtonTestID?: string;
531
+
585
532
  /**
586
533
  * Style object for the tab bar container.
587
534
  */
@@ -598,6 +545,11 @@ export type BottomTabNavigationOptions = {
598
545
  * Only supported on iOS 18 and below.
599
546
  */
600
547
  shadowColor?: ColorValue;
548
+ /**
549
+ * Whether the tab bar is visible.
550
+ * Setting this to `'none'` hides the tab bar.
551
+ */
552
+ display?: 'flex' | 'none';
601
553
  };
602
554
 
603
555
  /**
@@ -615,7 +567,7 @@ export type BottomTabNavigationOptions = {
615
567
  /**
616
568
  * Style object for the component wrapping the screen content.
617
569
  */
618
- sceneStyle?: StyleProp<ViewStyle>;
570
+ sceneStyle?: React.ComponentProps<typeof Screen>['style'];
619
571
 
620
572
  /**
621
573
  * Function that returns a React Element to display as a header.
@@ -628,6 +580,19 @@ export type BottomTabNavigationOptions = {
628
580
  * Defaults to `false` unless a header is provided.
629
581
  */
630
582
  headerShown?: boolean;
583
+
584
+ /**
585
+ * What should happen when screens become inactive.
586
+ * - `pause`: Effects are cleaned up.
587
+ * - `none`: Screen renders normally
588
+ *
589
+ * Defaults to `pause`.
590
+ *
591
+ * If you set `lazy: false` or preload a screen,
592
+ * It won't be paused until after the first time it becomes focused.
593
+ * This makes sure that effects are run to initialize the screen.
594
+ */
595
+ inactiveBehavior?: 'pause' | 'none';
631
596
  } & HeaderOptions &
632
597
  BottomTabNativeOptions &
633
598
  BottomTabCustomOptions;
@@ -718,15 +683,6 @@ export type BottomTabNavigationConfig = {
718
683
  * Function that returns a React element to display as the tab bar.
719
684
  */
720
685
  tabBar?: (props: BottomTabBarProps) => React.ReactNode;
721
-
722
- /**
723
- * Whether inactive screens should be detached from the view hierarchy to save memory.
724
- *
725
- * Defaults to `true`.
726
- *
727
- * Only supported with `custom` implementation.
728
- */
729
- detachInactiveScreens?: boolean;
730
686
  };
731
687
 
732
688
  export type BottomTabHeaderProps = {
@@ -754,7 +710,7 @@ export type BottomTabBarButtonProps = Omit<
754
710
  React.ComponentProps<typeof PlatformPressable>,
755
711
  'style'
756
712
  > & {
757
- href?: string;
713
+ href?: string | undefined;
758
714
  children: React.ReactNode;
759
715
  style?: StyleProp<ViewStyle>;
760
716
  onPress?: (
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import { BottomTabAnimationContext } from './BottomTabAnimationContext';
4
4
 
5
5
  export function useBottomTabAnimation() {
6
- const animation = React.useContext(BottomTabAnimationContext);
6
+ const animation = React.use(BottomTabAnimationContext);
7
7
 
8
8
  if (animation === undefined) {
9
9
  throw new Error(
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import { BottomTabBarHeightContext } from './BottomTabBarHeightContext';
4
4
 
5
5
  export function useBottomTabBarHeight() {
6
- const height = React.useContext(BottomTabBarHeightContext);
6
+ const height = React.use(BottomTabBarHeightContext);
7
7
 
8
8
  if (height === undefined) {
9
9
  throw new Error(
@@ -207,7 +207,7 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
207
207
  const insets = useSafeAreaInsets();
208
208
  const isKeyboardShown = useIsKeyboardShown();
209
209
 
210
- const onHeightChange = React.useContext(BottomTabBarHeightCallbackContext);
210
+ const onHeightChange = React.use(BottomTabBarHeightCallbackContext);
211
211
 
212
212
  const shouldShowTabBar = !(tabBarHideOnKeyboard && isKeyboardShown);
213
213
 
@@ -228,18 +228,22 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
228
228
  React.useEffect(() => {
229
229
  const visibilityAnimationConfig = visibilityAnimationConfigRef.current;
230
230
 
231
+ let animation;
232
+
231
233
  if (shouldShowTabBar) {
232
- const animation =
234
+ const animate =
233
235
  visibilityAnimationConfig?.show?.animation === 'spring'
234
236
  ? Animated.spring
235
237
  : Animated.timing;
236
238
 
237
- animation(visible, {
239
+ animation = animate(visible, {
238
240
  toValue: 1,
239
241
  useNativeDriver,
240
242
  duration: 250,
241
243
  ...visibilityAnimationConfig?.show?.config,
242
- }).start(({ finished }) => {
244
+ });
245
+
246
+ animation.start(({ finished }) => {
243
247
  if (finished) {
244
248
  setIsTabBarHidden(false);
245
249
  }
@@ -248,20 +252,22 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
248
252
  // eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
249
253
  setIsTabBarHidden(true);
250
254
 
251
- const animation =
255
+ const animate =
252
256
  visibilityAnimationConfig?.hide?.animation === 'spring'
253
257
  ? Animated.spring
254
258
  : Animated.timing;
255
259
 
256
- animation(visible, {
260
+ animation = animate(visible, {
257
261
  toValue: 0,
258
262
  useNativeDriver,
259
263
  duration: 200,
260
264
  ...visibilityAnimationConfig?.hide?.config,
261
- }).start();
265
+ });
266
+
267
+ animation.start();
262
268
  }
263
269
 
264
- return () => visible.stopAnimation();
270
+ return () => animation.stop();
265
271
  }, [visible, shouldShowTabBar]);
266
272
 
267
273
  const [layout, setLayout] = React.useState({
@@ -343,7 +349,7 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
343
349
  : { borderTopWidth: StyleSheet.hairlineWidth },
344
350
  {
345
351
  backgroundColor:
346
- tabBarBackgroundElement != null ? 'transparent' : colors.card,
352
+ tabBarBackgroundElement != null ? 'transparent' : colors.background,
347
353
  borderColor: colors.border,
348
354
  },
349
355
  sidebar
@@ -435,8 +441,10 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
435
441
  const accessibilityLabel =
436
442
  options.tabBarAccessibilityLabel !== undefined
437
443
  ? options.tabBarAccessibilityLabel
438
- : typeof label === 'string' && Platform.OS === 'ios'
439
- ? `${label}, tab, ${index + 1} of ${routes.length}`
444
+ : typeof label === 'string'
445
+ ? Platform.OS === 'android'
446
+ ? `${label}, ${index + 1} of ${routes.length}`
447
+ : `${label}, ${focused ? 'selected' : 'unselected'}`
440
448
  : undefined;
441
449
 
442
450
  return (
@@ -29,7 +29,7 @@ type Props = {
29
29
  /**
30
30
  * The `href` to use for the anchor tag on web
31
31
  */
32
- href?: string;
32
+ href?: string | undefined;
33
33
  /**
34
34
  * Whether the tab is focused.
35
35
  */
@@ -56,23 +56,23 @@ type Props = {
56
56
  /**
57
57
  * Text to show in a badge on the tab icon.
58
58
  */
59
- badge?: number | string;
59
+ badge?: number | string | undefined;
60
60
  /**
61
61
  * Custom style for the badge.
62
62
  */
63
- badgeStyle?: StyleProp<TextStyle>;
63
+ badgeStyle?: StyleProp<TextStyle> | undefined;
64
64
  /**
65
65
  * The button for the tab. Uses a `Pressable` by default.
66
66
  */
67
- button?: (props: BottomTabBarButtonProps) => React.ReactNode;
67
+ button?: ((props: BottomTabBarButtonProps) => React.ReactNode) | undefined;
68
68
  /**
69
69
  * The accessibility label for the tab.
70
70
  */
71
- accessibilityLabel?: string;
71
+ accessibilityLabel?: string | undefined;
72
72
  /**
73
73
  * An unique ID for testing for the tab.
74
74
  */
75
- testID?: string;
75
+ testID?: string | undefined;
76
76
  /**
77
77
  * Function to execute on press in React Native.
78
78
  * On the web, this will use onClick.
@@ -105,44 +105,44 @@ type Props = {
105
105
  /**
106
106
  * Color for the icon and label when the item is active.
107
107
  */
108
- activeTintColor?: ColorValue;
108
+ activeTintColor?: ColorValue | undefined;
109
109
  /**
110
110
  * Color for the icon and label when the item is inactive.
111
111
  */
112
- inactiveTintColor?: ColorValue;
112
+ inactiveTintColor?: ColorValue | undefined;
113
113
  /**
114
114
  * Background color for item when its active.
115
115
  */
116
- activeBackgroundColor?: ColorValue;
116
+ activeBackgroundColor?: ColorValue | undefined;
117
117
  /**
118
118
  * Background color for item when its inactive.
119
119
  */
120
- inactiveBackgroundColor?: ColorValue;
120
+ inactiveBackgroundColor?: ColorValue | undefined;
121
121
  /**
122
122
  * Color of tab bar item's ripple effect.
123
123
  */
124
- rippleColor?: ColorValue;
124
+ rippleColor?: ColorValue | undefined;
125
125
  /**
126
126
  * Label visibility mode for the tab bar item.
127
127
  */
128
- labelVisibilityMode?: TabBarItemLabelVisibilityMode;
128
+ labelVisibilityMode?: TabBarItemLabelVisibilityMode | undefined;
129
129
  /**
130
130
  * Whether to allow scaling the font for the label for accessibility purposes.
131
131
  * Defaults to `false` on iOS 13+ where it uses `largeContentTitle`.
132
132
  */
133
- allowFontScaling?: boolean;
133
+ allowFontScaling?: boolean | undefined;
134
134
  /**
135
135
  * Style object for the label element.
136
136
  */
137
- labelStyle?: StyleProp<TextStyle>;
137
+ labelStyle?: StyleProp<TextStyle> | undefined;
138
138
  /**
139
139
  * Style object for the icon element.
140
140
  */
141
- iconStyle?: StyleProp<ViewStyle>;
141
+ iconStyle?: StyleProp<ViewStyle> | undefined;
142
142
  /**
143
143
  * Style object for the wrapper element.
144
144
  */
145
- style?: StyleProp<ViewStyle>;
145
+ style?: StyleProp<ViewStyle> | undefined;
146
146
  };
147
147
 
148
148
  const renderButtonDefault = (props: BottomTabBarButtonProps) => (
@@ -189,9 +189,7 @@ export function BottomTabItem({
189
189
  const activeTintColor: ColorValue =
190
190
  customActiveTintColor ??
191
191
  (variant === 'uikit' && sidebar && horizontal
192
- ? Color(colors.primary)?.isDark()
193
- ? 'white'
194
- : (Color(colors.primary)?.darken(0.71).string() ?? 'white')
192
+ ? Color.foreground(colors.primary)
195
193
  : colors.primary);
196
194
 
197
195
  const inactiveTintColor: ColorValue =