@react-navigation/bottom-tabs 7.20.0 → 7.22.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.
- package/lib/module/unstable/Deferred.js +3 -10
- package/lib/module/unstable/Deferred.js.map +1 -1
- package/lib/module/unstable/NativeBottomTabView.native.js +288 -196
- package/lib/module/unstable/NativeBottomTabView.native.js.map +1 -1
- package/lib/module/unstable/NativeScreen/NativeScreen.js +1 -1
- package/lib/module/unstable/NativeScreen/useAnimatedHeaderHeight.js.map +1 -1
- package/lib/module/unstable/NativeScreen/useHeaderConfig.js +11 -11
- package/lib/module/unstable/NativeScreen/useHeaderConfig.js.map +1 -1
- package/lib/module/views/BottomTabBar.js +130 -67
- package/lib/module/views/BottomTabBar.js.map +1 -1
- package/lib/module/views/BottomTabItem.js +4 -4
- package/lib/module/views/BottomTabItem.js.map +1 -1
- package/lib/module/views/BottomTabView.js +78 -57
- package/lib/module/views/BottomTabView.js.map +1 -1
- package/lib/module/views/TabBarIcon.js +6 -2
- package/lib/module/views/TabBarIcon.js.map +1 -1
- package/lib/typescript/src/types.d.ts +17 -4
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/unstable/Deferred.d.ts.map +1 -1
- package/lib/typescript/src/unstable/NativeBottomTabView.d.ts +1 -1
- package/lib/typescript/src/unstable/NativeBottomTabView.d.ts.map +1 -1
- package/lib/typescript/src/unstable/NativeBottomTabView.native.d.ts.map +1 -1
- package/lib/typescript/src/unstable/NativeScreen/types.d.ts +1 -6
- package/lib/typescript/src/unstable/NativeScreen/types.d.ts.map +1 -1
- package/lib/typescript/src/unstable/NativeScreen/useAnimatedHeaderHeight.d.ts.map +1 -1
- package/lib/typescript/src/unstable/NativeScreen/useHeaderConfig.d.ts.map +1 -1
- package/lib/typescript/src/unstable/types.d.ts +125 -5
- package/lib/typescript/src/unstable/types.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabBar.d.ts +1 -1
- package/lib/typescript/src/views/BottomTabBar.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabItem.d.ts +5 -1
- package/lib/typescript/src/views/BottomTabItem.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabView.d.ts.map +1 -1
- package/lib/typescript/src/views/TabBarIcon.d.ts +2 -1
- package/lib/typescript/src/views/TabBarIcon.d.ts.map +1 -1
- package/package.json +14 -14
- package/src/types.tsx +33 -4
- package/src/unstable/Deferred.tsx +3 -11
- package/src/unstable/NativeBottomTabView.native.tsx +356 -218
- package/src/unstable/NativeBottomTabView.tsx +3 -3
- package/src/unstable/NativeScreen/NativeScreen.tsx +1 -1
- package/src/unstable/NativeScreen/types.ts +3 -6
- package/src/unstable/NativeScreen/useAnimatedHeaderHeight.tsx +5 -3
- package/src/unstable/NativeScreen/useHeaderConfig.tsx +8 -14
- package/src/unstable/types.tsx +134 -8
- package/src/views/BottomTabBar.tsx +176 -86
- package/src/views/BottomTabItem.tsx +11 -2
- package/src/views/BottomTabView.tsx +100 -66
- package/src/views/TabBarIcon.tsx +9 -2
|
@@ -64,12 +64,9 @@ export type NativeHeaderOptions = {
|
|
|
64
64
|
*
|
|
65
65
|
* @platform ios
|
|
66
66
|
*/
|
|
67
|
-
headerLargeTitleStyle?: StyleProp<
|
|
68
|
-
fontFamily
|
|
69
|
-
|
|
70
|
-
fontWeight?: string;
|
|
71
|
-
color?: ColorValue;
|
|
72
|
-
}>;
|
|
67
|
+
headerLargeTitleStyle?: StyleProp<
|
|
68
|
+
Pick<TextStyle, 'fontFamily' | 'fontSize' | 'fontWeight' | 'color'>
|
|
69
|
+
>;
|
|
73
70
|
/**
|
|
74
71
|
* Style object for header. Supported properties:
|
|
75
72
|
* - backgroundColor
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { Animated } from 'react-native';
|
|
3
3
|
|
|
4
|
-
export const AnimatedHeaderHeightContext
|
|
4
|
+
export const AnimatedHeaderHeightContext: React.Context<
|
|
5
5
|
Animated.AnimatedInterpolation<number> | undefined
|
|
6
|
-
>(
|
|
6
|
+
> = React.createContext<Animated.AnimatedInterpolation<number> | undefined>(
|
|
7
|
+
undefined
|
|
8
|
+
);
|
|
7
9
|
|
|
8
|
-
export function useAnimatedHeaderHeight() {
|
|
10
|
+
export function useAnimatedHeaderHeight(): Animated.AnimatedInterpolation<number> {
|
|
9
11
|
const animatedValue = React.useContext(AnimatedHeaderHeightContext);
|
|
10
12
|
|
|
11
13
|
if (animatedValue === undefined) {
|
|
@@ -241,19 +241,12 @@ export function useHeaderConfig({
|
|
|
241
241
|
|
|
242
242
|
const largeTitleFontWeight = headerLargeTitleStyleFlattened.fontWeight;
|
|
243
243
|
|
|
244
|
-
const headerTitleStyleSupported: TextStyle = {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if (titleFontSize != null) {
|
|
251
|
-
headerTitleStyleSupported.fontSize = titleFontSize;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (titleFontWeight != null) {
|
|
255
|
-
headerTitleStyleSupported.fontWeight = titleFontWeight;
|
|
256
|
-
}
|
|
244
|
+
const headerTitleStyleSupported: TextStyle = {
|
|
245
|
+
color: titleColor,
|
|
246
|
+
...(titleFontFamily != null ? { fontFamily: titleFontFamily } : null),
|
|
247
|
+
...(titleFontSize != null ? { fontSize: titleFontSize } : null),
|
|
248
|
+
...(titleFontWeight != null ? { fontWeight: titleFontWeight } : null),
|
|
249
|
+
};
|
|
257
250
|
|
|
258
251
|
const headerBackgroundColor =
|
|
259
252
|
headerStyleFlattened.backgroundColor ??
|
|
@@ -421,7 +414,8 @@ export function useHeaderConfig({
|
|
|
421
414
|
largeTitleColor,
|
|
422
415
|
largeTitleFontFamily,
|
|
423
416
|
largeTitleFontSize,
|
|
424
|
-
largeTitleFontWeight
|
|
417
|
+
largeTitleFontWeight:
|
|
418
|
+
largeTitleFontWeight != null ? String(largeTitleFontWeight) : undefined,
|
|
425
419
|
largeTitleHideShadow: headerLargeTitleShadowVisible === false,
|
|
426
420
|
title: titleText,
|
|
427
421
|
titleColor,
|
package/src/unstable/types.tsx
CHANGED
|
@@ -101,8 +101,6 @@ type IconImage = {
|
|
|
101
101
|
* Disabling will keep the image's original colors.
|
|
102
102
|
*
|
|
103
103
|
* Defaults to `true`.
|
|
104
|
-
*
|
|
105
|
-
* @platform ios
|
|
106
104
|
*/
|
|
107
105
|
tinted?: boolean;
|
|
108
106
|
};
|
|
@@ -118,10 +116,25 @@ type IconIOSSfSymbol = {
|
|
|
118
116
|
* @platform ios
|
|
119
117
|
*/
|
|
120
118
|
name: SFSymbol;
|
|
119
|
+
/**
|
|
120
|
+
* How to color the symbol.
|
|
121
|
+
* - `monochrome`: Single color, using the tint color.
|
|
122
|
+
* - `multicolor`: Uses the symbol's built-in multicolor scheme.
|
|
123
|
+
*
|
|
124
|
+
* Defaults to a single color for system symbols.
|
|
125
|
+
*
|
|
126
|
+
* @platform ios
|
|
127
|
+
*/
|
|
128
|
+
renderingMode?: 'monochrome' | 'multicolor';
|
|
121
129
|
};
|
|
122
130
|
|
|
123
131
|
export type NativeBottomTabIcon = IconIOSSfSymbol | IconImage;
|
|
124
132
|
|
|
133
|
+
type TabBarLabelOffset = {
|
|
134
|
+
horizontal?: number;
|
|
135
|
+
vertical?: number;
|
|
136
|
+
};
|
|
137
|
+
|
|
125
138
|
export type NativeBottomTabNavigationOptions = NativeHeaderOptions & {
|
|
126
139
|
/**
|
|
127
140
|
* Title text for the screen.
|
|
@@ -130,16 +143,90 @@ export type NativeBottomTabNavigationOptions = NativeHeaderOptions & {
|
|
|
130
143
|
|
|
131
144
|
/**
|
|
132
145
|
* Uses iOS built-in tab bar items with standard iOS styling and localized titles.
|
|
133
|
-
* If set to `search`, it's positioned next to the tab bar on iOS 26 and above.
|
|
134
146
|
*
|
|
135
|
-
* The `tabBarIcon` and `tabBarLabel` options
|
|
147
|
+
* The `tabBarIcon` and `tabBarLabel` options override the icon and label from the system item.
|
|
136
148
|
* If you want to keep the system behavior on iOS, but need to provide icon and label for other platforms,
|
|
137
149
|
* Use `Platform.OS` or `Platform.select` to conditionally set `undefined` for `tabBarIcon` and `tabBarLabel` on iOS.
|
|
138
150
|
*
|
|
151
|
+
* If set to `search`, it may receive the prominent visual treatment on iOS 26.
|
|
152
|
+
* See `tabBarRole` for more details on iOS 27 and above.
|
|
153
|
+
*
|
|
139
154
|
* @platform ios
|
|
140
155
|
*/
|
|
141
156
|
tabBarSystemItem?: TabsScreenSystemItem;
|
|
142
157
|
|
|
158
|
+
/**
|
|
159
|
+
* The role of the tab within the system tab bar.
|
|
160
|
+
*
|
|
161
|
+
* Supported values:
|
|
162
|
+
* - `prominent` - the tab gets the prominent visual treatment when supported
|
|
163
|
+
* - `search` - the tab is used as the system search tab
|
|
164
|
+
*
|
|
165
|
+
* If set to `prominent`, the tab may receive special styling to make it stand out,
|
|
166
|
+
* e.g., being positioned as a separate button next to the tab bar on iOS 27 and above.
|
|
167
|
+
* Only one tab can have the `prominent` role at a time.
|
|
168
|
+
* Supported on iOS 27 and above.
|
|
169
|
+
*
|
|
170
|
+
* If set to `search`, the tab gets the prominent visual treatment on iOS 26.
|
|
171
|
+
* On iOS 27 and above, it gets the prominent styling only if `tabBarSearchAutoFocus` is enabled,
|
|
172
|
+
* and no other tab has the `prominent` role.
|
|
173
|
+
* The tab uses system search icon and label by default.
|
|
174
|
+
* They can be overridden by `tabBarSystemItem`, `tabBarIcon`, and `tabBarLabel` options.
|
|
175
|
+
* Adding or removing the `search` role after the tab is rendered is not supported.
|
|
176
|
+
* Supported on iOS 26.1 and above.
|
|
177
|
+
*
|
|
178
|
+
* @platform ios
|
|
179
|
+
*/
|
|
180
|
+
tabBarRole?: 'prominent' | 'search';
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Whether the search field is automatically focused when the tab is selected.
|
|
184
|
+
* Cancelling the search selects the previously selected tab.
|
|
185
|
+
*
|
|
186
|
+
* Only applies to tabs with `tabBarRole: 'search'`,
|
|
187
|
+
* and requires `headerSearchBarOptions` to be set in a native stack nested in the tab.
|
|
188
|
+
*
|
|
189
|
+
* Defaults to `false`.
|
|
190
|
+
*
|
|
191
|
+
* Supported on iOS 26.1 and above.
|
|
192
|
+
*
|
|
193
|
+
* @platform ios
|
|
194
|
+
*/
|
|
195
|
+
tabBarSearchAutoFocus?: boolean;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Whether the sidebar or the tab bar is preferred when only one of them can be displayed.
|
|
199
|
+
*
|
|
200
|
+
* Supported values:
|
|
201
|
+
* - `auto` - uses the system default (tab bar)
|
|
202
|
+
* - `sidebar` - the sidebar is displayed when it's available
|
|
203
|
+
* - `tabBar` - the tab bar is displayed
|
|
204
|
+
*
|
|
205
|
+
* Requires `tabBarControllerMode` to be set to `tabSidebar`.
|
|
206
|
+
*
|
|
207
|
+
* The sidebar is only available when the horizontal size class is regular,
|
|
208
|
+
* e.g. on iPad, or on larger iPhones in landscape.
|
|
209
|
+
*
|
|
210
|
+
* Defaults to `auto`.
|
|
211
|
+
*
|
|
212
|
+
* Supported on iOS 27 and above.
|
|
213
|
+
* Not supported on tvOS.
|
|
214
|
+
*
|
|
215
|
+
* @platform ios
|
|
216
|
+
*/
|
|
217
|
+
tabBarSidebarPreferredPlacement?: 'auto' | 'sidebar' | 'tabBar';
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Whether showing and hiding the tab bar is animated.
|
|
221
|
+
*
|
|
222
|
+
* Defaults to `true`.
|
|
223
|
+
*
|
|
224
|
+
* Supported on iOS 18 and above.
|
|
225
|
+
*
|
|
226
|
+
* @platform ios
|
|
227
|
+
*/
|
|
228
|
+
tabBarVisibilityAnimationEnabled?: boolean;
|
|
229
|
+
|
|
143
230
|
/**
|
|
144
231
|
* Title string of the tab displayed in the tab bar
|
|
145
232
|
*
|
|
@@ -186,6 +273,16 @@ export type NativeBottomTabNavigationOptions = NativeHeaderOptions & {
|
|
|
186
273
|
| NativeBottomTabIcon
|
|
187
274
|
| ((props: { focused: boolean }) => NativeBottomTabIcon);
|
|
188
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Size of the tab's icon.
|
|
278
|
+
*
|
|
279
|
+
* The largest size is used for the icon area in all tabs.
|
|
280
|
+
* Icons smaller than the largest size are centered in this area.
|
|
281
|
+
*
|
|
282
|
+
* @platform android
|
|
283
|
+
*/
|
|
284
|
+
tabBarIconSize?: number;
|
|
285
|
+
|
|
189
286
|
/**
|
|
190
287
|
* Text to show in a badge on the tab icon.
|
|
191
288
|
*/
|
|
@@ -228,6 +325,20 @@ export type NativeBottomTabNavigationOptions = NativeHeaderOptions & {
|
|
|
228
325
|
*/
|
|
229
326
|
tabBarActiveIndicatorEnabled?: boolean;
|
|
230
327
|
|
|
328
|
+
/**
|
|
329
|
+
* Width of the tab's active indicator.
|
|
330
|
+
*
|
|
331
|
+
* @platform android
|
|
332
|
+
*/
|
|
333
|
+
tabBarActiveIndicatorWidth?: number;
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Height of the tab's active indicator.
|
|
337
|
+
*
|
|
338
|
+
* @platform android
|
|
339
|
+
*/
|
|
340
|
+
tabBarActiveIndicatorHeight?: number;
|
|
341
|
+
|
|
231
342
|
/**
|
|
232
343
|
* Color of tab bar item's ripple effect.
|
|
233
344
|
*
|
|
@@ -347,6 +458,24 @@ export type NativeBottomTabNavigationOptions = NativeHeaderOptions & {
|
|
|
347
458
|
*/
|
|
348
459
|
tabBarMinimizeBehavior?: 'auto' | 'none' | 'onScrollDown' | 'onScrollUp';
|
|
349
460
|
|
|
461
|
+
/**
|
|
462
|
+
* Offset applied to the tab label relative to its default position.
|
|
463
|
+
* Positive `vertical` moves the label down, positive `horizontal` moves it right.
|
|
464
|
+
*
|
|
465
|
+
* The offset is specified separately for each tab bar item layout:
|
|
466
|
+
*
|
|
467
|
+
* - `stacked` - icon above the label, e.g. on iPhone in portrait
|
|
468
|
+
* - `inline` - icon beside the label in regular width, e.g. on iPad
|
|
469
|
+
* - `compactInline` - icon beside the label in compact width, e.g. on iPhone in landscape
|
|
470
|
+
*
|
|
471
|
+
* @platform ios
|
|
472
|
+
*/
|
|
473
|
+
tabBarLabelPositionAdjustment?: {
|
|
474
|
+
stacked?: TabBarLabelOffset;
|
|
475
|
+
inline?: TabBarLabelOffset;
|
|
476
|
+
compactInline?: TabBarLabelOffset;
|
|
477
|
+
};
|
|
478
|
+
|
|
350
479
|
/**
|
|
351
480
|
* Function which returns a React element to display as an accessory view.
|
|
352
481
|
*
|
|
@@ -419,10 +548,7 @@ export type NativeBottomTabNavigationConfig = {};
|
|
|
419
548
|
export type NativeBottomTabBarProps = {
|
|
420
549
|
state: TabNavigationState<ParamListBase>;
|
|
421
550
|
descriptors: NativeBottomTabDescriptorMap;
|
|
422
|
-
navigation:
|
|
423
|
-
ParamListBase,
|
|
424
|
-
NativeBottomTabNavigationEventMap
|
|
425
|
-
>;
|
|
551
|
+
navigation: NativeBottomTabNavigationHelpers;
|
|
426
552
|
insets: EdgeInsets;
|
|
427
553
|
};
|
|
428
554
|
|
|
@@ -23,9 +23,15 @@ import {
|
|
|
23
23
|
View,
|
|
24
24
|
type ViewStyle,
|
|
25
25
|
} from 'react-native';
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
import type {
|
|
26
|
+
import type { EdgeInsets } from 'react-native-safe-area-context';
|
|
27
|
+
|
|
28
|
+
import type {
|
|
29
|
+
BottomTabBarProps,
|
|
30
|
+
BottomTabDescriptor,
|
|
31
|
+
BottomTabDescriptorMap,
|
|
32
|
+
LabelVisibilityMode,
|
|
33
|
+
Variant,
|
|
34
|
+
} from '../types';
|
|
29
35
|
import { BottomTabBarHeightCallbackContext } from '../utils/BottomTabBarHeightCallbackContext';
|
|
30
36
|
import { useIsKeyboardShown } from '../utils/useIsKeyboardShown';
|
|
31
37
|
import { BottomTabItem } from './BottomTabItem';
|
|
@@ -175,6 +181,7 @@ export function BottomTabBar({
|
|
|
175
181
|
tabBarVariant = 'uikit',
|
|
176
182
|
tabBarStyle,
|
|
177
183
|
tabBarBackground,
|
|
184
|
+
tabBarTransparent,
|
|
178
185
|
tabBarActiveTintColor,
|
|
179
186
|
tabBarInactiveTintColor,
|
|
180
187
|
tabBarActiveBackgroundColor,
|
|
@@ -241,7 +248,7 @@ export function BottomTabBar({
|
|
|
241
248
|
}
|
|
242
249
|
});
|
|
243
250
|
} else {
|
|
244
|
-
// eslint-disable-next-line @eslint-react/
|
|
251
|
+
// eslint-disable-next-line @eslint-react/set-state-in-effect
|
|
245
252
|
setIsTabBarHidden(true);
|
|
246
253
|
|
|
247
254
|
const animation =
|
|
@@ -319,7 +326,9 @@ export function BottomTabBar({
|
|
|
319
326
|
? styles.start
|
|
320
327
|
: tabBarPosition === 'right'
|
|
321
328
|
? styles.end
|
|
322
|
-
:
|
|
329
|
+
: tabBarPosition === 'top'
|
|
330
|
+
? styles.top
|
|
331
|
+
: styles.bottom,
|
|
323
332
|
(
|
|
324
333
|
Platform.OS === 'web'
|
|
325
334
|
? tabBarPosition === 'right'
|
|
@@ -380,6 +389,7 @@ export function BottomTabBar({
|
|
|
380
389
|
paddingHorizontal: Math.max(insets.left, insets.right),
|
|
381
390
|
},
|
|
382
391
|
],
|
|
392
|
+
tabBarTransparent ? styles.transparent : null,
|
|
383
393
|
tabBarStyle,
|
|
384
394
|
]}
|
|
385
395
|
pointerEvents={isTabBarHidden ? 'none' : 'auto'}
|
|
@@ -396,38 +406,6 @@ export function BottomTabBar({
|
|
|
396
406
|
const focused = index === state.index;
|
|
397
407
|
const { options } = descriptors[route.key];
|
|
398
408
|
|
|
399
|
-
const onPress = () => {
|
|
400
|
-
const event = navigation.emit({
|
|
401
|
-
type: 'tabPress',
|
|
402
|
-
target: route.key,
|
|
403
|
-
canPreventDefault: true,
|
|
404
|
-
data: {
|
|
405
|
-
behavior: {
|
|
406
|
-
scrollToTop:
|
|
407
|
-
focused &&
|
|
408
|
-
options.tabBarRepeatedPressBehavior?.scrollToTop !== false,
|
|
409
|
-
popToTop:
|
|
410
|
-
focused &&
|
|
411
|
-
options.tabBarRepeatedPressBehavior?.popToTop !== false,
|
|
412
|
-
},
|
|
413
|
-
},
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
if (!focused && !event.defaultPrevented) {
|
|
417
|
-
navigation.dispatch({
|
|
418
|
-
...CommonActions.navigate(route.name, route.params),
|
|
419
|
-
target: state.key,
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
const onLongPress = () => {
|
|
425
|
-
navigation.emit({
|
|
426
|
-
type: 'tabLongPress',
|
|
427
|
-
target: route.key,
|
|
428
|
-
});
|
|
429
|
-
};
|
|
430
|
-
|
|
431
409
|
const label =
|
|
432
410
|
typeof options.tabBarLabel === 'function'
|
|
433
411
|
? options.tabBarLabel
|
|
@@ -444,57 +422,28 @@ export function BottomTabBar({
|
|
|
444
422
|
: undefined;
|
|
445
423
|
|
|
446
424
|
return (
|
|
447
|
-
<
|
|
425
|
+
<BottomTabBarItem
|
|
448
426
|
key={route.key}
|
|
449
427
|
route={route}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
inactiveBackgroundColor={tabBarInactiveBackgroundColor}
|
|
470
|
-
button={options.tabBarButton}
|
|
471
|
-
icon={
|
|
472
|
-
options.tabBarIcon ??
|
|
473
|
-
(({ color, size }) => (
|
|
474
|
-
<MissingIcon color={color} size={size} />
|
|
475
|
-
))
|
|
476
|
-
}
|
|
477
|
-
badge={options.tabBarBadge}
|
|
478
|
-
badgeStyle={options.tabBarBadgeStyle}
|
|
479
|
-
label={label}
|
|
480
|
-
showLabel={tabBarShowLabel}
|
|
481
|
-
labelVisibilityMode={tabBarLabelVisibilityMode}
|
|
482
|
-
labelStyle={options.tabBarLabelStyle}
|
|
483
|
-
iconStyle={options.tabBarIconStyle}
|
|
484
|
-
style={[
|
|
485
|
-
sidebar
|
|
486
|
-
? {
|
|
487
|
-
marginVertical: hasHorizontalLabels
|
|
488
|
-
? tabBarVariant === 'material'
|
|
489
|
-
? 0
|
|
490
|
-
: 1
|
|
491
|
-
: spacing / 2,
|
|
492
|
-
}
|
|
493
|
-
: styles.bottomItem,
|
|
494
|
-
options.tabBarItemStyle,
|
|
495
|
-
]}
|
|
496
|
-
/>
|
|
497
|
-
</NavigationProvider>
|
|
428
|
+
descriptor={descriptors[route.key]}
|
|
429
|
+
navigation={navigation}
|
|
430
|
+
navigatorKey={state.key}
|
|
431
|
+
href={buildHref(route.name, route.params)}
|
|
432
|
+
focused={focused}
|
|
433
|
+
label={label}
|
|
434
|
+
accessibilityLabel={accessibilityLabel}
|
|
435
|
+
hasHorizontalLabels={hasHorizontalLabels}
|
|
436
|
+
compact={compact}
|
|
437
|
+
sidebar={sidebar}
|
|
438
|
+
tabBarVariant={tabBarVariant}
|
|
439
|
+
spacing={spacing}
|
|
440
|
+
tabBarActiveTintColor={tabBarActiveTintColor}
|
|
441
|
+
tabBarInactiveTintColor={tabBarInactiveTintColor}
|
|
442
|
+
tabBarActiveBackgroundColor={tabBarActiveBackgroundColor}
|
|
443
|
+
tabBarInactiveBackgroundColor={tabBarInactiveBackgroundColor}
|
|
444
|
+
tabBarShowLabel={tabBarShowLabel}
|
|
445
|
+
tabBarLabelVisibilityMode={tabBarLabelVisibilityMode}
|
|
446
|
+
/>
|
|
498
447
|
);
|
|
499
448
|
})}
|
|
500
449
|
</View>
|
|
@@ -502,6 +451,132 @@ export function BottomTabBar({
|
|
|
502
451
|
);
|
|
503
452
|
}
|
|
504
453
|
|
|
454
|
+
type BottomTabBarItemProps = {
|
|
455
|
+
route: TabNavigationState<ParamListBase>['routes'][number];
|
|
456
|
+
descriptor: BottomTabDescriptor;
|
|
457
|
+
navigation: BottomTabBarProps['navigation'];
|
|
458
|
+
navigatorKey: string;
|
|
459
|
+
href: string | undefined;
|
|
460
|
+
focused: boolean;
|
|
461
|
+
label: React.ComponentProps<typeof BottomTabItem>['label'];
|
|
462
|
+
accessibilityLabel: string | undefined;
|
|
463
|
+
hasHorizontalLabels: boolean;
|
|
464
|
+
compact: boolean;
|
|
465
|
+
sidebar: boolean;
|
|
466
|
+
tabBarVariant: Variant;
|
|
467
|
+
spacing: number;
|
|
468
|
+
tabBarActiveTintColor: string | undefined;
|
|
469
|
+
tabBarInactiveTintColor: string | undefined;
|
|
470
|
+
tabBarActiveBackgroundColor: string | undefined;
|
|
471
|
+
tabBarInactiveBackgroundColor: string | undefined;
|
|
472
|
+
tabBarShowLabel: boolean | undefined;
|
|
473
|
+
tabBarLabelVisibilityMode: LabelVisibilityMode | undefined;
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
const BottomTabBarItem = React.memo(function BottomTabBarItem({
|
|
477
|
+
route,
|
|
478
|
+
descriptor,
|
|
479
|
+
navigation,
|
|
480
|
+
navigatorKey,
|
|
481
|
+
href,
|
|
482
|
+
focused,
|
|
483
|
+
label,
|
|
484
|
+
accessibilityLabel,
|
|
485
|
+
hasHorizontalLabels,
|
|
486
|
+
compact,
|
|
487
|
+
sidebar,
|
|
488
|
+
tabBarVariant,
|
|
489
|
+
spacing,
|
|
490
|
+
tabBarActiveTintColor,
|
|
491
|
+
tabBarInactiveTintColor,
|
|
492
|
+
tabBarActiveBackgroundColor,
|
|
493
|
+
tabBarInactiveBackgroundColor,
|
|
494
|
+
tabBarShowLabel,
|
|
495
|
+
tabBarLabelVisibilityMode,
|
|
496
|
+
}: BottomTabBarItemProps) {
|
|
497
|
+
const { options } = descriptor;
|
|
498
|
+
|
|
499
|
+
const onPress = () => {
|
|
500
|
+
const event = navigation.emit({
|
|
501
|
+
type: 'tabPress',
|
|
502
|
+
target: route.key,
|
|
503
|
+
canPreventDefault: true,
|
|
504
|
+
data: {
|
|
505
|
+
behavior: {
|
|
506
|
+
scrollToTop:
|
|
507
|
+
focused &&
|
|
508
|
+
options.tabBarRepeatedPressBehavior?.scrollToTop !== false,
|
|
509
|
+
popToTop:
|
|
510
|
+
focused && options.tabBarRepeatedPressBehavior?.popToTop !== false,
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
if (!focused && !event.defaultPrevented) {
|
|
516
|
+
navigation.dispatch({
|
|
517
|
+
...CommonActions.navigate(route.name, route.params),
|
|
518
|
+
target: navigatorKey,
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
const onLongPress = () => {
|
|
524
|
+
navigation.emit({
|
|
525
|
+
type: 'tabLongPress',
|
|
526
|
+
target: route.key,
|
|
527
|
+
});
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
return (
|
|
531
|
+
<NavigationProvider route={route} navigation={descriptor.navigation}>
|
|
532
|
+
<BottomTabItem
|
|
533
|
+
href={href}
|
|
534
|
+
route={route}
|
|
535
|
+
descriptor={descriptor}
|
|
536
|
+
focused={focused}
|
|
537
|
+
horizontal={hasHorizontalLabels}
|
|
538
|
+
compact={compact}
|
|
539
|
+
sidebar={sidebar}
|
|
540
|
+
variant={tabBarVariant}
|
|
541
|
+
onPress={onPress}
|
|
542
|
+
onLongPress={onLongPress}
|
|
543
|
+
accessibilityLabel={accessibilityLabel}
|
|
544
|
+
testID={options.tabBarButtonTestID}
|
|
545
|
+
allowFontScaling={options.tabBarAllowFontScaling}
|
|
546
|
+
activeTintColor={tabBarActiveTintColor}
|
|
547
|
+
inactiveTintColor={tabBarInactiveTintColor}
|
|
548
|
+
activeBackgroundColor={tabBarActiveBackgroundColor}
|
|
549
|
+
inactiveBackgroundColor={tabBarInactiveBackgroundColor}
|
|
550
|
+
button={options.tabBarButton}
|
|
551
|
+
icon={
|
|
552
|
+
options.tabBarIcon ??
|
|
553
|
+
(({ color, size }) => <MissingIcon color={color} size={size} />)
|
|
554
|
+
}
|
|
555
|
+
badge={options.tabBarBadge}
|
|
556
|
+
badgeStyle={options.tabBarBadgeStyle}
|
|
557
|
+
label={label}
|
|
558
|
+
showLabel={tabBarShowLabel}
|
|
559
|
+
labelVisibilityMode={tabBarLabelVisibilityMode}
|
|
560
|
+
labelStyle={options.tabBarLabelStyle}
|
|
561
|
+
iconSize={options.tabBarIconSize}
|
|
562
|
+
iconStyle={options.tabBarIconStyle}
|
|
563
|
+
style={[
|
|
564
|
+
sidebar
|
|
565
|
+
? {
|
|
566
|
+
marginVertical: hasHorizontalLabels
|
|
567
|
+
? tabBarVariant === 'material'
|
|
568
|
+
? 0
|
|
569
|
+
: 1
|
|
570
|
+
: spacing / 2,
|
|
571
|
+
}
|
|
572
|
+
: styles.bottomItem,
|
|
573
|
+
options.tabBarItemStyle,
|
|
574
|
+
]}
|
|
575
|
+
/>
|
|
576
|
+
</NavigationProvider>
|
|
577
|
+
);
|
|
578
|
+
});
|
|
579
|
+
|
|
505
580
|
const styles = StyleSheet.create({
|
|
506
581
|
start: {
|
|
507
582
|
top: 0,
|
|
@@ -513,12 +588,27 @@ const styles = StyleSheet.create({
|
|
|
513
588
|
bottom: 0,
|
|
514
589
|
end: 0,
|
|
515
590
|
},
|
|
591
|
+
top: {
|
|
592
|
+
start: 0,
|
|
593
|
+
end: 0,
|
|
594
|
+
top: 0,
|
|
595
|
+
elevation: 8,
|
|
596
|
+
},
|
|
516
597
|
bottom: {
|
|
517
598
|
start: 0,
|
|
518
599
|
end: 0,
|
|
519
600
|
bottom: 0,
|
|
520
601
|
elevation: 8,
|
|
521
602
|
},
|
|
603
|
+
transparent: {
|
|
604
|
+
position: 'absolute',
|
|
605
|
+
backgroundColor: 'transparent',
|
|
606
|
+
borderTopWidth: 0,
|
|
607
|
+
borderBottomWidth: 0,
|
|
608
|
+
borderLeftWidth: 0,
|
|
609
|
+
borderRightWidth: 0,
|
|
610
|
+
elevation: 0,
|
|
611
|
+
},
|
|
522
612
|
bottomContent: {
|
|
523
613
|
flex: 1,
|
|
524
614
|
flexDirection: 'row',
|
|
@@ -140,6 +140,10 @@ type Props = {
|
|
|
140
140
|
* Style object for the label element.
|
|
141
141
|
*/
|
|
142
142
|
labelStyle?: StyleProp<TextStyle>;
|
|
143
|
+
/**
|
|
144
|
+
* Size of the icon.
|
|
145
|
+
*/
|
|
146
|
+
iconSize?: number;
|
|
143
147
|
/**
|
|
144
148
|
* Style object for the icon element.
|
|
145
149
|
*/
|
|
@@ -186,6 +190,7 @@ export function BottomTabItem({
|
|
|
186
190
|
// https://developer.apple.com/documentation/uikit/uiview/3183939-largecontenttitle
|
|
187
191
|
allowFontScaling = SUPPORTS_LARGE_CONTENT_VIEWER ? false : undefined,
|
|
188
192
|
labelStyle,
|
|
193
|
+
iconSize,
|
|
189
194
|
iconStyle,
|
|
190
195
|
style,
|
|
191
196
|
}: Props) {
|
|
@@ -300,6 +305,7 @@ export function BottomTabItem({
|
|
|
300
305
|
route={route}
|
|
301
306
|
variant={variant}
|
|
302
307
|
size={compact ? 'compact' : 'regular'}
|
|
308
|
+
iconSize={iconSize}
|
|
303
309
|
badge={badge}
|
|
304
310
|
badgeStyle={badgeStyle}
|
|
305
311
|
activeOpacity={activeOpacity}
|
|
@@ -319,7 +325,7 @@ export function BottomTabItem({
|
|
|
319
325
|
? activeBackgroundColor
|
|
320
326
|
: inactiveBackgroundColor;
|
|
321
327
|
|
|
322
|
-
const
|
|
328
|
+
const flex = StyleSheet.flatten(style)?.flex;
|
|
323
329
|
const borderRadius =
|
|
324
330
|
variant === 'material'
|
|
325
331
|
? horizontal
|
|
@@ -335,7 +341,10 @@ export function BottomTabItem({
|
|
|
335
341
|
// Clip ripple effect on Android
|
|
336
342
|
{
|
|
337
343
|
borderRadius,
|
|
338
|
-
overflow:
|
|
344
|
+
overflow:
|
|
345
|
+
Platform.OS === 'android' && variant === 'material'
|
|
346
|
+
? 'hidden'
|
|
347
|
+
: 'visible',
|
|
339
348
|
},
|
|
340
349
|
style,
|
|
341
350
|
]}
|