// Like from Expo Router but with stored tab history.
import { CommonActions } from '@react-navigation/native'
import { TabRouter } from '@react-navigation/routers'
import { Link, Navigator } from 'expo-router'
import { Screen as RouterScreen } from 'expo-router/build/views/Screen'
import * as React from 'react'
import { GestureResponderEvent, StyleSheet, ViewStyle } from 'react-native'
import { Screen, ScreenContainer } from 'react-native-screens'
import { useContextRoute, useLinkBuilder, useNavigatorContext } from './hooks'
export function TabbedNavigator(props: React.ComponentProps) {
return
}
export default function TabbedSlot({
detachInactiveScreens = true,
style,
}: {
detachInactiveScreens?: boolean
style?: ViewStyle
}) {
const { state, descriptors } = useNavigatorContext()
const focusedRouteKey = state.routes[state.index].key
const [loaded, setLoaded] = React.useState([focusedRouteKey])
if (!loaded.includes(focusedRouteKey)) {
setLoaded([...loaded, focusedRouteKey])
}
const { routes } = state
return (
{routes.map((route, index) => {
const descriptor = descriptors[route.key]
const {
freezeOnBlur,
lazy = true,
unmountOnBlur,
} = descriptor.options as unknown as {
lazy: boolean
unmountOnBlur?: boolean
freezeOnBlur: boolean
}
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 zIndex = { zIndex: isFocused ? 0 : -1 }
return (
{descriptor.render()}
)
})}
)
}
export function TabLink({
name,
params,
...props
}: { name: string; params?: Record } & Omit<
React.ComponentProps,
'href' | 'onPress' | 'onLongPress'
>) {
const buildLink = useLinkBuilder()
const ctxRoute = useContextRoute(name)
if (!ctxRoute) {
return null
}
const { route, target, navigation } = ctxRoute
const onPress = (
e: GestureResponderEvent | React.MouseEvent
) => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
})
// @ts-expect-error: event type does not contain defaultPrevented, which should be available here on web
if (!event.defaultPrevented) {
e.preventDefault()
navigation.dispatch({
...CommonActions.navigate({ name: route.name, merge: true, params }),
target,
})
}
}
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
})
}
return
}
TabbedNavigator.Slot = TabbedSlot
TabbedNavigator.Link = TabLink
TabbedNavigator.Screen = RouterScreen
const styles = StyleSheet.create({
container: {
flex: 1,
overflow: 'hidden',
},
screen: {
...StyleSheet.absoluteFillObject,
overflow: 'hidden',
},
})