@react-navigation/bottom-tabs 8.0.0-alpha.5 → 8.0.0-alpha.50

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 (84) hide show
  1. package/lib/module/index.js +1 -1
  2. package/lib/module/index.js.map +1 -1
  3. package/lib/module/navigators/createBottomTabNavigator.js +4 -25
  4. package/lib/module/navigators/createBottomTabNavigator.js.map +1 -1
  5. package/lib/module/utils/useBottomTabAnimation.js +1 -1
  6. package/lib/module/utils/useBottomTabAnimation.js.map +1 -1
  7. package/lib/module/utils/useBottomTabBarHeight.js +1 -1
  8. package/lib/module/utils/useBottomTabBarHeight.js.map +1 -1
  9. package/lib/module/utils/useIsKeyboardShown.js.map +1 -1
  10. package/lib/module/views/BottomTabBar.js +40 -29
  11. package/lib/module/views/BottomTabBar.js.map +1 -1
  12. package/lib/module/views/BottomTabItem.js +3 -5
  13. package/lib/module/views/BottomTabItem.js.map +1 -1
  14. package/lib/module/views/{BottomTabViewCommon.js → BottomTabView.js} +1 -1
  15. package/lib/module/views/BottomTabView.js.map +1 -0
  16. package/lib/module/views/BottomTabViewCustom.js +97 -81
  17. package/lib/module/views/BottomTabViewCustom.js.map +1 -1
  18. package/lib/module/views/BottomTabViewNativeImpl.js +339 -121
  19. package/lib/module/views/BottomTabViewNativeImpl.js.map +1 -1
  20. package/lib/module/views/Deferred.js +41 -0
  21. package/lib/module/views/Deferred.js.map +1 -0
  22. package/lib/module/views/ScreenContent.js.map +1 -1
  23. package/lib/module/views/TabBarIcon.js +11 -48
  24. package/lib/module/views/TabBarIcon.js.map +1 -1
  25. package/lib/typescript/src/TransitionConfigs/SceneStyleInterpolators.d.ts +1 -1
  26. package/lib/typescript/src/TransitionConfigs/SceneStyleInterpolators.d.ts.map +1 -1
  27. package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts +1 -1
  28. package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts.map +1 -1
  29. package/lib/typescript/src/TransitionConfigs/TransitionSpecs.d.ts +1 -1
  30. package/lib/typescript/src/TransitionConfigs/TransitionSpecs.d.ts.map +1 -1
  31. package/lib/typescript/src/index.d.ts +11 -11
  32. package/lib/typescript/src/index.d.ts.map +1 -1
  33. package/lib/typescript/src/navigators/createBottomTabNavigator.d.ts +9 -15
  34. package/lib/typescript/src/navigators/createBottomTabNavigator.d.ts.map +1 -1
  35. package/lib/typescript/src/types.d.ts +66 -104
  36. package/lib/typescript/src/types.d.ts.map +1 -1
  37. package/lib/typescript/src/utils/BottomTabAnimationContext.d.ts +1 -1
  38. package/lib/typescript/src/utils/BottomTabAnimationContext.d.ts.map +1 -1
  39. package/lib/typescript/src/utils/useAnimatedHashMap.d.ts +1 -1
  40. package/lib/typescript/src/utils/useAnimatedHashMap.d.ts.map +1 -1
  41. package/lib/typescript/src/utils/useBottomTabAnimation.d.ts +1 -1
  42. package/lib/typescript/src/utils/useBottomTabAnimation.d.ts.map +1 -1
  43. package/lib/typescript/src/utils/useTabBarPosition.d.ts +1 -1
  44. package/lib/typescript/src/utils/useTabBarPosition.d.ts.map +1 -1
  45. package/lib/typescript/src/views/BottomTabBar.d.ts +3 -2
  46. package/lib/typescript/src/views/BottomTabBar.d.ts.map +1 -1
  47. package/lib/typescript/src/views/BottomTabItem.d.ts +20 -20
  48. package/lib/typescript/src/views/BottomTabItem.d.ts.map +1 -1
  49. package/lib/typescript/src/views/{BottomTabViewCommon.d.ts → BottomTabView.d.ts} +3 -3
  50. package/lib/typescript/src/views/BottomTabView.d.ts.map +1 -0
  51. package/lib/typescript/src/views/BottomTabViewCustom.d.ts +3 -2
  52. package/lib/typescript/src/views/BottomTabViewCustom.d.ts.map +1 -1
  53. package/lib/typescript/src/views/BottomTabViewNative.android.d.ts +1 -1
  54. package/lib/typescript/src/views/BottomTabViewNative.android.d.ts.map +1 -1
  55. package/lib/typescript/src/views/BottomTabViewNative.d.ts +1 -1
  56. package/lib/typescript/src/views/BottomTabViewNative.d.ts.map +1 -1
  57. package/lib/typescript/src/views/BottomTabViewNative.ios.d.ts +1 -1
  58. package/lib/typescript/src/views/BottomTabViewNative.ios.d.ts.map +1 -1
  59. package/lib/typescript/src/views/BottomTabViewNativeImpl.d.ts +3 -2
  60. package/lib/typescript/src/views/BottomTabViewNativeImpl.d.ts.map +1 -1
  61. package/lib/typescript/src/views/Deferred.d.ts +31 -0
  62. package/lib/typescript/src/views/Deferred.d.ts.map +1 -0
  63. package/lib/typescript/src/views/ScreenContent.d.ts +4 -4
  64. package/lib/typescript/src/views/ScreenContent.d.ts.map +1 -1
  65. package/lib/typescript/src/views/TabBarIcon.d.ts +8 -8
  66. package/lib/typescript/src/views/TabBarIcon.d.ts.map +1 -1
  67. package/package.json +22 -22
  68. package/src/index.tsx +2 -2
  69. package/src/navigators/createBottomTabNavigator.tsx +10 -75
  70. package/src/types.tsx +66 -112
  71. package/src/utils/useAnimatedHashMap.tsx +1 -1
  72. package/src/utils/useBottomTabAnimation.tsx +1 -1
  73. package/src/utils/useBottomTabBarHeight.tsx +1 -1
  74. package/src/utils/useIsKeyboardShown.tsx +2 -2
  75. package/src/views/BottomTabBar.tsx +68 -25
  76. package/src/views/BottomTabItem.tsx +19 -21
  77. package/src/views/BottomTabViewCustom.tsx +172 -143
  78. package/src/views/BottomTabViewNativeImpl.tsx +480 -161
  79. package/src/views/Deferred.tsx +57 -0
  80. package/src/views/ScreenContent.tsx +1 -2
  81. package/src/views/TabBarIcon.tsx +13 -56
  82. package/lib/module/views/BottomTabViewCommon.js.map +0 -1
  83. package/lib/typescript/src/views/BottomTabViewCommon.d.ts.map +0 -1
  84. /package/src/views/{BottomTabViewCommon.tsx → BottomTabView.tsx} +0 -0
@@ -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(
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { type EmitterSubscription, Keyboard, Platform } from 'react-native';
2
+ import { Keyboard, Platform } from 'react-native';
3
3
 
4
4
  export function useIsKeyboardShown() {
5
5
  const [isKeyboardShown, setIsKeyboardShown] = React.useState(false);
@@ -8,7 +8,7 @@ export function useIsKeyboardShown() {
8
8
  const handleKeyboardShow = () => setIsKeyboardShown(true);
9
9
  const handleKeyboardHide = () => setIsKeyboardShown(false);
10
10
 
11
- let subscriptions: EmitterSubscription[];
11
+ let subscriptions: ReturnType<typeof Keyboard.addListener>[];
12
12
 
13
13
  if (Platform.OS === 'ios') {
14
14
  subscriptions = [
@@ -12,7 +12,7 @@ import {
12
12
  useLocale,
13
13
  useTheme,
14
14
  } from '@react-navigation/native';
15
- import React from 'react';
15
+ import * as React from 'react';
16
16
  import {
17
17
  Animated,
18
18
  type LayoutChangeEvent,
@@ -57,8 +57,11 @@ const shouldUseHorizontalLabels = ({
57
57
  }: Options & {
58
58
  dimensions: { height: number; width: number };
59
59
  }) => {
60
- const { tabBarLabelPosition } =
61
- descriptors[state.routes[state.index].key].options;
60
+ const focusedRoute = state.routes[state.index];
61
+ const tabBarLabelPosition =
62
+ focusedRoute == null
63
+ ? undefined
64
+ : descriptors[focusedRoute.key]?.options.tabBarLabelPosition;
62
65
 
63
66
  if (tabBarLabelPosition) {
64
67
  switch (tabBarLabelPosition) {
@@ -72,8 +75,9 @@ const shouldUseHorizontalLabels = ({
72
75
  if (dimensions.width >= 768) {
73
76
  // Screen size matches a tablet
74
77
  const maxTabWidth = state.routes.reduce((acc, route) => {
75
- const { tabBarItemStyle } = descriptors[route.key].options;
76
- const flattenedStyle = StyleSheet.flatten(tabBarItemStyle);
78
+ const flattenedStyle = StyleSheet.flatten(
79
+ descriptors[route.key]?.options.tabBarItemStyle
80
+ );
77
81
 
78
82
  if (flattenedStyle) {
79
83
  if (typeof flattenedStyle.width === 'number') {
@@ -97,8 +101,9 @@ const isCompact = ({
97
101
  descriptors,
98
102
  dimensions,
99
103
  }: Options & { dimensions: { height: number; width: number } }): boolean => {
104
+ const focusedRoute = state.routes[state.index];
100
105
  const { tabBarPosition, tabBarVariant } =
101
- descriptors[state.routes[state.index].key].options;
106
+ focusedRoute == null ? {} : (descriptors[focusedRoute.key]?.options ?? {});
102
107
 
103
108
  if (
104
109
  tabBarPosition === 'left' ||
@@ -138,7 +143,11 @@ export const getTabBarHeight = ({
138
143
  dimensions: { height: number; width: number };
139
144
  style: Animated.WithAnimatedValue<StyleProp<ViewStyle>> | undefined;
140
145
  }) => {
141
- const { tabBarPosition } = descriptors[state.routes[state.index].key].options;
146
+ const focusedRoute = state.routes[state.index];
147
+ const tabBarPosition =
148
+ focusedRoute == null
149
+ ? undefined
150
+ : descriptors[focusedRoute.key]?.options.tabBarPosition;
142
151
 
143
152
  const flattenedStyle = StyleSheet.flatten(style);
144
153
  const customHeight =
@@ -165,7 +174,19 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
165
174
  const { buildHref } = useLinkBuilder();
166
175
 
167
176
  const focusedRoute = state.routes[state.index];
177
+
178
+ if (focusedRoute == null) {
179
+ throw new Error(`Couldn't find a route at index ${state.index}.`);
180
+ }
181
+
168
182
  const focusedDescriptor = descriptors[focusedRoute.key];
183
+
184
+ if (focusedDescriptor == null) {
185
+ throw new Error(
186
+ `Couldn't find a descriptor for route '${focusedRoute.key}'.`
187
+ );
188
+ }
189
+
169
190
  const focusedOptions = focusedDescriptor.options;
170
191
 
171
192
  const {
@@ -207,7 +228,7 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
207
228
  const insets = useSafeAreaInsets();
208
229
  const isKeyboardShown = useIsKeyboardShown();
209
230
 
210
- const onHeightChange = React.useContext(BottomTabBarHeightCallbackContext);
231
+ const onHeightChange = React.use(BottomTabBarHeightCallbackContext);
211
232
 
212
233
  const shouldShowTabBar = !(tabBarHideOnKeyboard && isKeyboardShown);
213
234
 
@@ -228,18 +249,22 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
228
249
  React.useEffect(() => {
229
250
  const visibilityAnimationConfig = visibilityAnimationConfigRef.current;
230
251
 
252
+ let animation;
253
+
231
254
  if (shouldShowTabBar) {
232
- const animation =
255
+ const animate =
233
256
  visibilityAnimationConfig?.show?.animation === 'spring'
234
257
  ? Animated.spring
235
258
  : Animated.timing;
236
259
 
237
- animation(visible, {
260
+ animation = animate(visible, {
238
261
  toValue: 1,
239
262
  useNativeDriver,
240
263
  duration: 250,
241
264
  ...visibilityAnimationConfig?.show?.config,
242
- }).start(({ finished }) => {
265
+ });
266
+
267
+ animation.start(({ finished }) => {
243
268
  if (finished) {
244
269
  setIsTabBarHidden(false);
245
270
  }
@@ -248,20 +273,22 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
248
273
  // eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
249
274
  setIsTabBarHidden(true);
250
275
 
251
- const animation =
276
+ const animate =
252
277
  visibilityAnimationConfig?.hide?.animation === 'spring'
253
278
  ? Animated.spring
254
279
  : Animated.timing;
255
280
 
256
- animation(visible, {
281
+ animation = animate(visible, {
257
282
  toValue: 0,
258
283
  useNativeDriver,
259
284
  duration: 200,
260
285
  ...visibilityAnimationConfig?.hide?.config,
261
- }).start();
286
+ });
287
+
288
+ animation.start();
262
289
  }
263
290
 
264
- return () => visible.stopAnimation();
291
+ return () => animation.stop();
265
292
  }, [visible, shouldShowTabBar]);
266
293
 
267
294
  const [layout, setLayout] = React.useState({
@@ -343,7 +370,7 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
343
370
  : { borderTopWidth: StyleSheet.hairlineWidth },
344
371
  {
345
372
  backgroundColor:
346
- tabBarBackgroundElement != null ? 'transparent' : colors.card,
373
+ tabBarBackgroundElement != null ? 'transparent' : colors.background,
347
374
  borderColor: colors.border,
348
375
  },
349
376
  sidebar
@@ -400,7 +427,15 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
400
427
  >
401
428
  {routes.map((route, index) => {
402
429
  const focused = index === state.index;
403
- const { options } = descriptors[route.key];
430
+ const descriptor = descriptors[route.key];
431
+
432
+ if (descriptor == null) {
433
+ throw new Error(
434
+ `Couldn't find a descriptor for route '${route.key}'.`
435
+ );
436
+ }
437
+
438
+ const { options } = descriptor;
404
439
 
405
440
  const onPress = () => {
406
441
  const event = navigation.emit({
@@ -409,10 +444,16 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
409
444
  canPreventDefault: true,
410
445
  });
411
446
 
412
- if (!focused && !event.defaultPrevented) {
413
- navigation.dispatch({
414
- ...CommonActions.navigate(route),
415
- target: state.key,
447
+ if (
448
+ !focused &&
449
+ !event.defaultPrevented &&
450
+ options.tabBarSelectionEnabled !== false
451
+ ) {
452
+ React.startTransition(() => {
453
+ navigation.dispatch({
454
+ ...CommonActions.navigate(route.name, route.params),
455
+ target: state.key,
456
+ });
416
457
  });
417
458
  }
418
459
  };
@@ -435,20 +476,22 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
435
476
  const accessibilityLabel =
436
477
  options.tabBarAccessibilityLabel !== undefined
437
478
  ? options.tabBarAccessibilityLabel
438
- : typeof label === 'string' && Platform.OS === 'ios'
439
- ? `${label}, tab, ${index + 1} of ${routes.length}`
479
+ : typeof label === 'string'
480
+ ? Platform.OS === 'android'
481
+ ? `${label}, ${index + 1} of ${routes.length}`
482
+ : `${label}, ${focused ? 'selected' : 'unselected'}`
440
483
  : undefined;
441
484
 
442
485
  return (
443
486
  <NavigationProvider
444
487
  key={route.key}
445
- navigation={descriptors[route.key].navigation}
488
+ navigation={descriptor.navigation}
446
489
  route={route}
447
490
  >
448
491
  <BottomTabItem
449
492
  href={buildHref(route.name, route.params)}
450
493
  route={route}
451
- descriptor={descriptors[route.key]}
494
+ descriptor={descriptor}
452
495
  focused={focused}
453
496
  horizontal={hasHorizontalLabels}
454
497
  compact={compact}
@@ -1,7 +1,7 @@
1
1
  import { getLabel, Label, PlatformPressable } from '@react-navigation/elements';
2
2
  import { Color } from '@react-navigation/elements/internal';
3
3
  import { type Route, useTheme } from '@react-navigation/native';
4
- import React from 'react';
4
+ import * as React from 'react';
5
5
  import {
6
6
  type ColorValue,
7
7
  type GestureResponderEvent,
@@ -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 =
@@ -311,7 +309,7 @@ export function BottomTabItem({
311
309
  ? activeBackgroundColor
312
310
  : inactiveBackgroundColor;
313
311
 
314
- const { flex } = StyleSheet.flatten(style || {});
312
+ const flex = StyleSheet.flatten(style)?.flex;
315
313
  const borderRadius =
316
314
  variant === 'material'
317
315
  ? horizontal