@react-navigation/bottom-tabs 7.0.0-rc.8 → 7.0.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 (148) hide show
  1. package/lib/commonjs/TransitionConfigs/TransitionPresets.js +2 -2
  2. package/lib/commonjs/index.js +9 -9
  3. package/lib/commonjs/navigators/createBottomTabNavigator.js +10 -12
  4. package/lib/commonjs/navigators/createBottomTabNavigator.js.map +1 -1
  5. package/lib/commonjs/package.json +1 -0
  6. package/lib/commonjs/utils/useBottomTabBarHeight.js +1 -1
  7. package/lib/commonjs/views/Badge.js +6 -4
  8. package/lib/commonjs/views/Badge.js.map +1 -1
  9. package/lib/commonjs/views/BottomTabBar.js +149 -110
  10. package/lib/commonjs/views/BottomTabBar.js.map +1 -1
  11. package/lib/commonjs/views/BottomTabItem.js +99 -59
  12. package/lib/commonjs/views/BottomTabItem.js.map +1 -1
  13. package/lib/commonjs/views/BottomTabView.js +124 -100
  14. package/lib/commonjs/views/BottomTabView.js.map +1 -1
  15. package/lib/commonjs/views/ScreenFallback.js +15 -9
  16. package/lib/commonjs/views/ScreenFallback.js.map +1 -1
  17. package/lib/commonjs/views/TabBarIcon.js +59 -37
  18. package/lib/commonjs/views/TabBarIcon.js.map +1 -1
  19. package/lib/module/TransitionConfigs/SceneStyleInterpolators.js +2 -0
  20. package/lib/module/TransitionConfigs/SceneStyleInterpolators.js.map +1 -1
  21. package/lib/module/TransitionConfigs/TransitionPresets.js +4 -2
  22. package/lib/module/TransitionConfigs/TransitionPresets.js.map +1 -1
  23. package/lib/module/TransitionConfigs/TransitionSpecs.js +2 -0
  24. package/lib/module/TransitionConfigs/TransitionSpecs.js.map +1 -1
  25. package/lib/module/index.js +11 -9
  26. package/lib/module/index.js.map +1 -1
  27. package/lib/module/navigators/createBottomTabNavigator.js +12 -10
  28. package/lib/module/navigators/createBottomTabNavigator.js.map +1 -1
  29. package/lib/module/package.json +1 -0
  30. package/lib/module/types.js +2 -0
  31. package/lib/module/utils/BottomTabBarHeightCallbackContext.js +2 -0
  32. package/lib/module/utils/BottomTabBarHeightCallbackContext.js.map +1 -1
  33. package/lib/module/utils/BottomTabBarHeightContext.js +2 -0
  34. package/lib/module/utils/BottomTabBarHeightContext.js.map +1 -1
  35. package/lib/module/utils/useAnimatedHashMap.js +2 -0
  36. package/lib/module/utils/useAnimatedHashMap.js.map +1 -1
  37. package/lib/module/utils/useBottomTabBarHeight.js +3 -1
  38. package/lib/module/utils/useBottomTabBarHeight.js.map +1 -1
  39. package/lib/module/utils/useIsKeyboardShown.js +2 -0
  40. package/lib/module/utils/useIsKeyboardShown.js.map +1 -1
  41. package/lib/module/views/Badge.js +8 -4
  42. package/lib/module/views/Badge.js.map +1 -1
  43. package/lib/module/views/BottomTabBar.js +151 -110
  44. package/lib/module/views/BottomTabBar.js.map +1 -1
  45. package/lib/module/views/BottomTabItem.js +101 -59
  46. package/lib/module/views/BottomTabItem.js.map +1 -1
  47. package/lib/module/views/BottomTabView.js +126 -100
  48. package/lib/module/views/BottomTabView.js.map +1 -1
  49. package/lib/module/views/ScreenFallback.js +17 -9
  50. package/lib/module/views/ScreenFallback.js.map +1 -1
  51. package/lib/module/views/TabBarIcon.js +61 -37
  52. package/lib/module/views/TabBarIcon.js.map +1 -1
  53. package/lib/typescript/commonjs/package.json +1 -0
  54. package/lib/typescript/commonjs/src/TransitionConfigs/SceneStyleInterpolators.d.ts.map +1 -0
  55. package/lib/typescript/commonjs/src/TransitionConfigs/TransitionPresets.d.ts.map +1 -0
  56. package/lib/typescript/commonjs/src/TransitionConfigs/TransitionSpecs.d.ts.map +1 -0
  57. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  58. package/lib/typescript/{src → commonjs/src}/navigators/createBottomTabNavigator.d.ts +3 -4
  59. package/lib/typescript/commonjs/src/navigators/createBottomTabNavigator.d.ts.map +1 -0
  60. package/lib/typescript/{src → commonjs/src}/types.d.ts +21 -4
  61. package/lib/typescript/commonjs/src/types.d.ts.map +1 -0
  62. package/lib/typescript/commonjs/src/utils/BottomTabBarHeightCallbackContext.d.ts.map +1 -0
  63. package/lib/typescript/commonjs/src/utils/BottomTabBarHeightContext.d.ts.map +1 -0
  64. package/lib/typescript/commonjs/src/utils/useAnimatedHashMap.d.ts.map +1 -0
  65. package/lib/typescript/commonjs/src/utils/useBottomTabBarHeight.d.ts.map +1 -0
  66. package/lib/typescript/commonjs/src/utils/useIsKeyboardShown.d.ts.map +1 -0
  67. package/lib/typescript/{src → commonjs/src}/views/Badge.d.ts +1 -2
  68. package/lib/typescript/commonjs/src/views/Badge.d.ts.map +1 -0
  69. package/lib/typescript/{src → commonjs/src}/views/BottomTabBar.d.ts +2 -3
  70. package/lib/typescript/commonjs/src/views/BottomTabBar.d.ts.map +1 -0
  71. package/lib/typescript/{src → commonjs/src}/views/BottomTabItem.d.ts +9 -1
  72. package/lib/typescript/commonjs/src/views/BottomTabItem.d.ts.map +1 -0
  73. package/lib/typescript/{src → commonjs/src}/views/BottomTabView.d.ts +1 -2
  74. package/lib/typescript/commonjs/src/views/BottomTabView.d.ts.map +1 -0
  75. package/lib/typescript/{src → commonjs/src}/views/ScreenFallback.d.ts +2 -2
  76. package/lib/typescript/commonjs/src/views/ScreenFallback.d.ts.map +1 -0
  77. package/lib/typescript/{src → commonjs/src}/views/TabBarIcon.d.ts +3 -2
  78. package/lib/typescript/commonjs/src/views/TabBarIcon.d.ts.map +1 -0
  79. package/lib/typescript/commonjs/tsconfig.build.tsbuildinfo +1 -0
  80. package/lib/typescript/module/package.json +1 -0
  81. package/lib/typescript/module/src/TransitionConfigs/SceneStyleInterpolators.d.ts +10 -0
  82. package/lib/typescript/module/src/TransitionConfigs/SceneStyleInterpolators.d.ts.map +1 -0
  83. package/lib/typescript/module/src/TransitionConfigs/TransitionPresets.d.ts +4 -0
  84. package/lib/typescript/module/src/TransitionConfigs/TransitionPresets.d.ts.map +1 -0
  85. package/lib/typescript/module/src/TransitionConfigs/TransitionSpecs.d.ts +4 -0
  86. package/lib/typescript/module/src/TransitionConfigs/TransitionSpecs.d.ts.map +1 -0
  87. package/lib/typescript/module/src/index.d.ts +27 -0
  88. package/lib/typescript/module/src/index.d.ts.map +1 -0
  89. package/lib/typescript/module/src/navigators/createBottomTabNavigator.d.ts +17 -0
  90. package/lib/typescript/module/src/navigators/createBottomTabNavigator.d.ts.map +1 -0
  91. package/lib/typescript/module/src/types.d.ts +326 -0
  92. package/lib/typescript/module/src/types.d.ts.map +1 -0
  93. package/lib/typescript/module/src/utils/BottomTabBarHeightCallbackContext.d.ts +3 -0
  94. package/lib/typescript/module/src/utils/BottomTabBarHeightCallbackContext.d.ts.map +1 -0
  95. package/lib/typescript/module/src/utils/BottomTabBarHeightContext.d.ts +3 -0
  96. package/lib/typescript/module/src/utils/BottomTabBarHeightContext.d.ts.map +1 -0
  97. package/lib/typescript/module/src/utils/useAnimatedHashMap.d.ts +4 -0
  98. package/lib/typescript/module/src/utils/useAnimatedHashMap.d.ts.map +1 -0
  99. package/lib/typescript/module/src/utils/useBottomTabBarHeight.d.ts +2 -0
  100. package/lib/typescript/module/src/utils/useBottomTabBarHeight.d.ts.map +1 -0
  101. package/lib/typescript/module/src/utils/useIsKeyboardShown.d.ts +2 -0
  102. package/lib/typescript/module/src/utils/useIsKeyboardShown.d.ts.map +1 -0
  103. package/lib/typescript/module/src/views/Badge.d.ts +22 -0
  104. package/lib/typescript/module/src/views/Badge.d.ts.map +1 -0
  105. package/lib/typescript/module/src/views/BottomTabBar.d.ts +22 -0
  106. package/lib/typescript/module/src/views/BottomTabBar.d.ts.map +1 -0
  107. package/lib/typescript/module/src/views/BottomTabItem.d.ts +125 -0
  108. package/lib/typescript/module/src/views/BottomTabItem.d.ts.map +1 -0
  109. package/lib/typescript/module/src/views/BottomTabView.d.ts +10 -0
  110. package/lib/typescript/module/src/views/BottomTabView.d.ts.map +1 -0
  111. package/lib/typescript/module/src/views/ScreenFallback.d.ts +17 -0
  112. package/lib/typescript/module/src/views/ScreenFallback.d.ts.map +1 -0
  113. package/lib/typescript/module/src/views/TabBarIcon.d.ts +23 -0
  114. package/lib/typescript/module/src/views/TabBarIcon.d.ts.map +1 -0
  115. package/lib/typescript/module/tsconfig.build.tsbuildinfo +1 -0
  116. package/package.json +41 -17
  117. package/src/navigators/createBottomTabNavigator.tsx +4 -7
  118. package/src/types.tsx +20 -4
  119. package/src/views/BottomTabBar.tsx +89 -47
  120. package/src/views/BottomTabItem.tsx +115 -31
  121. package/src/views/BottomTabView.tsx +22 -4
  122. package/src/views/TabBarIcon.tsx +55 -18
  123. package/lib/typescript/src/TransitionConfigs/SceneStyleInterpolators.d.ts.map +0 -1
  124. package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts.map +0 -1
  125. package/lib/typescript/src/TransitionConfigs/TransitionSpecs.d.ts.map +0 -1
  126. package/lib/typescript/src/index.d.ts.map +0 -1
  127. package/lib/typescript/src/navigators/createBottomTabNavigator.d.ts.map +0 -1
  128. package/lib/typescript/src/types.d.ts.map +0 -1
  129. package/lib/typescript/src/utils/BottomTabBarHeightCallbackContext.d.ts.map +0 -1
  130. package/lib/typescript/src/utils/BottomTabBarHeightContext.d.ts.map +0 -1
  131. package/lib/typescript/src/utils/useAnimatedHashMap.d.ts.map +0 -1
  132. package/lib/typescript/src/utils/useBottomTabBarHeight.d.ts.map +0 -1
  133. package/lib/typescript/src/utils/useIsKeyboardShown.d.ts.map +0 -1
  134. package/lib/typescript/src/views/Badge.d.ts.map +0 -1
  135. package/lib/typescript/src/views/BottomTabBar.d.ts.map +0 -1
  136. package/lib/typescript/src/views/BottomTabItem.d.ts.map +0 -1
  137. package/lib/typescript/src/views/BottomTabView.d.ts.map +0 -1
  138. package/lib/typescript/src/views/ScreenFallback.d.ts.map +0 -1
  139. package/lib/typescript/src/views/TabBarIcon.d.ts.map +0 -1
  140. /package/lib/typescript/{src → commonjs/src}/TransitionConfigs/SceneStyleInterpolators.d.ts +0 -0
  141. /package/lib/typescript/{src → commonjs/src}/TransitionConfigs/TransitionPresets.d.ts +0 -0
  142. /package/lib/typescript/{src → commonjs/src}/TransitionConfigs/TransitionSpecs.d.ts +0 -0
  143. /package/lib/typescript/{src → commonjs/src}/index.d.ts +0 -0
  144. /package/lib/typescript/{src → commonjs/src}/utils/BottomTabBarHeightCallbackContext.d.ts +0 -0
  145. /package/lib/typescript/{src → commonjs/src}/utils/BottomTabBarHeightContext.d.ts +0 -0
  146. /package/lib/typescript/{src → commonjs/src}/utils/useAnimatedHashMap.d.ts +0 -0
  147. /package/lib/typescript/{src → commonjs/src}/utils/useBottomTabBarHeight.d.ts +0 -0
  148. /package/lib/typescript/{src → commonjs/src}/utils/useIsKeyboardShown.d.ts +0 -0
@@ -13,7 +13,6 @@ import {
13
13
  useLocale,
14
14
  useTheme,
15
15
  } from '@react-navigation/native';
16
- import Color from 'color';
17
16
  import React from 'react';
18
17
  import {
19
18
  Animated,
@@ -38,10 +37,11 @@ type Props = BottomTabBarProps & {
38
37
  style?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
39
38
  };
40
39
 
41
- const DEFAULT_TABBAR_HEIGHT = 49;
42
- const COMPACT_TABBAR_HEIGHT = 32;
40
+ const TABBAR_HEIGHT_UIKIT = 49;
41
+ const TABBAR_HEIGHT_UIKIT_COMPACT = 32;
42
+ const SPACING_UIKIT = 15;
43
+ const SPACING_MATERIAL = 12;
43
44
  const DEFAULT_MAX_TAB_ITEM_WIDTH = 125;
44
- const SPACING = 12;
45
45
 
46
46
  const useNativeDriver = Platform.OS !== 'web';
47
47
 
@@ -91,8 +91,36 @@ const shouldUseHorizontalLabels = ({
91
91
  }
92
92
  };
93
93
 
94
- const getPaddingBottom = (insets: EdgeInsets) =>
95
- Math.max(insets.bottom - Platform.select({ ios: 4, default: 0 }), 0);
94
+ const isCompact = ({ state, descriptors, dimensions }: Options): boolean => {
95
+ const { tabBarPosition, tabBarVariant } =
96
+ descriptors[state.routes[state.index].key].options;
97
+
98
+ if (
99
+ tabBarPosition === 'left' ||
100
+ tabBarPosition === 'right' ||
101
+ tabBarVariant === 'material'
102
+ ) {
103
+ return false;
104
+ }
105
+
106
+ const isLandscape = dimensions.width > dimensions.height;
107
+ const horizontalLabels = shouldUseHorizontalLabels({
108
+ state,
109
+ descriptors,
110
+ dimensions,
111
+ });
112
+
113
+ if (
114
+ Platform.OS === 'ios' &&
115
+ !Platform.isPad &&
116
+ isLandscape &&
117
+ horizontalLabels
118
+ ) {
119
+ return true;
120
+ }
121
+
122
+ return false;
123
+ };
96
124
 
97
125
  export const getTabBarHeight = ({
98
126
  state,
@@ -100,11 +128,12 @@ export const getTabBarHeight = ({
100
128
  dimensions,
101
129
  insets,
102
130
  style,
103
- ...rest
104
131
  }: Options & {
105
132
  insets: EdgeInsets;
106
133
  style: Animated.WithAnimatedValue<StyleProp<ViewStyle>> | undefined;
107
134
  }) => {
135
+ const { tabBarPosition } = descriptors[state.routes[state.index].key].options;
136
+
108
137
  const flattenedStyle = StyleSheet.flatten(style);
109
138
  const customHeight =
110
139
  flattenedStyle && 'height' in flattenedStyle
@@ -115,25 +144,13 @@ export const getTabBarHeight = ({
115
144
  return customHeight;
116
145
  }
117
146
 
118
- const isLandscape = dimensions.width > dimensions.height;
119
- const horizontalLabels = shouldUseHorizontalLabels({
120
- state,
121
- descriptors,
122
- dimensions,
123
- ...rest,
124
- });
125
- const paddingBottom = getPaddingBottom(insets);
147
+ const inset = insets[tabBarPosition === 'top' ? 'top' : 'bottom'];
126
148
 
127
- if (
128
- Platform.OS === 'ios' &&
129
- !Platform.isPad &&
130
- isLandscape &&
131
- horizontalLabels
132
- ) {
133
- return COMPACT_TABBAR_HEIGHT + paddingBottom;
149
+ if (isCompact({ state, descriptors, dimensions })) {
150
+ return TABBAR_HEIGHT_UIKIT_COMPACT + inset;
134
151
  }
135
152
 
136
- return DEFAULT_TABBAR_HEIGHT + paddingBottom;
153
+ return TABBAR_HEIGHT_UIKIT + inset;
137
154
  };
138
155
 
139
156
  export function BottomTabBar({
@@ -154,22 +171,38 @@ export function BottomTabBar({
154
171
  const {
155
172
  tabBarPosition = 'bottom',
156
173
  tabBarShowLabel,
174
+ tabBarLabelPosition,
157
175
  tabBarHideOnKeyboard = false,
158
176
  tabBarVisibilityAnimationConfig,
177
+ tabBarVariant = 'uikit',
159
178
  tabBarStyle,
160
179
  tabBarBackground,
161
180
  tabBarActiveTintColor,
162
181
  tabBarInactiveTintColor,
163
- tabBarActiveBackgroundColor = tabBarPosition !== 'bottom' &&
164
- tabBarPosition !== 'top'
165
- ? Color(tabBarActiveTintColor ?? colors.primary)
166
- .alpha(0.12)
167
- .rgb()
168
- .string()
169
- : undefined,
182
+ tabBarActiveBackgroundColor,
170
183
  tabBarInactiveBackgroundColor,
171
184
  } = focusedOptions;
172
185
 
186
+ if (
187
+ tabBarVariant === 'material' &&
188
+ tabBarPosition !== 'left' &&
189
+ tabBarPosition !== 'right'
190
+ ) {
191
+ throw new Error(
192
+ "The 'material' variant for tab bar is only supported when 'tabBarPosition' is set to 'left' or 'right'."
193
+ );
194
+ }
195
+
196
+ if (
197
+ tabBarLabelPosition === 'below-icon' &&
198
+ tabBarVariant === 'uikit' &&
199
+ (tabBarPosition === 'left' || tabBarPosition === 'right')
200
+ ) {
201
+ throw new Error(
202
+ "The 'below-icon' label position for tab bar is only supported when 'tabBarPosition' is set to 'top' or 'bottom' when using the 'uikit' variant."
203
+ );
204
+ }
205
+
173
206
  const dimensions = useSafeAreaFrame();
174
207
  const isKeyboardShown = useIsKeyboardShown();
175
208
 
@@ -211,6 +244,7 @@ export function BottomTabBar({
211
244
  }
212
245
  });
213
246
  } else {
247
+ // eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
214
248
  setIsTabBarHidden(true);
215
249
 
216
250
  const animation =
@@ -249,7 +283,6 @@ export function BottomTabBar({
249
283
 
250
284
  const { routes } = state;
251
285
 
252
- const paddingBottom = getPaddingBottom(insets);
253
286
  const tabBarHeight = getTabBarHeight({
254
287
  state,
255
288
  descriptors,
@@ -264,7 +297,10 @@ export function BottomTabBar({
264
297
  dimensions,
265
298
  });
266
299
 
267
- const isSidebar = tabBarPosition === 'left' || tabBarPosition === 'right';
300
+ const compact = isCompact({ state, descriptors, dimensions });
301
+ const sidebar = tabBarPosition === 'left' || tabBarPosition === 'right';
302
+ const spacing =
303
+ tabBarVariant === 'material' ? SPACING_MATERIAL : SPACING_UIKIT;
268
304
 
269
305
  const tabBarBackgroundElement = tabBarBackground?.();
270
306
 
@@ -298,16 +334,16 @@ export function BottomTabBar({
298
334
  tabBarBackgroundElement != null ? 'transparent' : colors.card,
299
335
  borderColor: colors.border,
300
336
  },
301
- isSidebar
337
+ sidebar
302
338
  ? {
303
339
  paddingTop:
304
- (hasHorizontalLabels ? SPACING : SPACING / 2) + insets.top,
340
+ (hasHorizontalLabels ? spacing : spacing / 2) + insets.top,
305
341
  paddingBottom:
306
- (hasHorizontalLabels ? SPACING : SPACING / 2) + insets.bottom,
342
+ (hasHorizontalLabels ? spacing : spacing / 2) + insets.bottom,
307
343
  paddingStart:
308
- SPACING + (tabBarPosition === 'left' ? insets.left : 0),
344
+ spacing + (tabBarPosition === 'left' ? insets.left : 0),
309
345
  paddingEnd:
310
- SPACING + (tabBarPosition === 'right' ? insets.right : 0),
346
+ spacing + (tabBarPosition === 'right' ? insets.right : 0),
311
347
  minWidth: hasHorizontalLabels
312
348
  ? getDefaultSidebarWidth(dimensions)
313
349
  : 0,
@@ -320,7 +356,7 @@ export function BottomTabBar({
320
356
  inputRange: [0, 1],
321
357
  outputRange: [
322
358
  layout.height +
323
- paddingBottom +
359
+ insets[tabBarPosition === 'top' ? 'top' : 'bottom'] +
324
360
  StyleSheet.hairlineWidth,
325
361
  0,
326
362
  ],
@@ -333,21 +369,22 @@ export function BottomTabBar({
333
369
  },
334
370
  {
335
371
  height: tabBarHeight,
336
- paddingBottom,
372
+ paddingBottom: tabBarPosition === 'bottom' ? insets.bottom : 0,
373
+ paddingTop: tabBarPosition === 'top' ? insets.top : 0,
337
374
  paddingHorizontal: Math.max(insets.left, insets.right),
338
375
  },
339
376
  ],
340
377
  tabBarStyle,
341
378
  ]}
342
379
  pointerEvents={isTabBarHidden ? 'none' : 'auto'}
343
- onLayout={isSidebar ? undefined : handleLayout}
380
+ onLayout={sidebar ? undefined : handleLayout}
344
381
  >
345
382
  <View pointerEvents="none" style={StyleSheet.absoluteFill}>
346
383
  {tabBarBackgroundElement}
347
384
  </View>
348
385
  <View
349
386
  accessibilityRole="tablist"
350
- style={isSidebar ? styles.sideContent : styles.bottomContent}
387
+ style={sidebar ? styles.sideContent : styles.bottomContent}
351
388
  >
352
389
  {routes.map((route, index) => {
353
390
  const focused = index === state.index;
@@ -402,7 +439,9 @@ export function BottomTabBar({
402
439
  descriptor={descriptors[route.key]}
403
440
  focused={focused}
404
441
  horizontal={hasHorizontalLabels}
405
- variant={isSidebar ? 'material' : 'uikit'}
442
+ compact={compact}
443
+ sidebar={sidebar}
444
+ variant={tabBarVariant}
406
445
  onPress={onPress}
407
446
  onLongPress={onLongPress}
408
447
  accessibilityLabel={accessibilityLabel}
@@ -426,8 +465,14 @@ export function BottomTabBar({
426
465
  labelStyle={options.tabBarLabelStyle}
427
466
  iconStyle={options.tabBarIconStyle}
428
467
  style={[
429
- isSidebar
430
- ? !hasHorizontalLabels && styles.sideItemVertical
468
+ sidebar
469
+ ? {
470
+ marginVertical: hasHorizontalLabels
471
+ ? tabBarVariant === 'material'
472
+ ? 0
473
+ : 1
474
+ : spacing / 2,
475
+ }
431
476
  : styles.bottomItem,
432
477
  options.tabBarItemStyle,
433
478
  ]}
@@ -469,7 +514,4 @@ const styles = StyleSheet.create({
469
514
  bottomItem: {
470
515
  flex: 1,
471
516
  },
472
- sideItemVertical: {
473
- marginVertical: SPACING / 2,
474
- },
475
517
  });
@@ -90,6 +90,14 @@ type Props = {
90
90
  * Whether the label should be aligned with the icon horizontally.
91
91
  */
92
92
  horizontal: boolean;
93
+ /**
94
+ * Whether to render the icon and label in compact mode.
95
+ */
96
+ compact: boolean;
97
+ /**
98
+ * Whether the tab is an item in a side bar.
99
+ */
100
+ sidebar: boolean;
93
101
  /**
94
102
  * Variant of navigation bar styling
95
103
  * - `uikit`: iOS UIKit style
@@ -134,6 +142,10 @@ type Props = {
134
142
  style?: StyleProp<ViewStyle>;
135
143
  };
136
144
 
145
+ const renderButtonDefault = (props: BottomTabBarButtonProps) => (
146
+ <PlatformPressable {...props} />
147
+ );
148
+
137
149
  export function BottomTabItem({
138
150
  route,
139
151
  href,
@@ -143,16 +155,18 @@ export function BottomTabItem({
143
155
  icon,
144
156
  badge,
145
157
  badgeStyle,
146
- button = (props: BottomTabBarButtonProps) => <PlatformPressable {...props} />,
158
+ button = renderButtonDefault,
147
159
  accessibilityLabel,
148
160
  testID,
149
161
  onPress,
150
162
  onLongPress,
151
163
  horizontal,
164
+ compact,
165
+ sidebar,
152
166
  variant,
153
167
  activeTintColor: customActiveTintColor,
154
168
  inactiveTintColor: customInactiveTintColor,
155
- activeBackgroundColor = 'transparent',
169
+ activeBackgroundColor: customActiveBackgroundColor,
156
170
  inactiveBackgroundColor = 'transparent',
157
171
  showLabel = true,
158
172
  allowFontScaling,
@@ -163,21 +177,47 @@ export function BottomTabItem({
163
177
  const { colors, fonts } = useTheme();
164
178
 
165
179
  const activeTintColor =
166
- customActiveTintColor === undefined
167
- ? colors.primary
168
- : customActiveTintColor;
180
+ customActiveTintColor ??
181
+ (variant === 'uikit' && sidebar && horizontal
182
+ ? Color(colors.primary).isDark()
183
+ ? 'white'
184
+ : Color(colors.primary).darken(0.71).string()
185
+ : colors.primary);
169
186
 
170
187
  const inactiveTintColor =
171
188
  customInactiveTintColor === undefined
172
- ? Color(colors.text).mix(Color(colors.card), 0.5).hex()
189
+ ? variant === 'material'
190
+ ? Color(colors.text).alpha(0.68).rgb().string()
191
+ : Color(colors.text).mix(Color(colors.card), 0.5).hex()
173
192
  : customInactiveTintColor;
174
193
 
194
+ const activeBackgroundColor =
195
+ customActiveBackgroundColor ??
196
+ (variant === 'material'
197
+ ? Color(activeTintColor).alpha(0.12).rgb().string()
198
+ : sidebar && horizontal
199
+ ? colors.primary
200
+ : 'transparent');
201
+
202
+ let labelInactiveTintColor = inactiveTintColor;
203
+ let iconInactiveTintColor = inactiveTintColor;
204
+
205
+ if (
206
+ variant === 'uikit' &&
207
+ sidebar &&
208
+ horizontal &&
209
+ customInactiveTintColor === undefined
210
+ ) {
211
+ iconInactiveTintColor = colors.primary;
212
+ labelInactiveTintColor = colors.text;
213
+ }
214
+
175
215
  const renderLabel = ({ focused }: { focused: boolean }) => {
176
216
  if (showLabel === false) {
177
217
  return null;
178
218
  }
179
219
 
180
- const color = focused ? activeTintColor : inactiveTintColor;
220
+ const color = focused ? activeTintColor : labelInactiveTintColor;
181
221
 
182
222
  if (typeof label !== 'string') {
183
223
  const { options } = descriptor;
@@ -206,11 +246,19 @@ export function BottomTabItem({
206
246
  horizontal
207
247
  ? [
208
248
  styles.labelBeside,
209
- { marginStart: icon !== undefined ? 16 : 0 },
210
- variant === 'uikit' && styles.labelBesideUikit,
249
+ variant === 'material'
250
+ ? styles.labelSidebarMaterial
251
+ : sidebar
252
+ ? styles.labelSidebarUiKit
253
+ : compact
254
+ ? styles.labelBesideUikitCompact
255
+ : styles.labelBesideUikit,
256
+ icon == null && { marginStart: 0 },
211
257
  ]
212
258
  : styles.labelBeneath,
213
- variant === 'material' && fonts.medium,
259
+ compact || (variant === 'uikit' && sidebar && horizontal)
260
+ ? fonts.regular
261
+ : fonts.medium,
214
262
  labelStyle,
215
263
  ]}
216
264
  allowFontScaling={allowFontScaling}
@@ -232,13 +280,14 @@ export function BottomTabItem({
232
280
  return (
233
281
  <TabBarIcon
234
282
  route={route}
235
- horizontal={horizontal}
283
+ variant={variant}
284
+ size={compact ? 'compact' : 'regular'}
236
285
  badge={badge}
237
286
  badgeStyle={badgeStyle}
238
287
  activeOpacity={activeOpacity}
239
288
  inactiveOpacity={inactiveOpacity}
240
289
  activeTintColor={activeTintColor}
241
- inactiveTintColor={inactiveTintColor}
290
+ inactiveTintColor={iconInactiveTintColor}
242
291
  renderIcon={icon}
243
292
  style={iconStyle}
244
293
  />
@@ -252,7 +301,14 @@ export function BottomTabItem({
252
301
  : inactiveBackgroundColor;
253
302
 
254
303
  const { flex } = StyleSheet.flatten(style || {});
255
- const borderRadius = variant === 'material' ? (horizontal ? 56 : 16) : 0;
304
+ const borderRadius =
305
+ variant === 'material'
306
+ ? horizontal
307
+ ? 56
308
+ : 16
309
+ : sidebar && horizontal
310
+ ? 10
311
+ : 0;
256
312
 
257
313
  return (
258
314
  <View
@@ -278,20 +334,26 @@ export function BottomTabItem({
278
334
  accessibilityStates: focused ? ['selected'] : [],
279
335
  android_ripple: { borderless: true },
280
336
  hoverEffect:
281
- variant === 'material' ? { color: colors.text } : undefined,
337
+ variant === 'material' || (sidebar && horizontal)
338
+ ? { color: colors.text }
339
+ : undefined,
282
340
  pressOpacity: 1,
283
341
  style: [
284
342
  styles.tab,
285
343
  { flex, backgroundColor, borderRadius },
286
- horizontal
287
- ? [
288
- styles.tabHorizontal,
289
- variant === 'material' && styles.tabHorizontalMaterial,
290
- ]
291
- : [
292
- styles.tabVertical,
293
- variant === 'material' && styles.tabVerticalMaterial,
294
- ],
344
+ sidebar
345
+ ? variant === 'material'
346
+ ? horizontal
347
+ ? styles.tabBarSidebarMaterial
348
+ : styles.tabVerticalMaterial
349
+ : horizontal
350
+ ? styles.tabBarSidebarUiKit
351
+ : styles.tabVerticalUiKit
352
+ : variant === 'material'
353
+ ? styles.tabVerticalMaterial
354
+ : horizontal
355
+ ? styles.tabHorizontalUiKit
356
+ : styles.tabVerticalUiKit,
295
357
  ],
296
358
  children: (
297
359
  <React.Fragment>
@@ -310,33 +372,55 @@ const styles = StyleSheet.create({
310
372
  // Roundness for iPad hover effect
311
373
  borderRadius: 10,
312
374
  },
313
- tabVertical: {
314
- justifyContent: 'flex-end',
375
+ tabVerticalUiKit: {
376
+ justifyContent: 'flex-start',
315
377
  flexDirection: 'column',
378
+ padding: 5,
316
379
  },
317
380
  tabVerticalMaterial: {
318
381
  padding: 10,
319
382
  },
320
- tabHorizontal: {
383
+ tabHorizontalUiKit: {
321
384
  justifyContent: 'center',
385
+ alignItems: 'center',
386
+ flexDirection: 'row',
387
+ padding: 5,
388
+ },
389
+ tabBarSidebarUiKit: {
390
+ justifyContent: 'flex-start',
391
+ alignItems: 'center',
392
+ flexDirection: 'row',
393
+ paddingVertical: 7,
394
+ paddingHorizontal: 5,
395
+ },
396
+ tabBarSidebarMaterial: {
397
+ justifyContent: 'flex-start',
398
+ alignItems: 'center',
322
399
  flexDirection: 'row',
323
- paddingVertical: 11,
400
+ paddingVertical: 15,
324
401
  paddingStart: 16,
325
402
  paddingEnd: 24,
326
403
  },
327
- tabHorizontalMaterial: {
328
- justifyContent: 'flex-start',
404
+ labelSidebarMaterial: {
405
+ marginStart: 12,
406
+ },
407
+ labelSidebarUiKit: {
408
+ fontSize: 17,
409
+ marginStart: 10,
329
410
  },
330
411
  labelBeneath: {
331
412
  fontSize: 10,
332
413
  },
333
414
  labelBeside: {
334
415
  marginEnd: 12,
335
- marginVertical: 4,
336
416
  lineHeight: 24,
337
- marginStart: 20,
338
417
  },
339
418
  labelBesideUikit: {
340
419
  fontSize: 13,
420
+ marginStart: 5,
421
+ },
422
+ labelBesideUikitCompact: {
423
+ fontSize: 12,
424
+ marginStart: 5,
341
425
  },
342
426
  });
@@ -64,12 +64,16 @@ const hasAnimation = (options: BottomTabNavigationOptions) => {
64
64
  return animation !== 'none';
65
65
  }
66
66
 
67
- return !transitionSpec;
67
+ return Boolean(transitionSpec);
68
68
  };
69
69
 
70
+ const renderTabBarDefault = (props: BottomTabBarProps) => (
71
+ <BottomTabBar {...props} />
72
+ );
73
+
70
74
  export function BottomTabView(props: Props) {
71
75
  const {
72
- tabBar = (props: BottomTabBarProps) => <BottomTabBar {...props} />,
76
+ tabBar = renderTabBarDefault,
73
77
  state,
74
78
  navigation,
75
79
  descriptors,
@@ -77,7 +81,6 @@ export function BottomTabView(props: Props) {
77
81
  detachInactiveScreens = Platform.OS === 'web' ||
78
82
  Platform.OS === 'android' ||
79
83
  Platform.OS === 'ios',
80
- sceneContainerStyle,
81
84
  } = props;
82
85
 
83
86
  const focusedRouteKey = state.routes[state.index].key;
@@ -119,6 +122,13 @@ export function BottomTabView(props: Props) {
119
122
  }
120
123
 
121
124
  const animateToIndex = () => {
125
+ if (previousRouteKey !== focusedRouteKey) {
126
+ navigation.emit({
127
+ type: 'transitionStart',
128
+ target: focusedRouteKey,
129
+ });
130
+ }
131
+
122
132
  Animated.parallel(
123
133
  state.routes
124
134
  .map((route, index) => {
@@ -156,6 +166,13 @@ export function BottomTabView(props: Props) {
156
166
  if (finished && popToTopAction) {
157
167
  navigation.dispatch(popToTopAction);
158
168
  }
169
+
170
+ if (previousRouteKey !== focusedRouteKey) {
171
+ navigation.emit({
172
+ type: 'transitionEnd',
173
+ target: focusedRouteKey,
174
+ });
175
+ }
159
176
  });
160
177
  };
161
178
 
@@ -268,6 +285,7 @@ export function BottomTabView(props: Props) {
268
285
  headerShown,
269
286
  headerStatusBarHeight,
270
287
  headerTransparent,
288
+ sceneStyle: customSceneStyle,
271
289
  } = descriptor.options;
272
290
 
273
291
  const { sceneStyle } =
@@ -317,7 +335,7 @@ export function BottomTabView(props: Props) {
317
335
  descriptor.navigation as BottomTabNavigationProp<ParamListBase>,
318
336
  options: descriptor.options,
319
337
  })}
320
- style={[sceneContainerStyle, animationEnabled && sceneStyle]}
338
+ style={[customSceneStyle, animationEnabled && sceneStyle]}
321
339
  >
322
340
  {descriptor.render()}
323
341
  </Screen>