@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.
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/navigators/createBottomTabNavigator.js +4 -25
- package/lib/module/navigators/createBottomTabNavigator.js.map +1 -1
- package/lib/module/utils/useBottomTabAnimation.js +1 -1
- package/lib/module/utils/useBottomTabAnimation.js.map +1 -1
- package/lib/module/utils/useBottomTabBarHeight.js +1 -1
- package/lib/module/utils/useBottomTabBarHeight.js.map +1 -1
- package/lib/module/utils/useIsKeyboardShown.js.map +1 -1
- package/lib/module/views/BottomTabBar.js +40 -29
- package/lib/module/views/BottomTabBar.js.map +1 -1
- package/lib/module/views/BottomTabItem.js +3 -5
- package/lib/module/views/BottomTabItem.js.map +1 -1
- package/lib/module/views/{BottomTabViewCommon.js → BottomTabView.js} +1 -1
- package/lib/module/views/BottomTabView.js.map +1 -0
- package/lib/module/views/BottomTabViewCustom.js +97 -81
- package/lib/module/views/BottomTabViewCustom.js.map +1 -1
- package/lib/module/views/BottomTabViewNativeImpl.js +339 -121
- package/lib/module/views/BottomTabViewNativeImpl.js.map +1 -1
- package/lib/module/views/Deferred.js +41 -0
- package/lib/module/views/Deferred.js.map +1 -0
- package/lib/module/views/ScreenContent.js.map +1 -1
- package/lib/module/views/TabBarIcon.js +11 -48
- package/lib/module/views/TabBarIcon.js.map +1 -1
- package/lib/typescript/src/TransitionConfigs/SceneStyleInterpolators.d.ts +1 -1
- package/lib/typescript/src/TransitionConfigs/SceneStyleInterpolators.d.ts.map +1 -1
- package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts +1 -1
- package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts.map +1 -1
- package/lib/typescript/src/TransitionConfigs/TransitionSpecs.d.ts +1 -1
- package/lib/typescript/src/TransitionConfigs/TransitionSpecs.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +11 -11
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/navigators/createBottomTabNavigator.d.ts +9 -15
- package/lib/typescript/src/navigators/createBottomTabNavigator.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +66 -104
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/BottomTabAnimationContext.d.ts +1 -1
- package/lib/typescript/src/utils/BottomTabAnimationContext.d.ts.map +1 -1
- package/lib/typescript/src/utils/useAnimatedHashMap.d.ts +1 -1
- package/lib/typescript/src/utils/useAnimatedHashMap.d.ts.map +1 -1
- package/lib/typescript/src/utils/useBottomTabAnimation.d.ts +1 -1
- package/lib/typescript/src/utils/useBottomTabAnimation.d.ts.map +1 -1
- package/lib/typescript/src/utils/useTabBarPosition.d.ts +1 -1
- package/lib/typescript/src/utils/useTabBarPosition.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabBar.d.ts +3 -2
- package/lib/typescript/src/views/BottomTabBar.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabItem.d.ts +20 -20
- package/lib/typescript/src/views/BottomTabItem.d.ts.map +1 -1
- package/lib/typescript/src/views/{BottomTabViewCommon.d.ts → BottomTabView.d.ts} +3 -3
- package/lib/typescript/src/views/BottomTabView.d.ts.map +1 -0
- package/lib/typescript/src/views/BottomTabViewCustom.d.ts +3 -2
- package/lib/typescript/src/views/BottomTabViewCustom.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabViewNative.android.d.ts +1 -1
- package/lib/typescript/src/views/BottomTabViewNative.android.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabViewNative.d.ts +1 -1
- package/lib/typescript/src/views/BottomTabViewNative.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabViewNative.ios.d.ts +1 -1
- package/lib/typescript/src/views/BottomTabViewNative.ios.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabViewNativeImpl.d.ts +3 -2
- package/lib/typescript/src/views/BottomTabViewNativeImpl.d.ts.map +1 -1
- package/lib/typescript/src/views/Deferred.d.ts +31 -0
- package/lib/typescript/src/views/Deferred.d.ts.map +1 -0
- package/lib/typescript/src/views/ScreenContent.d.ts +4 -4
- package/lib/typescript/src/views/ScreenContent.d.ts.map +1 -1
- package/lib/typescript/src/views/TabBarIcon.d.ts +8 -8
- package/lib/typescript/src/views/TabBarIcon.d.ts.map +1 -1
- package/package.json +22 -22
- package/src/index.tsx +2 -2
- package/src/navigators/createBottomTabNavigator.tsx +10 -75
- package/src/types.tsx +66 -112
- package/src/utils/useAnimatedHashMap.tsx +1 -1
- package/src/utils/useBottomTabAnimation.tsx +1 -1
- package/src/utils/useBottomTabBarHeight.tsx +1 -1
- package/src/utils/useIsKeyboardShown.tsx +2 -2
- package/src/views/BottomTabBar.tsx +68 -25
- package/src/views/BottomTabItem.tsx +19 -21
- package/src/views/BottomTabViewCustom.tsx +172 -143
- package/src/views/BottomTabViewNativeImpl.tsx +480 -161
- package/src/views/Deferred.tsx +57 -0
- package/src/views/ScreenContent.tsx +1 -2
- package/src/views/TabBarIcon.tsx +13 -56
- package/lib/module/views/BottomTabViewCommon.js.map +0 -1
- package/lib/typescript/src/views/BottomTabViewCommon.d.ts.map +0 -1
- /package/src/views/{BottomTabViewCommon.tsx → BottomTabView.tsx} +0 -0
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { getLabel } from '@react-navigation/elements';
|
|
4
|
-
import {
|
|
4
|
+
import { ActivityView, Color, SafeAreaProviderCompat } from '@react-navigation/elements/internal';
|
|
5
5
|
import { CommonActions, MaterialSymbol, NavigationMetaContext, StackActions, useTheme } from '@react-navigation/native';
|
|
6
6
|
import * as React from 'react';
|
|
7
|
-
import { Animated, Platform, PlatformColor } from 'react-native';
|
|
7
|
+
import { Animated, Platform, PlatformColor, StyleSheet } from 'react-native';
|
|
8
8
|
import { Tabs } from 'react-native-screens';
|
|
9
9
|
import { BottomTabAnimationContext } from "../utils/BottomTabAnimationContext.js";
|
|
10
10
|
import { BottomTabBarHeightContext } from "../utils/BottomTabBarHeightContext.js";
|
|
11
11
|
import { useTabBarPosition } from "../utils/useTabBarPosition.js";
|
|
12
|
+
import { Deferred } from "./Deferred.js";
|
|
12
13
|
import { ScreenContent } from "./ScreenContent.js";
|
|
13
14
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
15
|
const ICON_SIZE = Platform.select({
|
|
@@ -18,6 +19,26 @@ const ICON_SIZE = Platform.select({
|
|
|
18
19
|
const meta = {
|
|
19
20
|
type: 'native-tabs'
|
|
20
21
|
};
|
|
22
|
+
function reducer(state, action) {
|
|
23
|
+
switch (action.type) {
|
|
24
|
+
case 'TRACK_TRANSITION':
|
|
25
|
+
return {
|
|
26
|
+
...state,
|
|
27
|
+
lastTransition: action.lastTransition,
|
|
28
|
+
confirmed: action.confirmed
|
|
29
|
+
};
|
|
30
|
+
case 'CLEAR_TRANSITION':
|
|
31
|
+
return state.lastTransition?.to === action.to ? {
|
|
32
|
+
...state,
|
|
33
|
+
lastTransition: null
|
|
34
|
+
} : state;
|
|
35
|
+
case 'CONFIRM_STATE':
|
|
36
|
+
return state.confirmed.routeKey === action.confirmed.routeKey && state.confirmed.provenance === action.confirmed.provenance ? state : {
|
|
37
|
+
...state,
|
|
38
|
+
confirmed: action.confirmed
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
21
42
|
export function BottomTabViewNative({
|
|
22
43
|
state,
|
|
23
44
|
navigation,
|
|
@@ -29,23 +50,147 @@ export function BottomTabViewNative({
|
|
|
29
50
|
colors,
|
|
30
51
|
fonts
|
|
31
52
|
} = useTheme();
|
|
32
|
-
const
|
|
53
|
+
const focusedRoute = state.routes[state.index];
|
|
54
|
+
if (focusedRoute == null) {
|
|
55
|
+
throw new Error(`Couldn't find a route at index ${state.index}.`);
|
|
56
|
+
}
|
|
57
|
+
const focusedRouteKey = focusedRoute.key;
|
|
58
|
+
const [loaded, setLoaded] = React.useState([focusedRouteKey]);
|
|
59
|
+
if (!loaded.includes(focusedRouteKey)) {
|
|
60
|
+
setLoaded([...loaded, focusedRouteKey]);
|
|
61
|
+
}
|
|
62
|
+
const [nativeState, dispatch] = React.useReducer(reducer, {
|
|
63
|
+
lastTransition: null,
|
|
64
|
+
confirmed: {
|
|
65
|
+
routeKey: focusedRouteKey,
|
|
66
|
+
provenance: 0
|
|
67
|
+
}
|
|
68
|
+
});
|
|
33
69
|
const previousRouteKeyRef = React.useRef(focusedRouteKey);
|
|
34
70
|
React.useEffect(() => {
|
|
35
71
|
const previousRouteKey = previousRouteKeyRef.current;
|
|
36
72
|
if (previousRouteKey !== focusedRouteKey && descriptors[previousRouteKey]?.options.popToTopOnBlur) {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
73
|
+
const currentState = navigation.getState();
|
|
74
|
+
const prevRoute = currentState.routes.find(route => route.key === previousRouteKey);
|
|
75
|
+
if (prevRoute?.state?.type === 'stack' && prevRoute.state.key && ((prevRoute.state.index ?? prevRoute.state.routes.length - 1) > 0 || prevRoute.state.routes[0]?.history?.length)) {
|
|
76
|
+
navigation.dispatch({
|
|
40
77
|
...StackActions.popToTop(),
|
|
41
78
|
target: prevRoute.state.key
|
|
42
|
-
};
|
|
43
|
-
navigation.dispatch(popToTopAction);
|
|
79
|
+
});
|
|
44
80
|
}
|
|
45
81
|
}
|
|
46
82
|
previousRouteKeyRef.current = focusedRouteKey;
|
|
47
|
-
|
|
48
|
-
|
|
83
|
+
|
|
84
|
+
// We dispatch `popToTop` for unfocused tabs when `popToTopOnBlur` is true
|
|
85
|
+
// So we delay clearing `lastTransition` to keep the screen active for longer
|
|
86
|
+
// This gives time for the action to be handled before the screen is paused,
|
|
87
|
+
const timer = setTimeout(() => {
|
|
88
|
+
dispatch({
|
|
89
|
+
type: 'CLEAR_TRANSITION',
|
|
90
|
+
to: focusedRouteKey
|
|
91
|
+
});
|
|
92
|
+
}, 32);
|
|
93
|
+
return () => clearTimeout(timer);
|
|
94
|
+
}, [descriptors, focusedRouteKey, navigation]);
|
|
95
|
+
const navigate = (route, confirmed) => {
|
|
96
|
+
dispatch({
|
|
97
|
+
type: 'TRACK_TRANSITION',
|
|
98
|
+
confirmed,
|
|
99
|
+
lastTransition: {
|
|
100
|
+
from: previousRouteKeyRef.current,
|
|
101
|
+
to: route.key
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
navigation.dispatch({
|
|
105
|
+
...CommonActions.navigate(route.name, route.params),
|
|
106
|
+
target: state.key
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Native tabs are the source of truth for the selected tab.
|
|
111
|
+
// JS sends a requested tab with the native provenance it was based on.
|
|
112
|
+
// Native replies with the selected tab and its new provenance.
|
|
113
|
+
const onTabSelected = event => {
|
|
114
|
+
const {
|
|
115
|
+
selectedScreenKey,
|
|
116
|
+
provenance,
|
|
117
|
+
actionOrigin
|
|
118
|
+
} = event.nativeEvent;
|
|
119
|
+
const confirmed = {
|
|
120
|
+
routeKey: selectedScreenKey,
|
|
121
|
+
provenance
|
|
122
|
+
};
|
|
123
|
+
const route = state.routes.find(route => route.key === selectedScreenKey);
|
|
124
|
+
if (!route) {
|
|
125
|
+
console.error(`Received 'tabSelected' for route that doesn't exist: ${selectedScreenKey}`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (actionOrigin === 'user') {
|
|
129
|
+
const event = navigation.emit({
|
|
130
|
+
type: 'tabPress',
|
|
131
|
+
target: route.key,
|
|
132
|
+
canPreventDefault: true
|
|
133
|
+
});
|
|
134
|
+
if (event.defaultPrevented) {
|
|
135
|
+
throw new Error("Preventing default for 'tabPress' is not supported with native tab bar. Use the 'tabBarSelectionEnabled: false' option instead.");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (actionOrigin === 'programmatic-js' || focusedRouteKey === route.key) {
|
|
139
|
+
dispatch({
|
|
140
|
+
type: 'CONFIRM_STATE',
|
|
141
|
+
confirmed
|
|
142
|
+
});
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
navigate(route, confirmed);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// If native rejects a JS request, keep native as the source of truth
|
|
149
|
+
// and move JS back to the tab that native says is selected.
|
|
150
|
+
const onTabSelectionRejected = event => {
|
|
151
|
+
const {
|
|
152
|
+
selectedScreenKey,
|
|
153
|
+
provenance
|
|
154
|
+
} = event.nativeEvent;
|
|
155
|
+
const confirmed = {
|
|
156
|
+
routeKey: selectedScreenKey,
|
|
157
|
+
provenance
|
|
158
|
+
};
|
|
159
|
+
const route = state.routes.find(route => route.key === selectedScreenKey);
|
|
160
|
+
if (!route) {
|
|
161
|
+
console.error(`Received 'tabSelectionRejected' for route that doesn't exist: ${selectedScreenKey}`);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (focusedRouteKey === route.key) {
|
|
165
|
+
dispatch({
|
|
166
|
+
type: 'CONFIRM_STATE',
|
|
167
|
+
confirmed
|
|
168
|
+
});
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
navigate(route, confirmed);
|
|
172
|
+
};
|
|
173
|
+
const onTabSelectionPrevented = event => {
|
|
174
|
+
const {
|
|
175
|
+
selectedScreenKey,
|
|
176
|
+
provenance,
|
|
177
|
+
preventedScreenKey
|
|
178
|
+
} = event.nativeEvent;
|
|
179
|
+
const confirmed = {
|
|
180
|
+
routeKey: selectedScreenKey,
|
|
181
|
+
provenance
|
|
182
|
+
};
|
|
183
|
+
dispatch({
|
|
184
|
+
type: 'CONFIRM_STATE',
|
|
185
|
+
confirmed
|
|
186
|
+
});
|
|
187
|
+
navigation.emit({
|
|
188
|
+
type: 'tabPress',
|
|
189
|
+
target: preventedScreenKey,
|
|
190
|
+
canPreventDefault: true
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
const currentOptions = descriptors[focusedRouteKey]?.options ?? {};
|
|
49
194
|
const {
|
|
50
195
|
fontFamily = Platform.select({
|
|
51
196
|
ios: fonts.medium.fontFamily,
|
|
@@ -56,14 +201,48 @@ export function BottomTabViewNative({
|
|
|
56
201
|
default: fonts.regular.fontWeight
|
|
57
202
|
}),
|
|
58
203
|
fontSize,
|
|
59
|
-
fontStyle
|
|
204
|
+
fontStyle,
|
|
205
|
+
color: fontColor
|
|
60
206
|
} = currentOptions.tabBarLabelStyle || {};
|
|
61
|
-
const
|
|
62
|
-
const
|
|
207
|
+
const backgroundColor = currentOptions.tabBarStyle?.backgroundColor ?? colors.background;
|
|
208
|
+
const shouldHideTabBar = currentOptions.tabBarStyle?.display === 'none';
|
|
209
|
+
let activeIndicatorColor = currentOptions?.tabBarActiveIndicatorColor;
|
|
210
|
+
let activeTintColor = currentOptions.tabBarActiveTintColor;
|
|
211
|
+
let inactiveTintColor = currentOptions.tabBarInactiveTintColor;
|
|
212
|
+
|
|
213
|
+
// Derive colors based on Material Design guidelines
|
|
214
|
+
// https://m3.material.io/components/navigation-bar/specs
|
|
215
|
+
if (Platform.OS === 'android') {
|
|
216
|
+
switch (getAndroidColorName(backgroundColor)) {
|
|
217
|
+
case 'system_surface_container_light':
|
|
218
|
+
case 'system_surface_container_high_light':
|
|
219
|
+
case 'system_surface_container_highest_light':
|
|
220
|
+
case 'system_surface_container_low_light':
|
|
221
|
+
case 'system_surface_container_lowest_light':
|
|
222
|
+
inactiveTintColor = inactiveTintColor ?? PlatformColor('@android:color/system_on_surface_variant_light');
|
|
223
|
+
activeTintColor = activeTintColor ?? PlatformColor('@android:color/system_on_secondary_container_light');
|
|
224
|
+
activeIndicatorColor = activeIndicatorColor ?? PlatformColor('@android:color/system_secondary_container_light');
|
|
225
|
+
break;
|
|
226
|
+
case 'system_surface_container_dark':
|
|
227
|
+
case 'system_surface_container_high_dark':
|
|
228
|
+
case 'system_surface_container_highest_dark':
|
|
229
|
+
case 'system_surface_container_low_dark':
|
|
230
|
+
case 'system_surface_container_lowest_dark':
|
|
231
|
+
inactiveTintColor = inactiveTintColor ?? PlatformColor('@android:color/system_on_surface_variant_dark');
|
|
232
|
+
activeTintColor = activeTintColor ?? PlatformColor('@android:color/system_on_secondary_container_dark');
|
|
233
|
+
activeIndicatorColor = activeIndicatorColor ?? PlatformColor('@android:color/system_secondary_container_dark');
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
inactiveTintColor = inactiveTintColor ?? Platform.select({
|
|
63
238
|
ios: PlatformColor('label'),
|
|
64
239
|
default: colors.text
|
|
65
240
|
});
|
|
66
|
-
|
|
241
|
+
activeTintColor = activeTintColor ?? colors.primary;
|
|
242
|
+
activeIndicatorColor = activeIndicatorColor ?? Platform.select({
|
|
243
|
+
android: Color(activeTintColor)?.alpha(0.075).string(),
|
|
244
|
+
default: undefined
|
|
245
|
+
});
|
|
67
246
|
const onTransitionStart = ({
|
|
68
247
|
route
|
|
69
248
|
}) => {
|
|
@@ -95,60 +274,45 @@ export function BottomTabViewNative({
|
|
|
95
274
|
flexDirection: tabBarPosition === 'left' || tabBarPosition === 'right' ? 'row' : 'column'
|
|
96
275
|
},
|
|
97
276
|
children: [tabBarPosition === 'top' || tabBarPosition === 'left' ? tabBarElement : null, /*#__PURE__*/_jsx(Tabs.Host, {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
tabBarItemRippleColor: currentOptions?.tabBarRippleColor,
|
|
119
|
-
experimentalControlNavigationStateInJS: false,
|
|
120
|
-
onNativeFocusChange: e => {
|
|
121
|
-
const route = state.routes.find(route => route.key === e.nativeEvent.tabKey);
|
|
122
|
-
if (route) {
|
|
123
|
-
const event = navigation.emit({
|
|
124
|
-
type: 'tabPress',
|
|
125
|
-
target: route.key,
|
|
126
|
-
canPreventDefault: true
|
|
127
|
-
});
|
|
128
|
-
if (event.defaultPrevented) {
|
|
129
|
-
throw new Error("Preventing default for 'tabPress' is not supported with native tab bar.");
|
|
130
|
-
}
|
|
131
|
-
const isFocused = state.index === state.routes.findIndex(r => r.key === route.key);
|
|
132
|
-
if (!isFocused) {
|
|
133
|
-
navigation.dispatch({
|
|
134
|
-
...CommonActions.navigate(route.name, route.params),
|
|
135
|
-
target: state.key
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
}
|
|
277
|
+
navStateRequest: {
|
|
278
|
+
selectedScreenKey: focusedRouteKey,
|
|
279
|
+
baseProvenance: nativeState.confirmed.provenance
|
|
280
|
+
},
|
|
281
|
+
rejectStaleNavStateUpdates: true,
|
|
282
|
+
onTabSelected: onTabSelected,
|
|
283
|
+
onTabSelectionRejected: onTabSelectionRejected,
|
|
284
|
+
onTabSelectionPrevented: onTabSelectionPrevented,
|
|
285
|
+
tabBarHidden: hasCustomTabBar || shouldHideTabBar,
|
|
286
|
+
colorScheme: dark ? 'dark' : 'light',
|
|
287
|
+
nativeContainerStyle: {
|
|
288
|
+
backgroundColor: colors.background
|
|
289
|
+
},
|
|
290
|
+
ios: {
|
|
291
|
+
bottomAccessory: bottomAccessory ? environment => bottomAccessory({
|
|
292
|
+
placement: environment
|
|
293
|
+
}) : undefined,
|
|
294
|
+
tabBarControllerMode,
|
|
295
|
+
tabBarMinimizeBehavior,
|
|
296
|
+
tabBarTintColor: activeTintColor
|
|
139
297
|
},
|
|
140
298
|
children: state.routes.map((route, index) => {
|
|
299
|
+
const descriptor = descriptors[route.key];
|
|
300
|
+
if (descriptor == null) {
|
|
301
|
+
throw new Error(`Couldn't find a descriptor for route '${route.key}'.`);
|
|
302
|
+
}
|
|
141
303
|
const {
|
|
142
304
|
options,
|
|
143
305
|
render,
|
|
144
306
|
navigation
|
|
145
|
-
} =
|
|
307
|
+
} = descriptor;
|
|
146
308
|
const isFocused = state.index === index;
|
|
147
309
|
const isPreloaded = state.preloadedRouteKeys.includes(route.key);
|
|
148
310
|
const {
|
|
149
311
|
title,
|
|
150
|
-
lazy =
|
|
312
|
+
lazy = false,
|
|
313
|
+
inactiveBehavior = 'pause',
|
|
151
314
|
tabBarLabel,
|
|
315
|
+
tabBarSelectionEnabled,
|
|
152
316
|
tabBarBadgeStyle,
|
|
153
317
|
tabBarIcon,
|
|
154
318
|
tabBarBadge,
|
|
@@ -158,7 +322,7 @@ export function BottomTabViewNative({
|
|
|
158
322
|
tabBarAccessibilityLabel,
|
|
159
323
|
tabBarButtonTestID,
|
|
160
324
|
sceneStyle,
|
|
161
|
-
|
|
325
|
+
overrideScrollViewContentInsetAdjustmentBehavior
|
|
162
326
|
} = options;
|
|
163
327
|
const {
|
|
164
328
|
backgroundColor: tabBarBackgroundColor,
|
|
@@ -171,14 +335,25 @@ export function BottomTabViewNative({
|
|
|
171
335
|
label: tabBarLabel,
|
|
172
336
|
title
|
|
173
337
|
}, route.name);
|
|
338
|
+
const badgeBackgroundColor = tabBarBadgeStyle?.backgroundColor ?? colors.notification;
|
|
339
|
+
const badgeTextColor = tabBarBadgeStyle?.color ?? Color.foreground(badgeBackgroundColor);
|
|
174
340
|
const tabItemAppearance = {
|
|
175
341
|
tabBarItemTitleFontFamily: fontFamily,
|
|
176
342
|
tabBarItemTitleFontSize: fontSize,
|
|
177
343
|
tabBarItemTitleFontWeight: fontWeight,
|
|
178
|
-
tabBarItemTitleFontStyle: fontStyle
|
|
344
|
+
tabBarItemTitleFontStyle: fontStyle,
|
|
345
|
+
tabBarItemTitleFontColor: inactiveTintColor ?? fontColor,
|
|
346
|
+
tabBarItemIconColor: inactiveTintColor,
|
|
347
|
+
tabBarItemBadgeBackgroundColor: badgeBackgroundColor
|
|
348
|
+
};
|
|
349
|
+
const normalTabItemAppearance = {
|
|
350
|
+
tabBarItemTitleFontColor: inactiveTintColor ?? fontColor,
|
|
351
|
+
tabBarItemIconColor: inactiveTintColor
|
|
352
|
+
};
|
|
353
|
+
const selectedTabItemAppearance = {
|
|
354
|
+
tabBarItemTitleFontColor: activeTintColor,
|
|
355
|
+
tabBarItemIconColor: activeTintColor
|
|
179
356
|
};
|
|
180
|
-
const badgeBackgroundColor = tabBarBadgeStyle?.backgroundColor ?? colors.notification;
|
|
181
|
-
const badgeTextColor = tabBarBadgeStyle?.color ?? (Color(badgeBackgroundColor)?.isLight() ? 'black' : 'white');
|
|
182
357
|
const getIcon = selected => {
|
|
183
358
|
if (typeof tabBarIcon === 'function') {
|
|
184
359
|
const result = tabBarIcon({
|
|
@@ -198,8 +373,15 @@ export function BottomTabViewNative({
|
|
|
198
373
|
}
|
|
199
374
|
return undefined;
|
|
200
375
|
};
|
|
201
|
-
|
|
202
|
-
|
|
376
|
+
|
|
377
|
+
// An error is thrown for React Elements in `getIcon`
|
|
378
|
+
// So we only call it when we actually render a native tab bar
|
|
379
|
+
const icon = hasCustomTabBar ? undefined : getIcon(false);
|
|
380
|
+
const selectedIcon = hasCustomTabBar ? undefined : getIcon(true);
|
|
381
|
+
|
|
382
|
+
// For preloaded screens and if lazy is false,
|
|
383
|
+
// Keep them active so that the effects can run
|
|
384
|
+
const isActive = inactiveBehavior === 'none' || isPreloaded || nativeState.lastTransition?.from === route.key || nativeState.lastTransition?.to === route.key || lazy === false && !loaded.includes(route.key);
|
|
203
385
|
return /*#__PURE__*/_jsx(Tabs.Screen, {
|
|
204
386
|
onWillAppear: () => onTransitionStart({
|
|
205
387
|
route
|
|
@@ -207,40 +389,14 @@ export function BottomTabViewNative({
|
|
|
207
389
|
onDidAppear: () => onTransitionEnd({
|
|
208
390
|
route
|
|
209
391
|
}),
|
|
210
|
-
|
|
211
|
-
icon: icon,
|
|
212
|
-
selectedIcon: selectedIcon?.ios ?? selectedIcon?.shared,
|
|
213
|
-
tabBarItemBadgeBackgroundColor: badgeBackgroundColor,
|
|
214
|
-
tabBarItemBadgeTextColor: badgeTextColor,
|
|
392
|
+
screenKey: route.key,
|
|
215
393
|
tabBarItemAccessibilityLabel: tabBarAccessibilityLabel,
|
|
216
394
|
tabBarItemTestID: tabBarButtonTestID,
|
|
395
|
+
preventNativeSelection: tabBarSelectionEnabled === false,
|
|
217
396
|
badgeValue: tabBarBadge?.toString(),
|
|
218
|
-
systemItem: tabBarSystemItem,
|
|
219
|
-
isFocused: isFocused,
|
|
220
397
|
title: tabTitle,
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
bottom: scrollEdgeEffects?.bottom === 'auto' ? 'automatic' : scrollEdgeEffects?.bottom,
|
|
224
|
-
left: scrollEdgeEffects?.left === 'auto' ? 'automatic' : scrollEdgeEffects?.left,
|
|
225
|
-
right: scrollEdgeEffects?.right === 'auto' ? 'automatic' : scrollEdgeEffects?.right
|
|
226
|
-
}
|
|
227
|
-
// FIXME: if this is not provided, ScrollView on lazy tabs glitches on iOS 18
|
|
228
|
-
// For now we provide an empty object before adding proper support
|
|
229
|
-
,
|
|
230
|
-
scrollEdgeAppearance: {},
|
|
231
|
-
standardAppearance: {
|
|
232
|
-
tabBarBackgroundColor,
|
|
233
|
-
tabBarShadowColor,
|
|
234
|
-
tabBarBlurEffect,
|
|
235
|
-
stacked: {
|
|
236
|
-
normal: tabItemAppearance
|
|
237
|
-
},
|
|
238
|
-
inline: {
|
|
239
|
-
normal: tabItemAppearance
|
|
240
|
-
},
|
|
241
|
-
compactInline: {
|
|
242
|
-
normal: tabItemAppearance
|
|
243
|
-
}
|
|
398
|
+
nativeContainerStyle: {
|
|
399
|
+
backgroundColor: colors.background
|
|
244
400
|
},
|
|
245
401
|
specialEffects: {
|
|
246
402
|
repeatedTabSelection: {
|
|
@@ -248,27 +404,89 @@ export function BottomTabViewNative({
|
|
|
248
404
|
scrollToTop: true
|
|
249
405
|
}
|
|
250
406
|
},
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
407
|
+
android: {
|
|
408
|
+
icon: icon?.android ?? icon?.shared,
|
|
409
|
+
selectedIcon: selectedIcon?.android ?? selectedIcon?.shared,
|
|
410
|
+
standardAppearance: {
|
|
411
|
+
tabBarBackgroundColor: tabBarBackgroundColor ?? backgroundColor,
|
|
412
|
+
tabBarItemRippleColor: currentOptions?.tabBarRippleColor,
|
|
413
|
+
tabBarItemLabelVisibilityMode: currentOptions?.tabBarLabelVisibilityMode,
|
|
414
|
+
normal: normalTabItemAppearance,
|
|
415
|
+
selected: selectedTabItemAppearance,
|
|
416
|
+
tabBarItemActiveIndicatorColor: activeIndicatorColor,
|
|
417
|
+
tabBarItemActiveIndicatorEnabled: currentOptions?.tabBarActiveIndicatorEnabled,
|
|
418
|
+
tabBarItemTitleFontFamily: fontFamily,
|
|
419
|
+
tabBarItemTitleFontWeight: fontWeight,
|
|
420
|
+
tabBarItemTitleSmallLabelFontSize: fontSize,
|
|
421
|
+
tabBarItemTitleLargeLabelFontSize: fontSize,
|
|
422
|
+
tabBarItemTitleFontStyle: fontStyle,
|
|
423
|
+
tabBarItemBadgeBackgroundColor: badgeBackgroundColor,
|
|
424
|
+
tabBarItemBadgeTextColor: badgeTextColor
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
ios: {
|
|
428
|
+
icon: icon?.ios ?? icon?.shared,
|
|
429
|
+
selectedIcon: selectedIcon?.ios ?? selectedIcon?.shared,
|
|
430
|
+
systemItem: tabBarSystemItem,
|
|
431
|
+
scrollEdgeAppearance: {
|
|
432
|
+
tabBarBackgroundColor,
|
|
433
|
+
tabBarShadowColor,
|
|
434
|
+
tabBarBlurEffect,
|
|
435
|
+
stacked: {
|
|
436
|
+
normal: tabItemAppearance
|
|
437
|
+
},
|
|
438
|
+
inline: {
|
|
439
|
+
normal: tabItemAppearance
|
|
440
|
+
},
|
|
441
|
+
compactInline: {
|
|
442
|
+
normal: tabItemAppearance
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
standardAppearance: {
|
|
446
|
+
tabBarBackgroundColor,
|
|
447
|
+
tabBarShadowColor,
|
|
448
|
+
tabBarBlurEffect,
|
|
449
|
+
stacked: {
|
|
450
|
+
normal: tabItemAppearance
|
|
451
|
+
},
|
|
452
|
+
inline: {
|
|
453
|
+
normal: tabItemAppearance
|
|
454
|
+
},
|
|
455
|
+
compactInline: {
|
|
456
|
+
normal: tabItemAppearance
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
overrideScrollViewContentInsetAdjustmentBehavior
|
|
460
|
+
},
|
|
461
|
+
children: /*#__PURE__*/_jsx(Deferred, {
|
|
462
|
+
lazy: lazy,
|
|
463
|
+
visible: isFocused || isPreloaded || loaded.includes(route.key),
|
|
464
|
+
children: /*#__PURE__*/_jsx(ActivityView, {
|
|
465
|
+
mode: isFocused ? 'normal' : isActive ? 'inert' : 'paused',
|
|
466
|
+
visible:
|
|
467
|
+
// We don't need to hide the content since it's handled natively
|
|
468
|
+
// Hiding may also cause flash due to lag after native tab switch
|
|
469
|
+
// So we leave it always visible
|
|
470
|
+
true,
|
|
471
|
+
style: StyleSheet.absoluteFill,
|
|
472
|
+
children: /*#__PURE__*/_jsx(ScreenContent, {
|
|
262
473
|
isFocused: isFocused,
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
474
|
+
route: route,
|
|
475
|
+
navigation: navigation,
|
|
476
|
+
options: options,
|
|
477
|
+
style: sceneStyle,
|
|
478
|
+
children: /*#__PURE__*/_jsx(AnimatedScreenContent, {
|
|
479
|
+
isFocused: isFocused,
|
|
480
|
+
children: /*#__PURE__*/_jsx(BottomTabBarHeightContext.Provider, {
|
|
481
|
+
value: 0,
|
|
482
|
+
children: /*#__PURE__*/_jsx(NavigationMetaContext.Provider, {
|
|
483
|
+
value: meta,
|
|
484
|
+
children: render()
|
|
485
|
+
})
|
|
268
486
|
})
|
|
269
487
|
})
|
|
270
488
|
})
|
|
271
|
-
})
|
|
489
|
+
}, route.key)
|
|
272
490
|
})
|
|
273
491
|
}, route.key);
|
|
274
492
|
})
|
|
@@ -314,7 +532,10 @@ function getPlatformIcon(icon) {
|
|
|
314
532
|
android: {
|
|
315
533
|
type: 'imageSource',
|
|
316
534
|
imageSource: MaterialSymbol.getImageSource({
|
|
317
|
-
name: icon.name
|
|
535
|
+
name: icon.name,
|
|
536
|
+
variant: icon.variant,
|
|
537
|
+
weight: icon.weight,
|
|
538
|
+
size: ICON_SIZE
|
|
318
539
|
})
|
|
319
540
|
},
|
|
320
541
|
shared: undefined
|
|
@@ -334,16 +555,6 @@ function getPlatformIcon(icon) {
|
|
|
334
555
|
imageSource: icon.source
|
|
335
556
|
}
|
|
336
557
|
};
|
|
337
|
-
case 'resource':
|
|
338
|
-
return {
|
|
339
|
-
// TODO: support xcasset once new version of react-native-screens is released
|
|
340
|
-
ios: undefined,
|
|
341
|
-
android: {
|
|
342
|
-
type: 'drawableResource',
|
|
343
|
-
name: icon.name
|
|
344
|
-
},
|
|
345
|
-
shared: undefined
|
|
346
|
-
};
|
|
347
558
|
default:
|
|
348
559
|
{
|
|
349
560
|
const _exhaustiveCheck = icon;
|
|
@@ -351,4 +562,11 @@ function getPlatformIcon(icon) {
|
|
|
351
562
|
}
|
|
352
563
|
}
|
|
353
564
|
}
|
|
565
|
+
function getAndroidColorName(color) {
|
|
566
|
+
const value = color;
|
|
567
|
+
if (typeof value === 'object' && value != null && 'resource_paths' in value && Array.isArray(value.resource_paths) && typeof value.resource_paths[0] === 'string') {
|
|
568
|
+
return value.resource_paths[0].replace('@android:color/', '');
|
|
569
|
+
}
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
354
572
|
//# sourceMappingURL=BottomTabViewNativeImpl.js.map
|