@react-navigation/bottom-tabs 8.0.0-alpha.5 → 8.0.0-alpha.51
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 +11 -34
- 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 +34 -102
- 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,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)
|
|
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
|
|
312
|
+
const flex = StyleSheet.flatten(style)?.flex;
|
|
315
313
|
const borderRadius =
|
|
316
314
|
variant === 'material'
|
|
317
315
|
? horizontal
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ActivityView,
|
|
2
3
|
Container,
|
|
3
|
-
Lazy,
|
|
4
4
|
SafeAreaProviderCompat,
|
|
5
5
|
} from '@react-navigation/elements/internal';
|
|
6
6
|
import {
|
|
7
|
-
type NavigationAction,
|
|
8
7
|
type ParamListBase,
|
|
9
8
|
StackActions,
|
|
10
9
|
type TabNavigationState,
|
|
@@ -17,7 +16,6 @@ import {
|
|
|
17
16
|
StyleSheet,
|
|
18
17
|
type ViewStyle,
|
|
19
18
|
} from 'react-native';
|
|
20
|
-
import { Screen, ScreenContainer } from 'react-native-screens';
|
|
21
19
|
|
|
22
20
|
import {
|
|
23
21
|
FadeTransition,
|
|
@@ -37,6 +35,7 @@ import { BottomTabBarHeightContext } from '../utils/BottomTabBarHeightContext';
|
|
|
37
35
|
import { useAnimatedHashMap } from '../utils/useAnimatedHashMap';
|
|
38
36
|
import { useTabBarPosition } from '../utils/useTabBarPosition';
|
|
39
37
|
import { BottomTabBar, getTabBarHeight } from './BottomTabBar';
|
|
38
|
+
import { Deferred } from './Deferred';
|
|
40
39
|
import { ScreenContent } from './ScreenContent';
|
|
41
40
|
|
|
42
41
|
type Props = BottomTabNavigationConfig & {
|
|
@@ -45,11 +44,6 @@ type Props = BottomTabNavigationConfig & {
|
|
|
45
44
|
descriptors: BottomTabDescriptorMap;
|
|
46
45
|
};
|
|
47
46
|
|
|
48
|
-
const EPSILON = 1e-5;
|
|
49
|
-
const STATE_INACTIVE = 0;
|
|
50
|
-
const STATE_TRANSITIONING_OR_BELOW_TOP = 1;
|
|
51
|
-
const STATE_ON_TOP = 2;
|
|
52
|
-
|
|
53
47
|
const NAMED_TRANSITIONS_PRESETS = {
|
|
54
48
|
fade: FadeTransition,
|
|
55
49
|
shift: ShiftTransition,
|
|
@@ -83,36 +77,48 @@ export function BottomTabViewCustom({
|
|
|
83
77
|
state,
|
|
84
78
|
navigation,
|
|
85
79
|
descriptors,
|
|
86
|
-
detachInactiveScreens = Platform.OS === 'web' ||
|
|
87
|
-
Platform.OS === 'android' ||
|
|
88
|
-
Platform.OS === 'ios',
|
|
89
80
|
}: Props) {
|
|
90
81
|
const { routes } = state;
|
|
91
|
-
const
|
|
82
|
+
const focusedRoute = routes[state.index];
|
|
83
|
+
|
|
84
|
+
if (focusedRoute == null) {
|
|
85
|
+
throw new Error(`Couldn't find a route at index ${state.index}.`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const focusedRouteKey = focusedRoute.key;
|
|
89
|
+
const focusedOptions = descriptors[focusedRouteKey]?.options;
|
|
90
|
+
|
|
91
|
+
const [loaded, setLoaded] = React.useState([focusedRouteKey]);
|
|
92
|
+
|
|
93
|
+
if (!loaded.includes(focusedRouteKey)) {
|
|
94
|
+
setLoaded([...loaded, focusedRouteKey]);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const [lastUpdate, setLastUpdate] = React.useState<{
|
|
98
|
+
current: string;
|
|
99
|
+
previous?: string;
|
|
100
|
+
animating: boolean;
|
|
101
|
+
}>({
|
|
102
|
+
current: focusedRouteKey,
|
|
103
|
+
animating: false,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (lastUpdate.current !== focusedRouteKey) {
|
|
107
|
+
setLastUpdate({
|
|
108
|
+
current: focusedRouteKey,
|
|
109
|
+
previous: lastUpdate.current,
|
|
110
|
+
animating: true,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
92
113
|
|
|
93
|
-
const previousRouteKeyRef = React.useRef(focusedRouteKey);
|
|
94
114
|
const tabAnims = useAnimatedHashMap(state);
|
|
95
115
|
|
|
116
|
+
const previousRouteKeyRef = React.useRef(focusedRouteKey);
|
|
117
|
+
|
|
96
118
|
React.useEffect(() => {
|
|
97
119
|
const previousRouteKey = previousRouteKeyRef.current;
|
|
98
120
|
|
|
99
|
-
let
|
|
100
|
-
|
|
101
|
-
if (
|
|
102
|
-
previousRouteKey !== focusedRouteKey &&
|
|
103
|
-
descriptors[previousRouteKey]?.options.popToTopOnBlur
|
|
104
|
-
) {
|
|
105
|
-
const prevRoute = state.routes.find(
|
|
106
|
-
(route) => route.key === previousRouteKey
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
if (prevRoute?.state?.type === 'stack' && prevRoute.state.key) {
|
|
110
|
-
popToTopAction = {
|
|
111
|
-
...StackActions.popToTop(),
|
|
112
|
-
target: prevRoute.state.key,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
}
|
|
121
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
116
122
|
|
|
117
123
|
const animateToIndex = () => {
|
|
118
124
|
if (previousRouteKey !== focusedRouteKey) {
|
|
@@ -122,42 +128,71 @@ export function BottomTabViewCustom({
|
|
|
122
128
|
});
|
|
123
129
|
}
|
|
124
130
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
131
|
+
const animations = state.routes.map((route, index) => {
|
|
132
|
+
const descriptor = descriptors[route.key];
|
|
133
|
+
|
|
134
|
+
if (descriptor == null) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`Couldn't find a descriptor for route '${route.key}'.`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const { options } = descriptor;
|
|
141
|
+
const {
|
|
142
|
+
animation = 'none',
|
|
143
|
+
transitionSpec = NAMED_TRANSITIONS_PRESETS[animation].transitionSpec,
|
|
144
|
+
} = options;
|
|
145
|
+
|
|
146
|
+
let spec = transitionSpec;
|
|
147
|
+
|
|
148
|
+
if (route.key !== previousRouteKey && route.key !== focusedRouteKey) {
|
|
149
|
+
// Don't animate if the screen is not previous one or new one
|
|
150
|
+
// This will avoid flicker for screens not involved in the transition
|
|
151
|
+
spec = NAMED_TRANSITIONS_PRESETS.none.transitionSpec;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
spec = spec ?? NAMED_TRANSITIONS_PRESETS.none.transitionSpec;
|
|
155
|
+
|
|
156
|
+
const toValue =
|
|
157
|
+
index === state.index ? 0 : index >= state.index ? 1 : -1;
|
|
158
|
+
|
|
159
|
+
const tabAnimation = tabAnims[route.key];
|
|
160
|
+
|
|
161
|
+
if (tabAnimation == null) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`Couldn't find an animation for route '${route.key}'.`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return Animated[spec.animation](tabAnimation, {
|
|
168
|
+
...spec.config,
|
|
169
|
+
toValue,
|
|
170
|
+
useNativeDriver,
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
Animated.parallel(animations).start(({ finished }) => {
|
|
175
|
+
if (
|
|
176
|
+
previousRouteKey &&
|
|
177
|
+
previousRouteKey !== focusedRouteKey &&
|
|
178
|
+
descriptors[previousRouteKey]?.options.popToTopOnBlur
|
|
179
|
+
) {
|
|
180
|
+
const currentState = navigation.getState();
|
|
181
|
+
const prevRoute = currentState.routes.find(
|
|
182
|
+
(route) => route.key === previousRouteKey
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
if (
|
|
186
|
+
prevRoute?.state?.type === 'stack' &&
|
|
187
|
+
prevRoute.state.key &&
|
|
188
|
+
((prevRoute.state.index ?? prevRoute.state.routes.length - 1) > 0 ||
|
|
189
|
+
prevRoute.state.routes[0]?.history?.length)
|
|
190
|
+
) {
|
|
191
|
+
navigation.dispatch({
|
|
192
|
+
...StackActions.popToTop(),
|
|
193
|
+
target: prevRoute.state.key,
|
|
155
194
|
});
|
|
156
|
-
}
|
|
157
|
-
.filter(Boolean) as Animated.CompositeAnimation[]
|
|
158
|
-
).start(({ finished }) => {
|
|
159
|
-
if (finished && popToTopAction) {
|
|
160
|
-
navigation.dispatch(popToTopAction);
|
|
195
|
+
}
|
|
161
196
|
}
|
|
162
197
|
|
|
163
198
|
if (previousRouteKey !== focusedRouteKey) {
|
|
@@ -166,12 +201,26 @@ export function BottomTabViewCustom({
|
|
|
166
201
|
target: focusedRouteKey,
|
|
167
202
|
});
|
|
168
203
|
}
|
|
204
|
+
|
|
205
|
+
if (finished && animations.length) {
|
|
206
|
+
// Delay clearing `animating` state
|
|
207
|
+
// This will give time for `popToTop` to get handled before pause
|
|
208
|
+
timer = setTimeout(() => {
|
|
209
|
+
setLastUpdate((update) =>
|
|
210
|
+
update.animating ? { ...update, animating: false } : update
|
|
211
|
+
);
|
|
212
|
+
}, 32);
|
|
213
|
+
}
|
|
169
214
|
});
|
|
170
215
|
};
|
|
171
216
|
|
|
172
217
|
animateToIndex();
|
|
173
218
|
|
|
174
219
|
previousRouteKeyRef.current = focusedRouteKey;
|
|
220
|
+
|
|
221
|
+
return () => {
|
|
222
|
+
clearTimeout(timer);
|
|
223
|
+
};
|
|
175
224
|
}, [
|
|
176
225
|
descriptors,
|
|
177
226
|
focusedRouteKey,
|
|
@@ -187,7 +236,7 @@ export function BottomTabViewCustom({
|
|
|
187
236
|
descriptors,
|
|
188
237
|
dimensions: SafeAreaProviderCompat.initialMetrics.frame,
|
|
189
238
|
insets: SafeAreaProviderCompat.initialMetrics.insets,
|
|
190
|
-
style:
|
|
239
|
+
style: focusedOptions?.tabBarStyle,
|
|
191
240
|
})
|
|
192
241
|
);
|
|
193
242
|
|
|
@@ -204,14 +253,7 @@ export function BottomTabViewCustom({
|
|
|
204
253
|
</BottomTabBarHeightCallbackContext.Provider>
|
|
205
254
|
);
|
|
206
255
|
|
|
207
|
-
|
|
208
|
-
const hasTwoStates = !routes.some((route) =>
|
|
209
|
-
hasAnimation(descriptors[route.key].options)
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
const tabBarPosition = useTabBarPosition(
|
|
213
|
-
descriptors[focusedRouteKey].options
|
|
214
|
-
);
|
|
256
|
+
const tabBarPosition = useTabBarPosition(focusedOptions ?? {});
|
|
215
257
|
|
|
216
258
|
return (
|
|
217
259
|
<SafeAreaProviderCompat
|
|
@@ -225,19 +267,21 @@ export function BottomTabViewCustom({
|
|
|
225
267
|
{tabBarPosition === 'top' || tabBarPosition === 'left'
|
|
226
268
|
? tabBarElement
|
|
227
269
|
: null}
|
|
228
|
-
<
|
|
229
|
-
key="screens"
|
|
230
|
-
enabled={detachInactiveScreens}
|
|
231
|
-
hasTwoStates={hasTwoStates}
|
|
232
|
-
style={styles.screens}
|
|
233
|
-
>
|
|
270
|
+
<Container key="screens" style={styles.screens}>
|
|
234
271
|
{routes.map((route, index) => {
|
|
235
272
|
const descriptor = descriptors[route.key];
|
|
236
273
|
|
|
274
|
+
if (descriptor == null) {
|
|
275
|
+
throw new Error(
|
|
276
|
+
`Couldn't find a descriptor for route '${route.key}'.`
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
237
280
|
const { navigation, options, render } = descriptor;
|
|
238
281
|
|
|
239
282
|
const {
|
|
240
283
|
lazy = true,
|
|
284
|
+
inactiveBehavior = 'pause',
|
|
241
285
|
animation = 'none',
|
|
242
286
|
sceneStyleInterpolator = NAMED_TRANSITIONS_PRESETS[animation]
|
|
243
287
|
.sceneStyleInterpolator,
|
|
@@ -248,85 +292,70 @@ export function BottomTabViewCustom({
|
|
|
248
292
|
const isPreloaded = state.preloadedRouteKeys.includes(route.key);
|
|
249
293
|
|
|
250
294
|
const animationEnabled = hasAnimation(descriptor.options);
|
|
295
|
+
const tabAnimation = tabAnims[route.key];
|
|
296
|
+
|
|
297
|
+
if (tabAnimation == null) {
|
|
298
|
+
throw new Error(
|
|
299
|
+
`Couldn't find an animation for route '${route.key}'.`
|
|
300
|
+
);
|
|
301
|
+
}
|
|
251
302
|
|
|
252
303
|
const content = (
|
|
253
304
|
<AnimatedScreenContent
|
|
254
|
-
|
|
305
|
+
key={route.key}
|
|
306
|
+
progress={tabAnimation}
|
|
255
307
|
animationEnabled={animationEnabled}
|
|
256
308
|
sceneStyleInterpolator={sceneStyleInterpolator}
|
|
257
|
-
style={customSceneStyle}
|
|
309
|
+
style={[StyleSheet.absoluteFill, customSceneStyle]}
|
|
258
310
|
>
|
|
259
|
-
<
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
311
|
+
<ScreenContent
|
|
312
|
+
isFocused={isFocused}
|
|
313
|
+
route={route}
|
|
314
|
+
navigation={navigation}
|
|
315
|
+
options={options}
|
|
316
|
+
>
|
|
317
|
+
<BottomTabBarHeightContext.Provider
|
|
318
|
+
value={tabBarPosition === 'bottom' ? tabBarHeight : 0}
|
|
265
319
|
>
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
{render()}
|
|
270
|
-
</BottomTabBarHeightContext.Provider>
|
|
271
|
-
</ScreenContent>
|
|
272
|
-
</Lazy>
|
|
320
|
+
{render()}
|
|
321
|
+
</BottomTabBarHeightContext.Provider>
|
|
322
|
+
</ScreenContent>
|
|
273
323
|
</AnimatedScreenContent>
|
|
274
324
|
);
|
|
275
325
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
* - We still need to hide the view when screens is not enabled
|
|
281
|
-
* - We can use `inert` to handle a11y better for unfocused screens
|
|
282
|
-
*/
|
|
283
|
-
return (
|
|
284
|
-
<Container
|
|
285
|
-
key={route.key}
|
|
286
|
-
inert={!isFocused}
|
|
287
|
-
style={{
|
|
288
|
-
...StyleSheet.absoluteFillObject,
|
|
289
|
-
visibility: isFocused ? 'visible' : 'hidden',
|
|
290
|
-
}}
|
|
291
|
-
>
|
|
292
|
-
{content}
|
|
293
|
-
</Container>
|
|
294
|
-
);
|
|
295
|
-
}
|
|
326
|
+
const isAnimatingRoute =
|
|
327
|
+
lastUpdate.animating &&
|
|
328
|
+
(lastUpdate.previous === route.key ||
|
|
329
|
+
lastUpdate.current === route.key);
|
|
296
330
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
STATE_TRANSITIONING_OR_BELOW_TOP,
|
|
305
|
-
STATE_INACTIVE, // the screen is detached after transition
|
|
306
|
-
],
|
|
307
|
-
extrapolate: 'extend',
|
|
308
|
-
})
|
|
309
|
-
: STATE_INACTIVE;
|
|
331
|
+
// For preloaded screens and if lazy is false,
|
|
332
|
+
// Keep them active so that the effects can run
|
|
333
|
+
const isActive =
|
|
334
|
+
inactiveBehavior === 'none' ||
|
|
335
|
+
isAnimatingRoute ||
|
|
336
|
+
isPreloaded ||
|
|
337
|
+
(lazy === false && !loaded.includes(route.key));
|
|
310
338
|
|
|
311
339
|
return (
|
|
312
|
-
<
|
|
340
|
+
<Deferred
|
|
313
341
|
key={route.key}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
{
|
|
317
|
-
zIndex: isFocused ? 0 : -1,
|
|
318
|
-
pointerEvents: isFocused ? 'auto' : 'none',
|
|
319
|
-
},
|
|
320
|
-
]}
|
|
321
|
-
activityState={activityState}
|
|
322
|
-
enabled={detachInactiveScreens}
|
|
323
|
-
shouldFreeze={activityState === STATE_INACTIVE && !isPreloaded}
|
|
342
|
+
lazy={lazy}
|
|
343
|
+
visible={isFocused || isPreloaded || loaded.includes(route.key)}
|
|
324
344
|
>
|
|
325
|
-
|
|
326
|
-
|
|
345
|
+
<ActivityView
|
|
346
|
+
mode={isFocused ? 'normal' : isActive ? 'inert' : 'paused'}
|
|
347
|
+
visible={isFocused || isAnimatingRoute}
|
|
348
|
+
style={{
|
|
349
|
+
...StyleSheet.absoluteFill,
|
|
350
|
+
zIndex: isFocused ? 0 : -1,
|
|
351
|
+
}}
|
|
352
|
+
>
|
|
353
|
+
{content}
|
|
354
|
+
</ActivityView>
|
|
355
|
+
</Deferred>
|
|
327
356
|
);
|
|
328
357
|
})}
|
|
329
|
-
</
|
|
358
|
+
</Container>
|
|
330
359
|
{tabBarPosition === 'bottom' || tabBarPosition === 'right'
|
|
331
360
|
? tabBarElement
|
|
332
361
|
: null}
|
|
@@ -343,7 +372,7 @@ function AnimatedScreenContent({
|
|
|
343
372
|
}: {
|
|
344
373
|
progress: Animated.Value;
|
|
345
374
|
animationEnabled: boolean;
|
|
346
|
-
sceneStyleInterpolator?: BottomTabSceneStyleInterpolator;
|
|
375
|
+
sceneStyleInterpolator?: BottomTabSceneStyleInterpolator | undefined;
|
|
347
376
|
children: React.ReactNode;
|
|
348
377
|
style: StyleProp<ViewStyle>;
|
|
349
378
|
}) {
|