@react-navigation/bottom-tabs 8.0.0-alpha.32 → 8.0.0-alpha.34
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/views/BottomTabBar.js +20 -14
- package/lib/module/views/BottomTabBar.js.map +1 -1
- package/lib/module/views/BottomTabViewCustom.js +39 -18
- package/lib/module/views/BottomTabViewCustom.js.map +1 -1
- package/lib/module/views/BottomTabViewNativeImpl.js +42 -26
- 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/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 +2 -2
- package/lib/typescript/src/navigators/createBottomTabNavigator.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +8 -2
- 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/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 +3 -3
- package/lib/typescript/src/views/BottomTabItem.d.ts.map +1 -1
- package/lib/typescript/src/views/BottomTabView.d.ts +2 -2
- package/lib/typescript/src/views/BottomTabView.d.ts.map +1 -1
- 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 +2 -2
- package/lib/typescript/src/views/ScreenContent.d.ts.map +1 -1
- package/lib/typescript/src/views/TabBarIcon.d.ts +1 -1
- package/lib/typescript/src/views/TabBarIcon.d.ts.map +1 -1
- package/package.json +13 -13
- package/src/types.tsx +8 -2
- package/src/views/BottomTabBar.tsx +38 -9
- package/src/views/BottomTabViewCustom.tsx +57 -24
- package/src/views/BottomTabViewNativeImpl.tsx +27 -9
- package/src/views/Deferred.tsx +57 -0
|
@@ -36,6 +36,7 @@ import { BottomTabBarHeightContext } from '../utils/BottomTabBarHeightContext';
|
|
|
36
36
|
import { useAnimatedHashMap } from '../utils/useAnimatedHashMap';
|
|
37
37
|
import { useTabBarPosition } from '../utils/useTabBarPosition';
|
|
38
38
|
import { BottomTabBar, getTabBarHeight } from './BottomTabBar';
|
|
39
|
+
import { Deferred } from './Deferred';
|
|
39
40
|
import { ScreenContent } from './ScreenContent';
|
|
40
41
|
|
|
41
42
|
type Props = BottomTabNavigationConfig & {
|
|
@@ -79,7 +80,14 @@ export function BottomTabViewCustom({
|
|
|
79
80
|
descriptors,
|
|
80
81
|
}: Props) {
|
|
81
82
|
const { routes } = state;
|
|
82
|
-
const
|
|
83
|
+
const focusedRoute = routes[state.index];
|
|
84
|
+
|
|
85
|
+
if (focusedRoute == null) {
|
|
86
|
+
throw new Error(`Couldn't find a route at index ${state.index}.`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const focusedRouteKey = focusedRoute.key;
|
|
90
|
+
const focusedOptions = descriptors[focusedRouteKey]?.options;
|
|
83
91
|
|
|
84
92
|
const [loaded, setLoaded] = React.useState([focusedRouteKey]);
|
|
85
93
|
|
|
@@ -141,7 +149,15 @@ export function BottomTabViewCustom({
|
|
|
141
149
|
|
|
142
150
|
const animations = state.routes
|
|
143
151
|
.map((route, index) => {
|
|
144
|
-
const
|
|
152
|
+
const descriptor = descriptors[route.key];
|
|
153
|
+
|
|
154
|
+
if (descriptor == null) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`Couldn't find a descriptor for route '${route.key}'.`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const { options } = descriptor;
|
|
145
161
|
const {
|
|
146
162
|
animation = 'none',
|
|
147
163
|
transitionSpec = NAMED_TRANSITIONS_PRESETS[animation]
|
|
@@ -161,7 +177,15 @@ export function BottomTabViewCustom({
|
|
|
161
177
|
const toValue =
|
|
162
178
|
index === state.index ? 0 : index >= state.index ? 1 : -1;
|
|
163
179
|
|
|
164
|
-
|
|
180
|
+
const tabAnimation = tabAnims[route.key];
|
|
181
|
+
|
|
182
|
+
if (tabAnimation == null) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
`Couldn't find an animation for route '${route.key}'.`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return Animated[spec.animation](tabAnimation, {
|
|
165
189
|
...spec.config,
|
|
166
190
|
toValue,
|
|
167
191
|
useNativeDriver,
|
|
@@ -218,7 +242,7 @@ export function BottomTabViewCustom({
|
|
|
218
242
|
descriptors,
|
|
219
243
|
dimensions: SafeAreaProviderCompat.initialMetrics.frame,
|
|
220
244
|
insets: SafeAreaProviderCompat.initialMetrics.insets,
|
|
221
|
-
style:
|
|
245
|
+
style: focusedOptions?.tabBarStyle,
|
|
222
246
|
})
|
|
223
247
|
);
|
|
224
248
|
|
|
@@ -235,9 +259,7 @@ export function BottomTabViewCustom({
|
|
|
235
259
|
</BottomTabBarHeightCallbackContext.Provider>
|
|
236
260
|
);
|
|
237
261
|
|
|
238
|
-
const tabBarPosition = useTabBarPosition(
|
|
239
|
-
descriptors[focusedRouteKey].options
|
|
240
|
-
);
|
|
262
|
+
const tabBarPosition = useTabBarPosition(focusedOptions ?? {});
|
|
241
263
|
|
|
242
264
|
return (
|
|
243
265
|
<SafeAreaProviderCompat
|
|
@@ -255,6 +277,12 @@ export function BottomTabViewCustom({
|
|
|
255
277
|
{routes.map((route, index) => {
|
|
256
278
|
const descriptor = descriptors[route.key];
|
|
257
279
|
|
|
280
|
+
if (descriptor == null) {
|
|
281
|
+
throw new Error(
|
|
282
|
+
`Couldn't find a descriptor for route '${route.key}'.`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
258
286
|
const { navigation, options, render } = descriptor;
|
|
259
287
|
|
|
260
288
|
const {
|
|
@@ -269,22 +297,19 @@ export function BottomTabViewCustom({
|
|
|
269
297
|
const isFocused = state.index === index;
|
|
270
298
|
const isPreloaded = state.preloadedRouteKeys.includes(route.key);
|
|
271
299
|
|
|
272
|
-
if (
|
|
273
|
-
lazy &&
|
|
274
|
-
!loaded.includes(route.key) &&
|
|
275
|
-
!isFocused &&
|
|
276
|
-
!isPreloaded
|
|
277
|
-
) {
|
|
278
|
-
// Don't render a lazy screen if we've never navigated to it or it wasn't preloaded
|
|
279
|
-
return null;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
300
|
const animationEnabled = hasAnimation(descriptor.options);
|
|
301
|
+
const tabAnimation = tabAnims[route.key];
|
|
302
|
+
|
|
303
|
+
if (tabAnimation == null) {
|
|
304
|
+
throw new Error(
|
|
305
|
+
`Couldn't find an animation for route '${route.key}'.`
|
|
306
|
+
);
|
|
307
|
+
}
|
|
283
308
|
|
|
284
309
|
const content = (
|
|
285
310
|
<AnimatedScreenContent
|
|
286
311
|
key={route.key}
|
|
287
|
-
progress={
|
|
312
|
+
progress={tabAnimation}
|
|
288
313
|
animationEnabled={animationEnabled}
|
|
289
314
|
sceneStyleInterpolator={sceneStyleInterpolator}
|
|
290
315
|
style={[StyleSheet.absoluteFill, customSceneStyle]}
|
|
@@ -318,14 +343,22 @@ export function BottomTabViewCustom({
|
|
|
318
343
|
(lazy === false && !loaded.includes(route.key));
|
|
319
344
|
|
|
320
345
|
return (
|
|
321
|
-
<
|
|
346
|
+
<Deferred
|
|
322
347
|
key={route.key}
|
|
323
|
-
|
|
324
|
-
visible={isFocused ||
|
|
325
|
-
style={{ ...StyleSheet.absoluteFill, zIndex: isFocused ? 0 : -1 }}
|
|
348
|
+
lazy={lazy}
|
|
349
|
+
visible={isFocused || isPreloaded || loaded.includes(route.key)}
|
|
326
350
|
>
|
|
327
|
-
|
|
328
|
-
|
|
351
|
+
<ActivityView
|
|
352
|
+
mode={isFocused ? 'normal' : isActive ? 'inert' : 'paused'}
|
|
353
|
+
visible={isFocused || isAnimatingRoute}
|
|
354
|
+
style={{
|
|
355
|
+
...StyleSheet.absoluteFill,
|
|
356
|
+
zIndex: isFocused ? 0 : -1,
|
|
357
|
+
}}
|
|
358
|
+
>
|
|
359
|
+
{content}
|
|
360
|
+
</ActivityView>
|
|
361
|
+
</Deferred>
|
|
329
362
|
);
|
|
330
363
|
})}
|
|
331
364
|
</Container>
|
|
@@ -39,10 +39,12 @@ import type {
|
|
|
39
39
|
BottomTabDescriptorMap,
|
|
40
40
|
BottomTabNavigationConfig,
|
|
41
41
|
BottomTabNavigationHelpers,
|
|
42
|
+
BottomTabNavigationOptions,
|
|
42
43
|
} from '../types';
|
|
43
44
|
import { BottomTabAnimationContext } from '../utils/BottomTabAnimationContext';
|
|
44
45
|
import { BottomTabBarHeightContext } from '../utils/BottomTabBarHeightContext';
|
|
45
46
|
import { useTabBarPosition } from '../utils/useTabBarPosition';
|
|
47
|
+
import { Deferred } from './Deferred';
|
|
46
48
|
import { ScreenContent } from './ScreenContent';
|
|
47
49
|
|
|
48
50
|
type Props = BottomTabNavigationConfig & {
|
|
@@ -125,7 +127,13 @@ export function BottomTabViewNative({
|
|
|
125
127
|
}: Props) {
|
|
126
128
|
const { dark, colors, fonts } = useTheme();
|
|
127
129
|
|
|
128
|
-
const
|
|
130
|
+
const focusedRoute = state.routes[state.index];
|
|
131
|
+
|
|
132
|
+
if (focusedRoute == null) {
|
|
133
|
+
throw new Error(`Couldn't find a route at index ${state.index}.`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const focusedRouteKey = focusedRoute.key;
|
|
129
137
|
|
|
130
138
|
const [loaded, setLoaded] = React.useState([focusedRouteKey]);
|
|
131
139
|
|
|
@@ -302,7 +310,8 @@ export function BottomTabViewNative({
|
|
|
302
310
|
});
|
|
303
311
|
};
|
|
304
312
|
|
|
305
|
-
const currentOptions =
|
|
313
|
+
const currentOptions: BottomTabNavigationOptions =
|
|
314
|
+
descriptors[focusedRouteKey]?.options ?? {};
|
|
306
315
|
|
|
307
316
|
const {
|
|
308
317
|
fontFamily = Platform.select({
|
|
@@ -438,6 +447,7 @@ export function BottomTabViewNative({
|
|
|
438
447
|
onTabSelectionRejected={onTabSelectionRejected}
|
|
439
448
|
onTabSelectionPrevented={onTabSelectionPrevented}
|
|
440
449
|
tabBarHidden={hasCustomTabBar || shouldHideTabBar}
|
|
450
|
+
nativeContainerStyle={{ backgroundColor }}
|
|
441
451
|
colorScheme={dark ? 'dark' : 'light'}
|
|
442
452
|
ios={{
|
|
443
453
|
bottomAccessory: bottomAccessory
|
|
@@ -450,13 +460,21 @@ export function BottomTabViewNative({
|
|
|
450
460
|
}}
|
|
451
461
|
>
|
|
452
462
|
{state.routes.map((route, index) => {
|
|
453
|
-
const
|
|
463
|
+
const descriptor = descriptors[route.key];
|
|
464
|
+
|
|
465
|
+
if (descriptor == null) {
|
|
466
|
+
throw new Error(
|
|
467
|
+
`Couldn't find a descriptor for route '${route.key}'.`
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const { options, render, navigation } = descriptor;
|
|
454
472
|
const isFocused = state.index === index;
|
|
455
473
|
const isPreloaded = state.preloadedRouteKeys.includes(route.key);
|
|
456
474
|
|
|
457
475
|
const {
|
|
458
476
|
title,
|
|
459
|
-
lazy =
|
|
477
|
+
lazy = false,
|
|
460
478
|
inactiveBehavior = 'pause',
|
|
461
479
|
tabBarLabel,
|
|
462
480
|
tabBarSelectionEnabled,
|
|
@@ -630,10 +648,10 @@ export function BottomTabViewNative({
|
|
|
630
648
|
overrideScrollViewContentInsetAdjustmentBehavior,
|
|
631
649
|
}}
|
|
632
650
|
>
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
651
|
+
<Deferred
|
|
652
|
+
lazy={lazy}
|
|
653
|
+
visible={isFocused || isPreloaded || loaded.includes(route.key)}
|
|
654
|
+
>
|
|
637
655
|
<ActivityView
|
|
638
656
|
key={route.key}
|
|
639
657
|
mode={isFocused ? 'normal' : isActive ? 'inert' : 'paused'}
|
|
@@ -661,7 +679,7 @@ export function BottomTabViewNative({
|
|
|
661
679
|
</AnimatedScreenContent>
|
|
662
680
|
</ScreenContent>
|
|
663
681
|
</ActivityView>
|
|
664
|
-
|
|
682
|
+
</Deferred>
|
|
665
683
|
</Tabs.Screen>
|
|
666
684
|
);
|
|
667
685
|
})}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
/**
|
|
5
|
+
* Whether lazy rendering is enabled.
|
|
6
|
+
*/
|
|
7
|
+
lazy: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Whether the component is visible.
|
|
10
|
+
*/
|
|
11
|
+
visible: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Content to render.
|
|
14
|
+
*/
|
|
15
|
+
children: React.ReactElement;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Render content lazily based on visibility.
|
|
20
|
+
*
|
|
21
|
+
* When lazy is enabled:
|
|
22
|
+
* - If content is visible, it will render immediately
|
|
23
|
+
* - If content is not visible, it won't render until it becomes visible
|
|
24
|
+
*
|
|
25
|
+
* Otherwise:
|
|
26
|
+
* - If content is visible, it will render immediately
|
|
27
|
+
* - If content is not visible, it will defer rendering
|
|
28
|
+
*
|
|
29
|
+
* Once rendered, the content remains rendered.
|
|
30
|
+
*/
|
|
31
|
+
export function Deferred({ lazy, visible, children }: Props) {
|
|
32
|
+
const [rendered, setRendered] = React.useState(lazy ? visible : false);
|
|
33
|
+
|
|
34
|
+
const shouldRenderDeferred = !(lazy || visible || rendered);
|
|
35
|
+
|
|
36
|
+
React.useEffect(() => {
|
|
37
|
+
if (shouldRenderDeferred === false) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
React.startTransition(() => {
|
|
42
|
+
setRendered(true);
|
|
43
|
+
});
|
|
44
|
+
}, [shouldRenderDeferred]);
|
|
45
|
+
|
|
46
|
+
if (visible && rendered === false) {
|
|
47
|
+
setRendered(true);
|
|
48
|
+
|
|
49
|
+
return children;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (rendered) {
|
|
53
|
+
return children;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return null;
|
|
57
|
+
}
|