@react-navigation/bottom-tabs 8.0.0-alpha.56 → 8.0.0-alpha.57

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/src/types.tsx CHANGED
@@ -194,7 +194,7 @@ type BottomTabCustomOptions = {
194
194
  *
195
195
  * Only supported with `custom` implementation.
196
196
  */
197
- tabBarIconStyle?: StyleProp<TextStyle>;
197
+ tabBarIconStyle?: StyleProp<ViewStyle>;
198
198
 
199
199
  /**
200
200
  * Whether the tab bar gets hidden when the keyboard is shown.
@@ -274,19 +274,106 @@ type BottomTabCustomOptions = {
274
274
  | undefined;
275
275
  };
276
276
 
277
+ type TabBarLabelOffset = {
278
+ horizontal?: number | undefined;
279
+ vertical?: number | undefined;
280
+ };
281
+
277
282
  type BottomTabNativeOptions = {
278
283
  /**
279
284
  * Uses iOS built-in tab bar items with standard iOS styling and localized titles.
280
- * If set to `search`, it's positioned next to the tab bar on iOS 26 and above.
281
285
  *
282
- * The `tabBarIcon` and `tabBarLabel` options will override the icon and label from the system item.
286
+ * The `tabBarIcon` and `tabBarLabel` options override the icon and label from the system item.
283
287
  * If you want to keep the system behavior on iOS, but need to provide icon and label for other platforms,
284
288
  * Use `Platform.OS` or `Platform.select` to conditionally set `undefined` for `tabBarIcon` and `tabBarLabel` on iOS.
285
289
  *
290
+ * If set to `search`, it may receive the prominent visual treatment on iOS 26.
291
+ * See `tabBarRole` for more details on iOS 27 and above.
292
+ *
286
293
  * @platform ios
287
294
  */
288
295
  tabBarSystemItem?: TabsScreenSystemItem | undefined;
289
296
 
297
+ /**
298
+ * The role of the tab within the system tab bar.
299
+ *
300
+ * Supported values:
301
+ * - `prominent` - the tab gets the prominent visual treatment when supported
302
+ * - `search` - the tab is used as the system search tab
303
+ *
304
+ * If set to `prominent`, the tab may receive special styling to make it stand out,
305
+ * e.g., being positioned as a separate button next to the tab bar on iOS 27 and above.
306
+ * Only one tab can have the `prominent` role at a time.
307
+ * Supported on iOS 27 and above.
308
+ *
309
+ * If set to `search`, the tab gets the prominent visual treatment on iOS 26.
310
+ * On iOS 27 and above, it gets the prominent styling only if `tabBarSearchAutoFocus` is enabled,
311
+ * and no other tab has the `prominent` role.
312
+ * The tab uses system search icon and label by default.
313
+ * They can be overridden by `tabBarSystemItem`, `tabBarIcon`, and `tabBarLabel` options.
314
+ * Adding or removing the `search` role after the tab is rendered is not supported.
315
+ * Supported on iOS 26.1 and above.
316
+ *
317
+ * Only supported with `native` implementation.
318
+ *
319
+ * @platform ios
320
+ */
321
+ tabBarRole?: 'prominent' | 'search' | undefined;
322
+
323
+ /**
324
+ * Whether the search field is automatically focused when the tab is selected.
325
+ * Cancelling the search selects the previously selected tab.
326
+ *
327
+ * Only applies to tabs with `tabBarRole: 'search'`,
328
+ * and requires `headerSearchBarOptions` to be set in a native stack nested in the tab.
329
+ *
330
+ * Defaults to `false`.
331
+ *
332
+ * Only supported with `native` implementation.
333
+ *
334
+ * Supported on iOS 26.1 and above.
335
+ *
336
+ * @platform ios
337
+ */
338
+ tabBarSearchAutoFocus?: boolean | undefined;
339
+
340
+ /**
341
+ * Whether the sidebar or the tab bar is preferred when only one of them can be displayed.
342
+ *
343
+ * Supported values:
344
+ * - `auto` - uses the system default (tab bar)
345
+ * - `sidebar` - the sidebar is displayed when it's available
346
+ * - `tabBar` - the tab bar is displayed
347
+ *
348
+ * Requires `tabBarControllerMode` to be set to `tabSidebar`.
349
+ *
350
+ * The sidebar is only available when the horizontal size class is regular,
351
+ * e.g. on iPad, or on larger iPhones in landscape.
352
+ *
353
+ * Defaults to `auto`.
354
+ *
355
+ * Only supported with `native` implementation.
356
+ *
357
+ * Supported on iOS 27 and above.
358
+ * Not supported on tvOS.
359
+ *
360
+ * @platform ios
361
+ */
362
+ tabBarSidebarPreferredPlacement?: 'auto' | 'sidebar' | 'tabBar' | undefined;
363
+
364
+ /**
365
+ * Whether showing and hiding the tab bar is animated.
366
+ *
367
+ * Defaults to `true`.
368
+ *
369
+ * Only supported with `native` implementation.
370
+ *
371
+ * Supported on iOS 18 and above.
372
+ *
373
+ * @platform ios
374
+ */
375
+ tabBarVisibilityAnimationEnabled?: boolean | undefined;
376
+
290
377
  /**
291
378
  * Blur effect applied to the tab bar when tab screen is selected.
292
379
  *
@@ -337,6 +424,28 @@ type BottomTabNativeOptions = {
337
424
  | 'onScrollUp'
338
425
  | undefined;
339
426
 
427
+ /**
428
+ * Offset applied to the tab label relative to its default position.
429
+ * Positive `vertical` moves the label down, positive `horizontal` moves it right.
430
+ *
431
+ * The offset is specified separately for each tab bar item layout:
432
+ *
433
+ * - `stacked` - icon above the label, e.g. on iPhone in portrait
434
+ * - `inline` - icon beside the label in regular width, e.g. on iPad
435
+ * - `compactInline` - icon beside the label in compact width, e.g. on iPhone in landscape
436
+ *
437
+ * Only supported with `native` implementation.
438
+ *
439
+ * @platform ios
440
+ */
441
+ tabBarLabelPositionAdjustment?:
442
+ | {
443
+ stacked?: TabBarLabelOffset | undefined;
444
+ inline?: TabBarLabelOffset | undefined;
445
+ compactInline?: TabBarLabelOffset | undefined;
446
+ }
447
+ | undefined;
448
+
340
449
  /**
341
450
  * Background color of the active indicator.
342
451
  *
@@ -355,6 +464,24 @@ type BottomTabNativeOptions = {
355
464
  */
356
465
  tabBarActiveIndicatorEnabled?: boolean | undefined;
357
466
 
467
+ /**
468
+ * Width of the tab's active indicator.
469
+ *
470
+ * Only supported with `native` implementation.
471
+ *
472
+ * @platform android
473
+ */
474
+ tabBarActiveIndicatorWidth?: number | undefined;
475
+
476
+ /**
477
+ * Height of the tab's active indicator.
478
+ *
479
+ * Only supported with `native` implementation.
480
+ *
481
+ * @platform android
482
+ */
483
+ tabBarActiveIndicatorHeight?: number | undefined;
484
+
358
485
  /**
359
486
  * Function which returns a React element to display as an accessory view.
360
487
  *
@@ -431,6 +558,17 @@ export type BottomTabNavigationOptions = {
431
558
  */
432
559
  tabBarLabelVisibilityMode?: TabBarItemLabelVisibilityMode | undefined;
433
560
 
561
+ /**
562
+ * Size of the tab's icon.
563
+ *
564
+ * With `native` implementation, the largest size is used for the icon area in all tabs.
565
+ * Icons smaller than the largest size are centered in this area.
566
+ *
567
+ * Supported on all platforms with `custom` implementation.
568
+ * Only supported on Android with `native` implementation.
569
+ */
570
+ tabBarIconSize?: number | undefined;
571
+
434
572
  /**
435
573
  * Style object for the tab label.
436
574
  */
@@ -450,8 +588,6 @@ export type BottomTabNavigationOptions = {
450
588
  * - on all platforms with `custom` implementation
451
589
  * - on iOS with `native` implementation
452
590
  *
453
- * With `native` implementation, `tinted` for `image` can only be disabled on iOS.
454
- *
455
591
  * A React element is only supported with `custom` implementation.
456
592
  */
457
593
  tabBarIcon?:
@@ -15,6 +15,7 @@ import {
15
15
  import * as React from 'react';
16
16
  import {
17
17
  Animated,
18
+ type ColorValue,
18
19
  type LayoutChangeEvent,
19
20
  Platform,
20
21
  type StyleProp,
@@ -26,8 +27,14 @@ import {
26
27
  type EdgeInsets,
27
28
  useSafeAreaInsets,
28
29
  } from 'react-native-safe-area-context';
29
-
30
- import type { BottomTabBarProps, BottomTabDescriptorMap } from '../types';
30
+ import type { TabBarItemLabelVisibilityMode } from 'react-native-screens';
31
+
32
+ import type {
33
+ BottomTabBarProps,
34
+ BottomTabDescriptor,
35
+ BottomTabDescriptorMap,
36
+ BottomTabNavigationHelpers,
37
+ } from '../types';
31
38
  import { BottomTabBarHeightCallbackContext } from '../utils/BottomTabBarHeightCallbackContext';
32
39
  import { useIsKeyboardShown } from '../utils/useIsKeyboardShown';
33
40
  import { useTabBarPosition } from '../utils/useTabBarPosition';
@@ -437,47 +444,6 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
437
444
 
438
445
  const { options } = descriptor;
439
446
 
440
- const onPress = () => {
441
- const isRepeatedPress =
442
- focused && options.tabBarSelectionEnabled !== false;
443
-
444
- const event = navigation.emit({
445
- type: 'tabPress',
446
- target: route.key,
447
- canPreventDefault: true,
448
- data: {
449
- behavior: {
450
- scrollToTop:
451
- isRepeatedPress &&
452
- options.tabBarRepeatedPressBehavior?.scrollToTop !== false,
453
- popToTop:
454
- isRepeatedPress &&
455
- options.tabBarRepeatedPressBehavior?.popToTop !== false,
456
- },
457
- },
458
- });
459
-
460
- if (
461
- !focused &&
462
- !event.defaultPrevented &&
463
- options.tabBarSelectionEnabled !== false
464
- ) {
465
- React.startTransition(() => {
466
- navigation.dispatch({
467
- ...CommonActions.navigate(route.name, route.params),
468
- target: state.key,
469
- });
470
- });
471
- }
472
- };
473
-
474
- const onLongPress = () => {
475
- navigation.emit({
476
- type: 'tabLongPress',
477
- target: route.key,
478
- });
479
- };
480
-
481
447
  const label =
482
448
  typeof options.tabBarLabel === 'function'
483
449
  ? options.tabBarLabel
@@ -496,52 +462,27 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
496
462
  : undefined;
497
463
 
498
464
  return (
499
- <NavigationProvider
465
+ <BottomTabBarItem
500
466
  key={route.key}
501
- navigation={descriptor.navigation}
502
467
  route={route}
503
- >
504
- <BottomTabItem
505
- href={buildHref(route.name, route.params)}
506
- route={route}
507
- descriptor={descriptor}
508
- focused={focused}
509
- horizontal={hasHorizontalLabels}
510
- compact={compact}
511
- sidebar={sidebar}
512
- variant={tabBarVariant}
513
- onPress={onPress}
514
- onLongPress={onLongPress}
515
- accessibilityLabel={accessibilityLabel}
516
- testID={options.tabBarButtonTestID}
517
- allowFontScaling={options.tabBarAllowFontScaling}
518
- activeTintColor={tabBarActiveTintColor}
519
- inactiveTintColor={tabBarInactiveTintColor}
520
- activeBackgroundColor={tabBarActiveBackgroundColor}
521
- inactiveBackgroundColor={tabBarInactiveBackgroundColor}
522
- rippleColor={options.tabBarRippleColor}
523
- button={options.tabBarButton}
524
- icon={options.tabBarIcon}
525
- badge={options.tabBarBadge}
526
- badgeStyle={options.tabBarBadgeStyle}
527
- label={label}
528
- labelVisibilityMode={tabBarLabelVisibilityMode}
529
- labelStyle={options.tabBarLabelStyle}
530
- iconStyle={options.tabBarIconStyle}
531
- style={[
532
- sidebar
533
- ? {
534
- marginVertical: hasHorizontalLabels
535
- ? tabBarVariant === 'material'
536
- ? 0
537
- : 1
538
- : spacing / 2,
539
- }
540
- : styles.bottomItem,
541
- options.tabBarItemStyle,
542
- ]}
543
- />
544
- </NavigationProvider>
468
+ descriptor={descriptor}
469
+ navigation={navigation}
470
+ navigatorKey={state.key}
471
+ href={buildHref(route.name, route.params)}
472
+ focused={focused}
473
+ label={label}
474
+ accessibilityLabel={accessibilityLabel}
475
+ hasHorizontalLabels={hasHorizontalLabels}
476
+ compact={compact}
477
+ sidebar={sidebar}
478
+ tabBarVariant={tabBarVariant}
479
+ spacing={spacing}
480
+ tabBarActiveTintColor={tabBarActiveTintColor}
481
+ tabBarInactiveTintColor={tabBarInactiveTintColor}
482
+ tabBarActiveBackgroundColor={tabBarActiveBackgroundColor}
483
+ tabBarInactiveBackgroundColor={tabBarInactiveBackgroundColor}
484
+ tabBarLabelVisibilityMode={tabBarLabelVisibilityMode}
485
+ />
545
486
  );
546
487
  })}
547
488
  </View>
@@ -549,6 +490,136 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
549
490
  );
550
491
  }
551
492
 
493
+ type BottomTabBarItemProps = {
494
+ route: TabNavigationState<ParamListBase>['routes'][number];
495
+ descriptor: BottomTabDescriptor;
496
+ navigation: BottomTabNavigationHelpers;
497
+ navigatorKey: string;
498
+ href: string | undefined;
499
+ focused: boolean;
500
+ label: React.ComponentProps<typeof BottomTabItem>['label'];
501
+ accessibilityLabel: string | undefined;
502
+ hasHorizontalLabels: boolean;
503
+ compact: boolean;
504
+ sidebar: boolean;
505
+ tabBarVariant: 'uikit' | 'material';
506
+ spacing: number;
507
+ tabBarActiveTintColor: ColorValue | undefined;
508
+ tabBarInactiveTintColor: ColorValue | undefined;
509
+ tabBarActiveBackgroundColor: ColorValue | undefined;
510
+ tabBarInactiveBackgroundColor: ColorValue | undefined;
511
+ tabBarLabelVisibilityMode: TabBarItemLabelVisibilityMode | undefined;
512
+ };
513
+
514
+ const BottomTabBarItem = React.memo(function BottomTabBarItem({
515
+ route,
516
+ descriptor,
517
+ navigation,
518
+ navigatorKey,
519
+ href,
520
+ focused,
521
+ label,
522
+ accessibilityLabel,
523
+ hasHorizontalLabels,
524
+ compact,
525
+ sidebar,
526
+ tabBarVariant,
527
+ spacing,
528
+ tabBarActiveTintColor,
529
+ tabBarInactiveTintColor,
530
+ tabBarActiveBackgroundColor,
531
+ tabBarInactiveBackgroundColor,
532
+ tabBarLabelVisibilityMode,
533
+ }: BottomTabBarItemProps) {
534
+ const { options } = descriptor;
535
+
536
+ const onPress = () => {
537
+ const isRepeatedPress = focused && options.tabBarSelectionEnabled !== false;
538
+
539
+ const event = navigation.emit({
540
+ type: 'tabPress',
541
+ target: route.key,
542
+ canPreventDefault: true,
543
+ data: {
544
+ behavior: {
545
+ scrollToTop:
546
+ isRepeatedPress &&
547
+ options.tabBarRepeatedPressBehavior?.scrollToTop !== false,
548
+ popToTop:
549
+ isRepeatedPress &&
550
+ options.tabBarRepeatedPressBehavior?.popToTop !== false,
551
+ },
552
+ },
553
+ });
554
+
555
+ if (
556
+ !focused &&
557
+ !event.defaultPrevented &&
558
+ options.tabBarSelectionEnabled !== false
559
+ ) {
560
+ React.startTransition(() => {
561
+ navigation.dispatch({
562
+ ...CommonActions.navigate(route.name, route.params),
563
+ target: navigatorKey,
564
+ });
565
+ });
566
+ }
567
+ };
568
+
569
+ const onLongPress = () => {
570
+ navigation.emit({
571
+ type: 'tabLongPress',
572
+ target: route.key,
573
+ });
574
+ };
575
+
576
+ return (
577
+ <NavigationProvider navigation={descriptor.navigation} route={route}>
578
+ <BottomTabItem
579
+ href={href}
580
+ route={route}
581
+ descriptor={descriptor}
582
+ focused={focused}
583
+ horizontal={hasHorizontalLabels}
584
+ compact={compact}
585
+ sidebar={sidebar}
586
+ variant={tabBarVariant}
587
+ onPress={onPress}
588
+ onLongPress={onLongPress}
589
+ accessibilityLabel={accessibilityLabel}
590
+ testID={options.tabBarButtonTestID}
591
+ allowFontScaling={options.tabBarAllowFontScaling}
592
+ activeTintColor={tabBarActiveTintColor}
593
+ inactiveTintColor={tabBarInactiveTintColor}
594
+ activeBackgroundColor={tabBarActiveBackgroundColor}
595
+ inactiveBackgroundColor={tabBarInactiveBackgroundColor}
596
+ rippleColor={options.tabBarRippleColor}
597
+ button={options.tabBarButton}
598
+ icon={options.tabBarIcon}
599
+ badge={options.tabBarBadge}
600
+ badgeStyle={options.tabBarBadgeStyle}
601
+ label={label}
602
+ labelVisibilityMode={tabBarLabelVisibilityMode}
603
+ labelStyle={options.tabBarLabelStyle}
604
+ iconSize={options.tabBarIconSize}
605
+ iconStyle={options.tabBarIconStyle}
606
+ style={[
607
+ sidebar
608
+ ? {
609
+ marginVertical: hasHorizontalLabels
610
+ ? tabBarVariant === 'material'
611
+ ? 0
612
+ : 1
613
+ : spacing / 2,
614
+ }
615
+ : styles.bottomItem,
616
+ options.tabBarItemStyle,
617
+ ]}
618
+ />
619
+ </NavigationProvider>
620
+ );
621
+ });
622
+
552
623
  const styles = StyleSheet.create({
553
624
  start: {
554
625
  top: 0,
@@ -135,6 +135,10 @@ type Props = {
135
135
  * Style object for the label element.
136
136
  */
137
137
  labelStyle?: StyleProp<TextStyle> | undefined;
138
+ /**
139
+ * Size of the icon.
140
+ */
141
+ iconSize?: number | undefined;
138
142
  /**
139
143
  * Style object for the icon element.
140
144
  */
@@ -181,6 +185,7 @@ export function BottomTabItem({
181
185
  // https://developer.apple.com/documentation/uikit/uiview/3183939-largecontenttitle
182
186
  allowFontScaling = SUPPORTS_LARGE_CONTENT_VIEWER ? false : undefined,
183
187
  labelStyle,
188
+ iconSize,
184
189
  iconStyle,
185
190
  style,
186
191
  }: Props) {
@@ -290,6 +295,7 @@ export function BottomTabItem({
290
295
  route={route}
291
296
  variant={variant}
292
297
  size={compact ? 'compact' : 'regular'}
298
+ iconSize={iconSize}
293
299
  badge={badge}
294
300
  badgeStyle={badgeStyle}
295
301
  activeOpacity={activeOpacity}
@@ -4,6 +4,7 @@ import {
4
4
  SafeAreaProviderCompat,
5
5
  } from '@react-navigation/elements/internal';
6
6
  import {
7
+ type NavigationRoute,
7
8
  type ParamListBase,
8
9
  StackActions,
9
10
  type TabNavigationState,
@@ -23,6 +24,7 @@ import {
23
24
  } from '../TransitionConfigs/TransitionPresets';
24
25
  import type {
25
26
  BottomTabBarProps,
27
+ BottomTabDescriptor,
26
28
  BottomTabDescriptorMap,
27
29
  BottomTabNavigationConfig,
28
30
  BottomTabNavigationHelpers,
@@ -275,21 +277,12 @@ export function BottomTabViewCustom({
275
277
  );
276
278
  }
277
279
 
278
- const { navigation, options, render } = descriptor;
279
-
280
- const {
281
- lazy = true,
282
- inactiveBehavior = 'pause',
283
- animation = 'none',
284
- sceneStyleInterpolator = NAMED_TRANSITIONS_PRESETS[animation]
285
- .sceneStyleInterpolator,
286
- sceneStyle: customSceneStyle,
287
- } = options;
280
+ const { lazy = true, inactiveBehavior = 'pause' } =
281
+ descriptor.options;
288
282
 
289
283
  const isFocused = state.index === index;
290
284
  const isPreloaded = state.preloadedRouteKeys.includes(route.key);
291
285
 
292
- const animationEnabled = hasAnimation(descriptor.options);
293
286
  const tabAnimation = tabAnims[route.key];
294
287
 
295
288
  if (tabAnimation == null) {
@@ -298,29 +291,6 @@ export function BottomTabViewCustom({
298
291
  );
299
292
  }
300
293
 
301
- const content = (
302
- <AnimatedScreenContent
303
- key={route.key}
304
- progress={tabAnimation}
305
- animationEnabled={animationEnabled}
306
- sceneStyleInterpolator={sceneStyleInterpolator}
307
- style={[StyleSheet.absoluteFill, customSceneStyle]}
308
- >
309
- <ScreenContent
310
- isFocused={isFocused}
311
- route={route}
312
- navigation={navigation}
313
- options={options}
314
- >
315
- <BottomTabBarHeightContext.Provider
316
- value={tabBarPosition === 'bottom' ? tabBarHeight : 0}
317
- >
318
- {render()}
319
- </BottomTabBarHeightContext.Provider>
320
- </ScreenContent>
321
- </AnimatedScreenContent>
322
- );
323
-
324
294
  const isAnimatingRoute =
325
295
  lastUpdate.animating &&
326
296
  (lastUpdate.previous === route.key ||
@@ -335,22 +305,18 @@ export function BottomTabViewCustom({
335
305
  (lazy === false && !loaded.includes(route.key));
336
306
 
337
307
  return (
338
- <Deferred
308
+ <TabScene
339
309
  key={route.key}
310
+ route={route}
311
+ descriptor={descriptor}
340
312
  lazy={lazy}
341
313
  visible={isFocused || isPreloaded || loaded.includes(route.key)}
342
- >
343
- <ActivityView
344
- mode={isFocused ? 'normal' : isActive ? 'inert' : 'paused'}
345
- visible={isFocused || isAnimatingRoute}
346
- style={{
347
- ...StyleSheet.absoluteFill,
348
- zIndex: isFocused ? 0 : -1,
349
- }}
350
- >
351
- {content}
352
- </ActivityView>
353
- </Deferred>
314
+ isFocused={isFocused}
315
+ isActive={isActive}
316
+ isAnimatingRoute={isAnimatingRoute}
317
+ tabAnimation={tabAnimation}
318
+ tabBarHeight={tabBarPosition === 'bottom' ? tabBarHeight : 0}
319
+ />
354
320
  );
355
321
  })}
356
322
  </Container>
@@ -361,6 +327,77 @@ export function BottomTabViewCustom({
361
327
  );
362
328
  }
363
329
 
330
+ type TabSceneProps = {
331
+ route: NavigationRoute<ParamListBase, string>;
332
+ descriptor: BottomTabDescriptor;
333
+ lazy: boolean;
334
+ visible: boolean;
335
+ isFocused: boolean;
336
+ isActive: boolean;
337
+ isAnimatingRoute: boolean;
338
+ tabAnimation: Animated.Value;
339
+ tabBarHeight: number;
340
+ };
341
+
342
+ const TabScene = React.memo(function TabScene({
343
+ route,
344
+ descriptor,
345
+ lazy,
346
+ visible,
347
+ isFocused,
348
+ isActive,
349
+ isAnimatingRoute,
350
+ tabAnimation,
351
+ tabBarHeight,
352
+ }: TabSceneProps) {
353
+ const { navigation, options, render } = descriptor;
354
+
355
+ const {
356
+ animation = 'none',
357
+ sceneStyleInterpolator = NAMED_TRANSITIONS_PRESETS[animation]
358
+ .sceneStyleInterpolator,
359
+ sceneStyle: customSceneStyle,
360
+ } = options;
361
+
362
+ const animationEnabled = hasAnimation(descriptor.options);
363
+
364
+ const content = (
365
+ <AnimatedScreenContent
366
+ key={route.key}
367
+ progress={tabAnimation}
368
+ animationEnabled={animationEnabled}
369
+ sceneStyleInterpolator={sceneStyleInterpolator}
370
+ style={[StyleSheet.absoluteFill, customSceneStyle]}
371
+ >
372
+ <ScreenContent
373
+ isFocused={isFocused}
374
+ route={route}
375
+ navigation={navigation}
376
+ options={options}
377
+ >
378
+ <BottomTabBarHeightContext.Provider value={tabBarHeight}>
379
+ {render()}
380
+ </BottomTabBarHeightContext.Provider>
381
+ </ScreenContent>
382
+ </AnimatedScreenContent>
383
+ );
384
+
385
+ return (
386
+ <Deferred lazy={lazy} visible={visible}>
387
+ <ActivityView
388
+ mode={isFocused ? 'normal' : isActive ? 'inert' : 'paused'}
389
+ visible={isFocused || isAnimatingRoute}
390
+ style={{
391
+ ...StyleSheet.absoluteFill,
392
+ zIndex: isFocused ? 0 : -1,
393
+ }}
394
+ >
395
+ {content}
396
+ </ActivityView>
397
+ </Deferred>
398
+ );
399
+ });
400
+
364
401
  function AnimatedScreenContent({
365
402
  progress,
366
403
  animationEnabled,