@react-navigation/bottom-tabs 8.0.0-alpha.13 → 8.0.0-alpha.14
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/navigators/createBottomTabNavigator.js +1 -18
- package/lib/module/navigators/createBottomTabNavigator.js.map +1 -1
- package/lib/module/views/BottomTabViewCustom.js +66 -62
- package/lib/module/views/BottomTabViewCustom.js.map +1 -1
- package/lib/module/views/BottomTabViewNativeImpl.js +40 -6
- package/lib/module/views/BottomTabViewNativeImpl.js.map +1 -1
- package/lib/typescript/src/navigators/createBottomTabNavigator.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +16 -12
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabItem.d.ts +16 -16
- package/lib/typescript/src/views/BottomTabItem.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabViewCustom.d.ts +1 -1
- package/lib/typescript/src/views/BottomTabViewCustom.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabViewNativeImpl.d.ts.map +1 -1
- package/lib/typescript/src/views/TabBarIcon.d.ts +3 -3
- package/lib/typescript/src/views/TabBarIcon.d.ts.map +1 -1
- package/package.json +12 -12
- package/src/navigators/createBottomTabNavigator.tsx +0 -28
- package/src/types.tsx +17 -13
- package/src/views/BottomTabItem.tsx +16 -16
- package/src/views/BottomTabViewCustom.tsx +127 -114
- package/src/views/BottomTabViewNativeImpl.tsx +78 -17
- package/src/views/TabBarIcon.tsx +3 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
ActivityView,
|
|
3
|
+
Container,
|
|
3
4
|
SafeAreaProviderCompat,
|
|
4
5
|
} from '@react-navigation/elements/internal';
|
|
5
6
|
import {
|
|
@@ -16,7 +17,6 @@ import {
|
|
|
16
17
|
StyleSheet,
|
|
17
18
|
type ViewStyle,
|
|
18
19
|
} from 'react-native';
|
|
19
|
-
import { Screen, ScreenContainer } from 'react-native-screens';
|
|
20
20
|
|
|
21
21
|
import {
|
|
22
22
|
FadeTransition,
|
|
@@ -44,11 +44,6 @@ type Props = BottomTabNavigationConfig & {
|
|
|
44
44
|
descriptors: BottomTabDescriptorMap;
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
const EPSILON = 1e-5;
|
|
48
|
-
const STATE_INACTIVE = 0;
|
|
49
|
-
const STATE_TRANSITIONING_OR_BELOW_TOP = 1;
|
|
50
|
-
const STATE_ON_TOP = 2;
|
|
51
|
-
|
|
52
47
|
const NAMED_TRANSITIONS_PRESETS = {
|
|
53
48
|
fade: FadeTransition,
|
|
54
49
|
shift: ShiftTransition,
|
|
@@ -82,22 +77,43 @@ export function BottomTabViewCustom({
|
|
|
82
77
|
state,
|
|
83
78
|
navigation,
|
|
84
79
|
descriptors,
|
|
85
|
-
detachInactiveScreens = Platform.OS === 'web' ||
|
|
86
|
-
Platform.OS === 'android' ||
|
|
87
|
-
Platform.OS === 'ios',
|
|
88
80
|
}: Props) {
|
|
89
81
|
const { routes } = state;
|
|
90
82
|
const focusedRouteKey = routes[state.index].key;
|
|
91
83
|
|
|
92
|
-
const
|
|
84
|
+
const [loaded, setLoaded] = React.useState([focusedRouteKey]);
|
|
85
|
+
|
|
86
|
+
if (!loaded.includes(focusedRouteKey)) {
|
|
87
|
+
setLoaded([...loaded, focusedRouteKey]);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const [lastUpdate, setLastUpdate] = React.useState<{
|
|
91
|
+
current: string;
|
|
92
|
+
previous?: string;
|
|
93
|
+
}>({
|
|
94
|
+
current: focusedRouteKey,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
if (lastUpdate.current !== focusedRouteKey) {
|
|
98
|
+
setLastUpdate({
|
|
99
|
+
current: focusedRouteKey,
|
|
100
|
+
previous: lastUpdate.current,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
93
104
|
const tabAnims = useAnimatedHashMap(state);
|
|
94
105
|
|
|
106
|
+
const [isAnimating, setIsAnimating] = React.useState(false);
|
|
107
|
+
|
|
108
|
+
const previousRouteKeyRef = React.useRef(focusedRouteKey);
|
|
109
|
+
|
|
95
110
|
React.useEffect(() => {
|
|
96
111
|
const previousRouteKey = previousRouteKeyRef.current;
|
|
97
112
|
|
|
98
113
|
let popToTopAction: NavigationAction | undefined;
|
|
99
114
|
|
|
100
115
|
if (
|
|
116
|
+
previousRouteKey &&
|
|
101
117
|
previousRouteKey !== focusedRouteKey &&
|
|
102
118
|
descriptors[previousRouteKey]?.options.popToTopOnBlur
|
|
103
119
|
) {
|
|
@@ -105,6 +121,12 @@ export function BottomTabViewCustom({
|
|
|
105
121
|
(route) => route.key === previousRouteKey
|
|
106
122
|
);
|
|
107
123
|
|
|
124
|
+
console.log(
|
|
125
|
+
'checking if we need to pop to top for route',
|
|
126
|
+
previousRouteKey,
|
|
127
|
+
focusedRouteKey
|
|
128
|
+
);
|
|
129
|
+
|
|
108
130
|
if (prevRoute?.state?.type === 'stack' && prevRoute.state.key) {
|
|
109
131
|
popToTopAction = {
|
|
110
132
|
...StackActions.popToTop(),
|
|
@@ -113,6 +135,8 @@ export function BottomTabViewCustom({
|
|
|
113
135
|
}
|
|
114
136
|
}
|
|
115
137
|
|
|
138
|
+
let timer: ReturnType<typeof setTimeout>;
|
|
139
|
+
|
|
116
140
|
const animateToIndex = () => {
|
|
117
141
|
if (previousRouteKey !== focusedRouteKey) {
|
|
118
142
|
navigation.emit({
|
|
@@ -121,42 +145,45 @@ export function BottomTabViewCustom({
|
|
|
121
145
|
});
|
|
122
146
|
}
|
|
123
147
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
transitionSpec
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
148
|
+
const animations = state.routes
|
|
149
|
+
.map((route, index) => {
|
|
150
|
+
const { options } = descriptors[route.key];
|
|
151
|
+
const {
|
|
152
|
+
animation = 'none',
|
|
153
|
+
transitionSpec = NAMED_TRANSITIONS_PRESETS[animation]
|
|
154
|
+
.transitionSpec,
|
|
155
|
+
} = options;
|
|
156
|
+
|
|
157
|
+
let spec = transitionSpec;
|
|
158
|
+
|
|
159
|
+
if (route.key !== previousRouteKey && route.key !== focusedRouteKey) {
|
|
160
|
+
// Don't animate if the screen is not previous one or new one
|
|
161
|
+
// This will avoid flicker for screens not involved in the transition
|
|
162
|
+
spec = NAMED_TRANSITIONS_PRESETS.none.transitionSpec;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
spec = spec ?? NAMED_TRANSITIONS_PRESETS.none.transitionSpec;
|
|
166
|
+
|
|
167
|
+
const toValue =
|
|
168
|
+
index === state.index ? 0 : index >= state.index ? 1 : -1;
|
|
169
|
+
|
|
170
|
+
return Animated[spec.animation](tabAnims[route.key], {
|
|
171
|
+
...spec.config,
|
|
172
|
+
toValue,
|
|
173
|
+
useNativeDriver,
|
|
174
|
+
});
|
|
175
|
+
})
|
|
176
|
+
.filter((anim) => anim != null);
|
|
177
|
+
|
|
178
|
+
if (animations.length) {
|
|
179
|
+
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
|
|
180
|
+
setIsAnimating(true);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
Animated.parallel(animations).start(({ finished }) => {
|
|
158
184
|
if (finished && popToTopAction) {
|
|
159
|
-
|
|
185
|
+
console.log('dispatching pop to top action', popToTopAction);
|
|
186
|
+
// navigation.dispatch(popToTopAction);
|
|
160
187
|
}
|
|
161
188
|
|
|
162
189
|
if (previousRouteKey !== focusedRouteKey) {
|
|
@@ -165,12 +192,24 @@ export function BottomTabViewCustom({
|
|
|
165
192
|
target: focusedRouteKey,
|
|
166
193
|
});
|
|
167
194
|
}
|
|
195
|
+
|
|
196
|
+
if (finished && animations.length) {
|
|
197
|
+
// Delay clearing `isAnimating`
|
|
198
|
+
// This will give time for `popToAction` to get handled before pause
|
|
199
|
+
timer = setTimeout(() => {
|
|
200
|
+
setIsAnimating(false);
|
|
201
|
+
}, 32);
|
|
202
|
+
}
|
|
168
203
|
});
|
|
169
204
|
};
|
|
170
205
|
|
|
171
206
|
animateToIndex();
|
|
172
207
|
|
|
173
208
|
previousRouteKeyRef.current = focusedRouteKey;
|
|
209
|
+
|
|
210
|
+
return () => {
|
|
211
|
+
clearTimeout(timer);
|
|
212
|
+
};
|
|
174
213
|
}, [
|
|
175
214
|
descriptors,
|
|
176
215
|
focusedRouteKey,
|
|
@@ -203,11 +242,6 @@ export function BottomTabViewCustom({
|
|
|
203
242
|
</BottomTabBarHeightCallbackContext.Provider>
|
|
204
243
|
);
|
|
205
244
|
|
|
206
|
-
// If there is no animation, we only have 2 states: visible and invisible
|
|
207
|
-
const hasTwoStates = !routes.some((route) =>
|
|
208
|
-
hasAnimation(descriptors[route.key].options)
|
|
209
|
-
);
|
|
210
|
-
|
|
211
245
|
const tabBarPosition = useTabBarPosition(
|
|
212
246
|
descriptors[focusedRouteKey].options
|
|
213
247
|
);
|
|
@@ -224,12 +258,7 @@ export function BottomTabViewCustom({
|
|
|
224
258
|
{tabBarPosition === 'top' || tabBarPosition === 'left'
|
|
225
259
|
? tabBarElement
|
|
226
260
|
: null}
|
|
227
|
-
<
|
|
228
|
-
key="screens"
|
|
229
|
-
enabled={detachInactiveScreens}
|
|
230
|
-
hasTwoStates={hasTwoStates}
|
|
231
|
-
style={styles.screens}
|
|
232
|
-
>
|
|
261
|
+
<Container key="screens" style={styles.screens}>
|
|
233
262
|
{routes.map((route, index) => {
|
|
234
263
|
const descriptor = descriptors[route.key];
|
|
235
264
|
|
|
@@ -237,6 +266,7 @@ export function BottomTabViewCustom({
|
|
|
237
266
|
|
|
238
267
|
const {
|
|
239
268
|
lazy = true,
|
|
269
|
+
inactiveBehavior = 'pause',
|
|
240
270
|
animation = 'none',
|
|
241
271
|
sceneStyleInterpolator = NAMED_TRANSITIONS_PRESETS[animation]
|
|
242
272
|
.sceneStyleInterpolator,
|
|
@@ -246,6 +276,16 @@ export function BottomTabViewCustom({
|
|
|
246
276
|
const isFocused = state.index === index;
|
|
247
277
|
const isPreloaded = state.preloadedRouteKeys.includes(route.key);
|
|
248
278
|
|
|
279
|
+
if (
|
|
280
|
+
lazy &&
|
|
281
|
+
!loaded.includes(route.key) &&
|
|
282
|
+
!isFocused &&
|
|
283
|
+
!isPreloaded
|
|
284
|
+
) {
|
|
285
|
+
// Don't render a lazy screen if we've never navigated to it or it wasn't preloaded
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
|
|
249
289
|
const animationEnabled = hasAnimation(descriptor.options);
|
|
250
290
|
|
|
251
291
|
const content = (
|
|
@@ -254,75 +294,48 @@ export function BottomTabViewCustom({
|
|
|
254
294
|
progress={tabAnims[route.key]}
|
|
255
295
|
animationEnabled={animationEnabled}
|
|
256
296
|
sceneStyleInterpolator={sceneStyleInterpolator}
|
|
257
|
-
style={customSceneStyle}
|
|
297
|
+
style={[StyleSheet.absoluteFill, customSceneStyle]}
|
|
258
298
|
>
|
|
259
|
-
<
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
? {
|
|
268
|
-
/**
|
|
269
|
-
* Don't use react-native-screens on web:
|
|
270
|
-
* - It applies display: none as fallback, which triggers `onLayout` events
|
|
271
|
-
* - We still need to hide the view when screens is not enabled
|
|
272
|
-
*/
|
|
273
|
-
...StyleSheet.absoluteFillObject,
|
|
274
|
-
visibility: isFocused ? 'visible' : 'hidden',
|
|
275
|
-
}
|
|
276
|
-
: undefined
|
|
277
|
-
}
|
|
299
|
+
<ScreenContent
|
|
300
|
+
isFocused={isFocused}
|
|
301
|
+
route={route}
|
|
302
|
+
navigation={navigation}
|
|
303
|
+
options={options}
|
|
304
|
+
>
|
|
305
|
+
<BottomTabBarHeightContext.Provider
|
|
306
|
+
value={tabBarPosition === 'bottom' ? tabBarHeight : 0}
|
|
278
307
|
>
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
{render()}
|
|
283
|
-
</BottomTabBarHeightContext.Provider>
|
|
284
|
-
</ScreenContent>
|
|
285
|
-
</Lazy>
|
|
308
|
+
{render()}
|
|
309
|
+
</BottomTabBarHeightContext.Provider>
|
|
310
|
+
</ScreenContent>
|
|
286
311
|
</AnimatedScreenContent>
|
|
287
312
|
);
|
|
288
313
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
314
|
+
const isAnimatingRoute =
|
|
315
|
+
isAnimating &&
|
|
316
|
+
(lastUpdate.previous === route.key ||
|
|
317
|
+
lastUpdate.current === route.key);
|
|
292
318
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
STATE_TRANSITIONING_OR_BELOW_TOP,
|
|
301
|
-
STATE_INACTIVE, // the screen is detached after transition
|
|
302
|
-
],
|
|
303
|
-
extrapolate: 'extend',
|
|
304
|
-
})
|
|
305
|
-
: STATE_INACTIVE;
|
|
319
|
+
// For preloaded screens and if lazy is false,
|
|
320
|
+
// Keep them active so that the effects can run
|
|
321
|
+
const isActive =
|
|
322
|
+
inactiveBehavior === 'none' ||
|
|
323
|
+
isAnimatingRoute ||
|
|
324
|
+
isPreloaded ||
|
|
325
|
+
(lazy === false && !loaded.includes(route.key));
|
|
306
326
|
|
|
307
327
|
return (
|
|
308
|
-
<
|
|
328
|
+
<ActivityView
|
|
309
329
|
key={route.key}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
zIndex: isFocused ? 0 : -1,
|
|
314
|
-
pointerEvents: isFocused ? 'auto' : 'none',
|
|
315
|
-
},
|
|
316
|
-
]}
|
|
317
|
-
activityState={activityState}
|
|
318
|
-
enabled={detachInactiveScreens}
|
|
319
|
-
shouldFreeze={activityState === STATE_INACTIVE && !isPreloaded}
|
|
330
|
+
mode={isFocused ? 'normal' : isActive ? 'inert' : 'paused'}
|
|
331
|
+
visible={isFocused || isAnimatingRoute}
|
|
332
|
+
style={{ ...StyleSheet.absoluteFill, zIndex: isFocused ? 0 : -1 }}
|
|
320
333
|
>
|
|
321
334
|
{content}
|
|
322
|
-
</
|
|
335
|
+
</ActivityView>
|
|
323
336
|
);
|
|
324
337
|
})}
|
|
325
|
-
</
|
|
338
|
+
</Container>
|
|
326
339
|
{tabBarPosition === 'bottom' || tabBarPosition === 'right'
|
|
327
340
|
? tabBarElement
|
|
328
341
|
: null}
|
|
@@ -339,7 +352,7 @@ function AnimatedScreenContent({
|
|
|
339
352
|
}: {
|
|
340
353
|
progress: Animated.Value;
|
|
341
354
|
animationEnabled: boolean;
|
|
342
|
-
sceneStyleInterpolator?: BottomTabSceneStyleInterpolator;
|
|
355
|
+
sceneStyleInterpolator?: BottomTabSceneStyleInterpolator | undefined;
|
|
343
356
|
children: React.ReactNode;
|
|
344
357
|
style: StyleProp<ViewStyle>;
|
|
345
358
|
}) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getLabel } from '@react-navigation/elements';
|
|
2
2
|
import {
|
|
3
|
+
ActivityView,
|
|
3
4
|
Color,
|
|
4
|
-
Lazy,
|
|
5
5
|
SafeAreaProviderCompat,
|
|
6
6
|
} from '@react-navigation/elements/internal';
|
|
7
7
|
import {
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type ColorValue,
|
|
21
21
|
Platform,
|
|
22
22
|
PlatformColor,
|
|
23
|
+
StyleSheet,
|
|
23
24
|
} from 'react-native';
|
|
24
25
|
import {
|
|
25
26
|
type PlatformIcon,
|
|
@@ -62,6 +63,18 @@ export function BottomTabViewNative({
|
|
|
62
63
|
const { dark, colors, fonts } = useTheme();
|
|
63
64
|
|
|
64
65
|
const focusedRouteKey = state.routes[state.index].key;
|
|
66
|
+
|
|
67
|
+
const [loaded, setLoaded] = React.useState([focusedRouteKey]);
|
|
68
|
+
|
|
69
|
+
if (!loaded.includes(focusedRouteKey)) {
|
|
70
|
+
setLoaded([...loaded, focusedRouteKey]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const [pendingNavigation, setPendingNavigation] = React.useState<{
|
|
74
|
+
from: string;
|
|
75
|
+
to: string;
|
|
76
|
+
} | null>(null);
|
|
77
|
+
|
|
65
78
|
const previousRouteKeyRef = React.useRef(focusedRouteKey);
|
|
66
79
|
|
|
67
80
|
React.useEffect(() => {
|
|
@@ -80,11 +93,26 @@ export function BottomTabViewNative({
|
|
|
80
93
|
...StackActions.popToTop(),
|
|
81
94
|
target: prevRoute.state.key,
|
|
82
95
|
};
|
|
96
|
+
|
|
83
97
|
navigation.dispatch(popToTopAction);
|
|
84
98
|
}
|
|
85
99
|
}
|
|
86
100
|
|
|
87
101
|
previousRouteKeyRef.current = focusedRouteKey;
|
|
102
|
+
|
|
103
|
+
// Delay clearing `isAnimating`
|
|
104
|
+
// This will give time for `popToAction` to get handled before pause
|
|
105
|
+
const timer = setTimeout(() => {
|
|
106
|
+
setPendingNavigation((pending) => {
|
|
107
|
+
if (pending?.to === focusedRouteKey) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return pending;
|
|
112
|
+
});
|
|
113
|
+
}, 32);
|
|
114
|
+
|
|
115
|
+
return () => clearTimeout(timer);
|
|
88
116
|
}, [descriptors, focusedRouteKey, navigation, state.index, state.routes]);
|
|
89
117
|
|
|
90
118
|
const currentOptions = descriptors[state.routes[state.index].key]?.options;
|
|
@@ -265,6 +293,11 @@ export function BottomTabViewNative({
|
|
|
265
293
|
state.routes.findIndex((r) => r.key === route.key);
|
|
266
294
|
|
|
267
295
|
if (!isFocused) {
|
|
296
|
+
setPendingNavigation({
|
|
297
|
+
from: previousRouteKeyRef.current,
|
|
298
|
+
to: route.key,
|
|
299
|
+
});
|
|
300
|
+
|
|
268
301
|
navigation.dispatch({
|
|
269
302
|
...CommonActions.navigate(route.name, route.params),
|
|
270
303
|
target: state.key,
|
|
@@ -281,6 +314,7 @@ export function BottomTabViewNative({
|
|
|
281
314
|
const {
|
|
282
315
|
title,
|
|
283
316
|
lazy = true,
|
|
317
|
+
inactiveBehavior = 'pause',
|
|
284
318
|
tabBarLabel,
|
|
285
319
|
tabBarBadgeStyle,
|
|
286
320
|
tabBarIcon,
|
|
@@ -355,6 +389,15 @@ export function BottomTabViewNative({
|
|
|
355
389
|
const icon = getIcon(false);
|
|
356
390
|
const selectedIcon = getIcon(true);
|
|
357
391
|
|
|
392
|
+
// For preloaded screens and if lazy is false,
|
|
393
|
+
// Keep them active so that the effects can run
|
|
394
|
+
const isActive =
|
|
395
|
+
inactiveBehavior === 'none' ||
|
|
396
|
+
isPreloaded ||
|
|
397
|
+
pendingNavigation?.from === route.key ||
|
|
398
|
+
pendingNavigation?.to === route.key ||
|
|
399
|
+
(lazy === false && !loaded.includes(route.key));
|
|
400
|
+
|
|
358
401
|
return (
|
|
359
402
|
<Tabs.Screen
|
|
360
403
|
onWillAppear={() => onTransitionStart({ route })}
|
|
@@ -390,6 +433,9 @@ export function BottomTabViewNative({
|
|
|
390
433
|
: scrollEdgeEffects?.right,
|
|
391
434
|
}}
|
|
392
435
|
scrollEdgeAppearance={{
|
|
436
|
+
tabBarBackgroundColor,
|
|
437
|
+
tabBarShadowColor,
|
|
438
|
+
tabBarBlurEffect,
|
|
393
439
|
stacked: {
|
|
394
440
|
normal: tabItemAppearance,
|
|
395
441
|
},
|
|
@@ -425,23 +471,38 @@ export function BottomTabViewNative({
|
|
|
425
471
|
}
|
|
426
472
|
experimental_userInterfaceStyle={dark ? 'dark' : 'light'}
|
|
427
473
|
>
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
474
|
+
{lazy &&
|
|
475
|
+
!loaded.includes(route.key) &&
|
|
476
|
+
!isFocused &&
|
|
477
|
+
!isPreloaded ? null : (
|
|
478
|
+
<ActivityView
|
|
479
|
+
key={route.key}
|
|
480
|
+
mode={isFocused ? 'normal' : isActive ? 'inert' : 'paused'}
|
|
481
|
+
visible={
|
|
482
|
+
// We don't need to hide the content since it's handled natively
|
|
483
|
+
// Hiding may also cause flash due to lag after native tab switch
|
|
484
|
+
// So we leave it always visible
|
|
485
|
+
true
|
|
486
|
+
}
|
|
487
|
+
style={StyleSheet.absoluteFill}
|
|
435
488
|
>
|
|
436
|
-
<
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
489
|
+
<ScreenContent
|
|
490
|
+
isFocused={isFocused}
|
|
491
|
+
route={route}
|
|
492
|
+
navigation={navigation}
|
|
493
|
+
options={options}
|
|
494
|
+
style={sceneStyle}
|
|
495
|
+
>
|
|
496
|
+
<AnimatedScreenContent isFocused={isFocused}>
|
|
497
|
+
<BottomTabBarHeightContext.Provider value={0}>
|
|
498
|
+
<NavigationMetaContext.Provider value={meta}>
|
|
499
|
+
{render()}
|
|
500
|
+
</NavigationMetaContext.Provider>
|
|
501
|
+
</BottomTabBarHeightContext.Provider>
|
|
502
|
+
</AnimatedScreenContent>
|
|
503
|
+
</ScreenContent>
|
|
504
|
+
</ActivityView>
|
|
505
|
+
)}
|
|
445
506
|
</Tabs.Screen>
|
|
446
507
|
);
|
|
447
508
|
})}
|
package/src/views/TabBarIcon.tsx
CHANGED
|
@@ -18,8 +18,8 @@ export type TabBarIconProps = {
|
|
|
18
18
|
route: Route<string>;
|
|
19
19
|
variant: 'uikit' | 'material';
|
|
20
20
|
size: 'compact' | 'regular';
|
|
21
|
-
badge?: string | number;
|
|
22
|
-
badgeStyle?: StyleProp<TextStyle
|
|
21
|
+
badge?: string | number | undefined;
|
|
22
|
+
badgeStyle?: StyleProp<TextStyle> | undefined;
|
|
23
23
|
activeOpacity: number;
|
|
24
24
|
inactiveOpacity: number;
|
|
25
25
|
activeTintColor: ColorValue;
|
|
@@ -31,7 +31,7 @@ export type TabBarIconProps = {
|
|
|
31
31
|
color: ColorValue;
|
|
32
32
|
size: number;
|
|
33
33
|
}) => BottomTabIcon | React.ReactNode);
|
|
34
|
-
allowFontScaling?: boolean;
|
|
34
|
+
allowFontScaling?: boolean | undefined;
|
|
35
35
|
style: StyleProp<ViewStyle>;
|
|
36
36
|
};
|
|
37
37
|
|