import { getHeaderTitle, Header, SafeAreaProviderCompat, Screen, } from '@react-navigation/elements'; import type { ParamListBase, TabNavigationState, } from '@react-navigation/native'; import * as React from 'react'; import { Platform, StyleSheet } from 'react-native'; import { SafeAreaInsetsContext } from 'react-native-safe-area-context'; import type { BottomTabBarProps, BottomTabDescriptorMap, BottomTabHeaderProps, BottomTabNavigationConfig, BottomTabNavigationHelpers, BottomTabNavigationProp, } from '../types'; import BottomTabBarHeightCallbackContext from '../utils/BottomTabBarHeightCallbackContext'; import BottomTabBarHeightContext from '../utils/BottomTabBarHeightContext'; import RenderWithPositionConfig from '../utils/RenderWithSidebarConfig'; import BottomTabBar, { getTabBarHeight } from './BottomTabBar'; import { MaybeScreen, MaybeScreenContainer } from './ScreenFallback'; type Props = BottomTabNavigationConfig & { state: TabNavigationState; navigation: BottomTabNavigationHelpers; descriptors: BottomTabDescriptorMap; }; export default function BottomTabView(props: Props) { const { tabBar = (props: BottomTabBarProps) => , state, navigation, descriptors, safeAreaInsets, detachInactiveScreens = Platform.OS === 'web' || Platform.OS === 'android' || Platform.OS === 'ios', sceneContainerStyle, } = props; const focusedRouteKey = state.routes[state.index].key; const [loaded, setLoaded] = React.useState([focusedRouteKey]); if (!loaded.includes(focusedRouteKey)) { setLoaded([...loaded, focusedRouteKey]); } const dimensions = SafeAreaProviderCompat.initialMetrics.frame; const [tabBarHeight, setTabBarHeight] = React.useState(() => getTabBarHeight({ state, descriptors, dimensions, layout: { width: dimensions.width, height: 0 }, insets: { ...SafeAreaProviderCompat.initialMetrics.insets, ...props.safeAreaInsets, }, style: descriptors[state.routes[state.index].key].options.tabBarStyle, }) ); const renderTabBar = () => { return ( {(insets) => tabBar({ state: state, descriptors: descriptors, navigation: navigation, insets: { top: safeAreaInsets?.top ?? insets?.top ?? 0, right: safeAreaInsets?.right ?? insets?.right ?? 0, bottom: safeAreaInsets?.bottom ?? insets?.bottom ?? 0, left: safeAreaInsets?.left ?? insets?.left ?? 0, }, }) } ); }; const { routes } = state; return ( {routes.map((route, index) => { const descriptor = descriptors[route.key]; const { lazy = true, unmountOnBlur } = descriptor.options; const isFocused = state.index === index; if (unmountOnBlur && !isFocused) { return null; } if (lazy && !loaded.includes(route.key) && !isFocused) { // Don't render a lazy screen if we've never navigated to it return null; } const { header = ({ layout, options }: BottomTabHeaderProps) => (
), } = descriptor.options; return ( , options: descriptor.options, })} style={sceneContainerStyle} > {descriptor.render()} ); })} ); } const styles = StyleSheet.create({ container: { flex: 1, overflow: 'hidden', }, });