Revert "Update react-navigation (#5967)"

This reverts commit f938963462.
This commit is contained in:
Hailey
2025-07-07 15:56:59 -07:00
parent 34291131b4
commit 86a01f18d5
11 changed files with 256 additions and 284 deletions
+5 -5
View File
@@ -94,10 +94,10 @@
"@react-native-async-storage/async-storage": "2.1.2", "@react-native-async-storage/async-storage": "2.1.2",
"@react-native-menu/menu": "^1.2.3", "@react-native-menu/menu": "^1.2.3",
"@react-native-picker/picker": "2.11.0", "@react-native-picker/picker": "2.11.0",
"@react-navigation/bottom-tabs": "^7.3.13", "@react-navigation/bottom-tabs": "^6.5.20",
"@react-navigation/drawer": "^7.3.12", "@react-navigation/drawer": "^6.6.15",
"@react-navigation/native": "^7.1.9", "@react-navigation/native": "^6.1.17",
"@react-navigation/native-stack": "^7.3.13", "@react-navigation/native-stack": "^6.9.26",
"@sentry/react-native": "~6.14.0", "@sentry/react-native": "~6.14.0",
"@tanstack/query-async-storage-persister": "^5.25.0", "@tanstack/query-async-storage-persister": "^5.25.0",
"@tanstack/react-query": "^5.8.1", "@tanstack/react-query": "^5.8.1",
@@ -198,7 +198,7 @@
"react-native-reanimated": "~3.17.5", "react-native-reanimated": "~3.17.5",
"react-native-root-siblings": "^5.0.1", "react-native-root-siblings": "^5.0.1",
"react-native-safe-area-context": "5.4.0", "react-native-safe-area-context": "5.4.0",
"react-native-screens": "^4.11.1", "react-native-screens": "~4.10.0",
"react-native-svg": "15.12.0", "react-native-svg": "15.12.0",
"react-native-uitextview": "^1.4.0", "react-native-uitextview": "^1.4.0",
"react-native-url-polyfill": "^1.3.0", "react-native-url-polyfill": "^1.3.0",
+62 -42
View File
@@ -103,7 +103,7 @@ import {
import {Wizard} from '#/screens/StarterPack/Wizard' import {Wizard} from '#/screens/StarterPack/Wizard'
import TopicScreen from '#/screens/Topic' import TopicScreen from '#/screens/Topic'
import {VideoFeed} from '#/screens/VideoFeed' import {VideoFeed} from '#/screens/VideoFeed'
import {type Theme, useTheme} from '#/alf' import {useTheme} from '#/alf'
import { import {
EmailDialogScreenID, EmailDialogScreenID,
useEmailDialogControl, useEmailDialogControl,
@@ -140,7 +140,7 @@ const Tab = createBottomTabNavigator<BottomTabNavigatorParams>()
/** /**
* These "common screens" are reused across stacks. * These "common screens" are reused across stacks.
*/ */
function commonScreens(Stack: typeof Flat, unreadCountLabel?: string) { function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
const title = (page: MessageDescriptor) => const title = (page: MessageDescriptor) =>
bskyTitle(i18n._(page), unreadCountLabel) bskyTitle(i18n._(page), unreadCountLabel)
@@ -610,10 +610,6 @@ function TabsNavigator() {
tabBar={tabBar}> tabBar={tabBar}>
<Tab.Screen name="HomeTab" getComponent={() => HomeTabNavigator} /> <Tab.Screen name="HomeTab" getComponent={() => HomeTabNavigator} />
<Tab.Screen name="SearchTab" getComponent={() => SearchTabNavigator} /> <Tab.Screen name="SearchTab" getComponent={() => SearchTabNavigator} />
<Tab.Screen
name="MessagesTab"
getComponent={() => MessagesTabNavigator}
/>
<Tab.Screen <Tab.Screen
name="NotificationsTab" name="NotificationsTab"
getComponent={() => NotificationsTabNavigator} getComponent={() => NotificationsTabNavigator}
@@ -622,26 +618,29 @@ function TabsNavigator() {
name="MyProfileTab" name="MyProfileTab"
getComponent={() => MyProfileTabNavigator} getComponent={() => MyProfileTabNavigator}
/> />
<Tab.Screen
name="MessagesTab"
getComponent={() => MessagesTabNavigator}
/>
</Tab.Navigator> </Tab.Navigator>
) )
} }
function screenOptions(t: Theme) {
return {
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: t.atoms.bg,
} as const
}
function HomeTabNavigator() { function HomeTabNavigator() {
const t = useTheme() const t = useTheme()
return ( return (
<HomeTab.Navigator screenOptions={screenOptions(t)} initialRouteName="Home"> <HomeTab.Navigator
screenOptions={{
animationDuration: 285,
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: t.atoms.bg,
}}>
<HomeTab.Screen name="Home" getComponent={() => HomeScreen} /> <HomeTab.Screen name="Home" getComponent={() => HomeScreen} />
<HomeTab.Screen name="Start" getComponent={() => HomeScreen} /> <HomeTab.Screen name="Start" getComponent={() => HomeScreen} />
{commonScreens(HomeTab as typeof Flat)} {commonScreens(HomeTab)}
</HomeTab.Navigator> </HomeTab.Navigator>
) )
} }
@@ -650,10 +649,15 @@ function SearchTabNavigator() {
const t = useTheme() const t = useTheme()
return ( return (
<SearchTab.Navigator <SearchTab.Navigator
screenOptions={screenOptions(t)} screenOptions={{
initialRouteName="Search"> animationDuration: 285,
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: t.atoms.bg,
}}>
<SearchTab.Screen name="Search" getComponent={() => SearchScreen} /> <SearchTab.Screen name="Search" getComponent={() => SearchScreen} />
{commonScreens(SearchTab as typeof Flat)} {commonScreens(SearchTab as typeof HomeTab)}
</SearchTab.Navigator> </SearchTab.Navigator>
) )
} }
@@ -662,14 +666,19 @@ function NotificationsTabNavigator() {
const t = useTheme() const t = useTheme()
return ( return (
<NotificationsTab.Navigator <NotificationsTab.Navigator
screenOptions={screenOptions(t)} screenOptions={{
initialRouteName="Notifications"> animationDuration: 285,
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: t.atoms.bg,
}}>
<NotificationsTab.Screen <NotificationsTab.Screen
name="Notifications" name="Notifications"
getComponent={() => NotificationsScreen} getComponent={() => NotificationsScreen}
options={{requireAuth: true}} options={{requireAuth: true}}
/> />
{commonScreens(NotificationsTab as typeof Flat)} {commonScreens(NotificationsTab as typeof HomeTab)}
</NotificationsTab.Navigator> </NotificationsTab.Navigator>
) )
} }
@@ -678,16 +687,23 @@ function MyProfileTabNavigator() {
const t = useTheme() const t = useTheme()
return ( return (
<MyProfileTab.Navigator <MyProfileTab.Navigator
screenOptions={screenOptions(t)} screenOptions={{
initialRouteName="MyProfile"> animationDuration: 285,
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: t.atoms.bg,
}}>
<MyProfileTab.Screen <MyProfileTab.Screen
// MyProfile is not in AllNavigationParams - asserting as Profile at least // @ts-ignore // TODO: fix this broken type in ProfileScreen
// gives us typechecking for initialParams -sfn name="MyProfile"
name={'MyProfile' as 'Profile'}
getComponent={() => ProfileScreen} getComponent={() => ProfileScreen}
initialParams={{name: 'me', hideBackButton: true}} initialParams={{
name: 'me',
hideBackButton: true,
}}
/> />
{commonScreens(MyProfileTab as unknown as typeof Flat)} {commonScreens(MyProfileTab as typeof HomeTab)}
</MyProfileTab.Navigator> </MyProfileTab.Navigator>
) )
} }
@@ -696,8 +712,13 @@ function MessagesTabNavigator() {
const t = useTheme() const t = useTheme()
return ( return (
<MessagesTab.Navigator <MessagesTab.Navigator
screenOptions={screenOptions(t)} screenOptions={{
initialRouteName="Messages"> animationDuration: 285,
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: t.atoms.bg,
}}>
<MessagesTab.Screen <MessagesTab.Screen
name="Messages" name="Messages"
getComponent={() => MessagesScreen} getComponent={() => MessagesScreen}
@@ -706,7 +727,7 @@ function MessagesTabNavigator() {
animationTypeForReplace: route.params?.animation ?? 'push', animationTypeForReplace: route.params?.animation ?? 'push',
})} })}
/> />
{commonScreens(MessagesTab as typeof Flat)} {commonScreens(MessagesTab as typeof HomeTab)}
</MessagesTab.Navigator> </MessagesTab.Navigator>
) )
} }
@@ -724,7 +745,13 @@ const FlatNavigator = () => {
return ( return (
<Flat.Navigator <Flat.Navigator
screenListeners={screenListeners} screenListeners={screenListeners}
screenOptions={screenOptions(t)}> screenOptions={{
animationDuration: 285,
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: t.atoms.bg,
}}>
<Flat.Screen <Flat.Screen
name="Home" name="Home"
getComponent={() => HomeScreen} getComponent={() => HomeScreen}
@@ -750,7 +777,7 @@ const FlatNavigator = () => {
getComponent={() => HomeScreen} getComponent={() => HomeScreen}
options={{title: title(msg`Home`)}} options={{title: title(msg`Home`)}}
/> />
{commonScreens(Flat, numUnread)} {commonScreens(Flat as typeof HomeTab, numUnread)}
</Flat.Navigator> </Flat.Navigator>
) )
} }
@@ -857,14 +884,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
logModuleInitTime() logModuleInitTime()
onReady() onReady()
logger.metric('router:navigate', {}, {statsig: false}) logger.metric('router:navigate', {}, {statsig: false})
}} }}>
// WARNING: Implicit navigation to nested navigators is depreciated in React Navigation 7.x
// However, there's a fair amount of places we do that, especially in when popping to the top of stacks.
// See BottomBar.tsx for an example of how to handle nested navigators in the tabs correctly.
// I'm scared of missing a spot (esp. with push notifications etc) so let's enable this legacy behaviour for now.
// We will need to confirm we handle nested navigators correctly by the time we migrate to React Navigation 8.x
// -sfn
navigationInChildEnabled>
{children} {children}
</NavigationContainer> </NavigationContainer>
</> </>
+10 -24
View File
@@ -1,10 +1,7 @@
import React, {useMemo} from 'react' import React from 'react'
import {type GestureResponderEvent} from 'react-native' import {type GestureResponderEvent} from 'react-native'
import {sanitizeUrl} from '@braintree/sanitize-url' import {sanitizeUrl} from '@braintree/sanitize-url'
import { import {StackActions, useLinkProps} from '@react-navigation/native'
type LinkProps as RNLinkProps,
StackActions,
} from '@react-navigation/native'
import {BSKY_DOWNLOAD_URL} from '#/lib/constants' import {BSKY_DOWNLOAD_URL} from '#/lib/constants'
import {useNavigationDeduped} from '#/lib/hooks/useNavigationDeduped' import {useNavigationDeduped} from '#/lib/hooks/useNavigationDeduped'
@@ -32,11 +29,12 @@ import {useGlobalDialogsControlContext} from './dialogs/Context'
*/ */
export {useButtonContext as useLinkContext} from '#/components/Button' export {useButtonContext as useLinkContext} from '#/components/Button'
type BaseLinkProps = { type BaseLinkProps = Pick<
Parameters<typeof useLinkProps<AllNavigatorParams>>[0],
'to'
> & {
testID?: string testID?: string
to: RNLinkProps<AllNavigatorParams> | string
/** /**
* The React Navigation `StackAction` to perform when the link is pressed. * The React Navigation `StackAction` to perform when the link is pressed.
*/ */
@@ -95,22 +93,10 @@ export function useLink({
shouldProxy?: boolean shouldProxy?: boolean
}) { }) {
const navigation = useNavigationDeduped() const navigation = useNavigationDeduped()
const href = useMemo(() => { const {href} = useLinkProps<AllNavigatorParams>({
return typeof to === 'string' to:
? convertBskyAppUrlIfNeeded(sanitizeUrl(to)) typeof to === 'string' ? convertBskyAppUrlIfNeeded(sanitizeUrl(to)) : to,
: to.screen })
? router.matchName(to.screen)?.build(to.params)
: to.href
? convertBskyAppUrlIfNeeded(sanitizeUrl(to.href))
: undefined
}, [to])
if (!href) {
throw new Error(
'Could not resolve screen. Link `to` prop must be a string or an object with `screen` and `params` properties',
)
}
const isExternal = isExternalUrl(href) const isExternal = isExternalUrl(href)
const {closeModal} = useModalControls() const {closeModal} = useModalControls()
const {linkWarningDialogControl} = useGlobalDialogsControlContext() const {linkWarningDialogControl} = useGlobalDialogsControlContext()
+38 -9
View File
@@ -1,8 +1,10 @@
import {useMemo} from 'react' import React from 'react'
import {useNavigation} from '@react-navigation/core' import {useNavigation} from '@react-navigation/core'
import {type NavigationState} from '@react-navigation/native'
import {type NavigationAction} from '@react-navigation/routers'
import {useDedupe} from '#/lib/hooks/useDedupe' import {useDedupe} from '#/lib/hooks/useDedupe'
import {type NavigationProp} from '#/lib/routes/types' import {type AllNavigatorParams, type NavigationProp} from '#/lib/routes/types'
export type DebouncedNavigationProp = Pick< export type DebouncedNavigationProp = Pick<
NavigationProp, NavigationProp,
@@ -21,19 +23,46 @@ export function useNavigationDeduped() {
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
const dedupe = useDedupe() const dedupe = useDedupe()
return useMemo<DebouncedNavigationProp>( return React.useMemo(
() => ({ (): DebouncedNavigationProp => ({
push: (...args: Parameters<typeof navigation.push>) => { // Types from @react-navigation/routers/lib/typescript/src/StackRouter.ts
push: <RouteName extends keyof AllNavigatorParams>(
...args: undefined extends AllNavigatorParams[RouteName]
?
| [screen: RouteName]
| [screen: RouteName, params: AllNavigatorParams[RouteName]]
: [screen: RouteName, params: AllNavigatorParams[RouteName]]
) => {
dedupe(() => navigation.push(...args)) dedupe(() => navigation.push(...args))
}, },
navigate: (...args: Parameters<typeof navigation.navigate>) => { // Types from @react-navigation/core/src/types.tsx
navigate: <RouteName extends keyof AllNavigatorParams>(
...args: RouteName extends unknown
? undefined extends AllNavigatorParams[RouteName]
?
| [screen: RouteName]
| [screen: RouteName, params: AllNavigatorParams[RouteName]]
: [screen: RouteName, params: AllNavigatorParams[RouteName]]
: never
) => {
dedupe(() => navigation.navigate(...args)) dedupe(() => navigation.navigate(...args))
}, },
replace: (...args: Parameters<typeof navigation.replace>) => { // Types from @react-navigation/routers/lib/typescript/src/StackRouter.ts
replace: <RouteName extends keyof AllNavigatorParams>(
...args: undefined extends AllNavigatorParams[RouteName]
?
| [screen: RouteName]
| [screen: RouteName, params: AllNavigatorParams[RouteName]]
: [screen: RouteName, params: AllNavigatorParams[RouteName]]
) => {
dedupe(() => navigation.replace(...args)) dedupe(() => navigation.replace(...args))
}, },
dispatch: (...args: Parameters<typeof navigation.dispatch>) => { dispatch: (
dedupe(() => navigation.dispatch(...args)) action:
| NavigationAction
| ((state: NavigationState) => NavigationAction),
) => {
dedupe(() => navigation.dispatch(action))
}, },
popToTop: () => { popToTop: () => {
dedupe(() => navigation.popToTop()) dedupe(() => navigation.popToTop())
+1 -1
View File
@@ -105,7 +105,7 @@ export type NotificationsTabNavigatorParams = CommonNavigatorParams & {
} }
export type MyProfileTabNavigatorParams = CommonNavigatorParams & { export type MyProfileTabNavigatorParams = CommonNavigatorParams & {
MyProfile: {name: 'me'; hideBackButton: true} MyProfile: undefined
} }
export type MessagesTabNavigatorParams = CommonNavigatorParams & { export type MessagesTabNavigatorParams = CommonNavigatorParams & {
+31 -36
View File
@@ -1,4 +1,4 @@
import {memo, useCallback, useMemo} from 'react' import React, {type ComponentProps, memo, useMemo} from 'react'
import { import {
type GestureResponderEvent, type GestureResponderEvent,
Platform, Platform,
@@ -11,7 +11,7 @@ import {
type ViewStyle, type ViewStyle,
} from 'react-native' } from 'react-native'
import {sanitizeUrl} from '@braintree/sanitize-url' import {sanitizeUrl} from '@braintree/sanitize-url'
import {StackActions} from '@react-navigation/native' import {StackActions, useLinkProps} from '@react-navigation/native'
import { import {
type DebouncedNavigationProp, type DebouncedNavigationProp,
@@ -39,7 +39,7 @@ type Event =
| React.MouseEvent<HTMLAnchorElement, MouseEvent> | React.MouseEvent<HTMLAnchorElement, MouseEvent>
| GestureResponderEvent | GestureResponderEvent
interface Props extends React.ComponentProps<typeof TouchableOpacity> { interface Props extends ComponentProps<typeof TouchableOpacity> {
testID?: string testID?: string
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
href?: string href?: string
@@ -48,7 +48,7 @@ interface Props extends React.ComponentProps<typeof TouchableOpacity> {
hoverStyle?: StyleProp<ViewStyle> hoverStyle?: StyleProp<ViewStyle>
noFeedback?: boolean noFeedback?: boolean
asAnchor?: boolean asAnchor?: boolean
dataSet?: any dataSet?: Object | undefined
anchorNoUnderline?: boolean anchorNoUnderline?: boolean
navigationAction?: 'push' | 'replace' | 'navigate' navigationAction?: 'push' | 'replace' | 'navigate'
onPointerEnter?: () => void onPointerEnter?: () => void
@@ -70,7 +70,6 @@ export const Link = memo(function Link({
onBeforePress, onBeforePress,
accessibilityActions, accessibilityActions,
onAccessibilityAction, onAccessibilityAction,
dataSet: dataSetProp,
...props ...props
}: Props) { }: Props) {
const t = useTheme() const t = useTheme()
@@ -79,7 +78,7 @@ export const Link = memo(function Link({
const anchorHref = asAnchor ? sanitizeUrl(href) : undefined const anchorHref = asAnchor ? sanitizeUrl(href) : undefined
const openLink = useOpenLink() const openLink = useOpenLink()
const onPress = useCallback( const onPress = React.useCallback(
(e?: Event) => { (e?: Event) => {
onBeforePress?.() onBeforePress?.()
if (typeof href === 'string') { if (typeof href === 'string') {
@@ -101,14 +100,6 @@ export const Link = memo(function Link({
{name: 'activate', label: title}, {name: 'activate', label: title},
] ]
const dataSet = useMemo(() => {
const ds = {...dataSetProp}
if (anchorNoUnderline) {
ds.noUnderline = 1
}
return ds
}, [dataSetProp, anchorNoUnderline])
if (noFeedback) { if (noFeedback) {
return ( return (
<WebAuxClickWrapper> <WebAuxClickWrapper>
@@ -139,6 +130,17 @@ export const Link = memo(function Link({
) )
} }
if (anchorNoUnderline) {
// @ts-ignore web only -prf
props.dataSet = props.dataSet || {}
// @ts-ignore web only -prf
props.dataSet.noUnderline = 1
}
if (title && !props.accessibilityLabel) {
props.accessibilityLabel = title
}
const Com = props.hoverStyle ? PressableWithHover : Pressable const Com = props.hoverStyle ? PressableWithHover : Pressable
return ( return (
<Com <Com
@@ -147,11 +149,8 @@ export const Link = memo(function Link({
onPress={onPress} onPress={onPress}
accessible={accessible} accessible={accessible}
accessibilityRole="link" accessibilityRole="link"
accessibilityLabel={props.accessibilityLabel ?? title}
accessibilityHint={props.accessibilityHint}
// @ts-ignore web only -prf // @ts-ignore web only -prf
href={anchorHref} href={anchorHref}
dataSet={dataSet}
{...props}> {...props}>
{children ? children : <Text>{title || 'link'}</Text>} {children ? children : <Text>{title || 'link'}</Text>}
</Com> </Com>
@@ -166,14 +165,14 @@ export const TextLink = memo(function TextLink({
text, text,
numberOfLines, numberOfLines,
lineHeight, lineHeight,
dataSet: dataSetProp, dataSet,
title, title,
onPress: onPressProp, onPress,
onBeforePress, onBeforePress,
disableMismatchWarning, disableMismatchWarning,
navigationAction, navigationAction,
anchorNoUnderline, anchorNoUnderline,
...props ...orgProps
}: { }: {
testID?: string testID?: string
type?: TypographyVariant type?: TypographyVariant
@@ -189,6 +188,7 @@ export const TextLink = memo(function TextLink({
anchorNoUnderline?: boolean anchorNoUnderline?: boolean
onBeforePress?: () => void onBeforePress?: () => void
} & TextProps) { } & TextProps) {
const {...props} = useLinkProps({to: sanitizeUrl(href)})
const navigation = useNavigationDeduped() const navigation = useNavigationDeduped()
const {closeModal} = useModalControls() const {closeModal} = useModalControls()
const {linkWarningDialogControl} = useGlobalDialogsControlContext() const {linkWarningDialogControl} = useGlobalDialogsControlContext()
@@ -198,15 +198,12 @@ export const TextLink = memo(function TextLink({
console.error('Unable to detect mismatching label') console.error('Unable to detect mismatching label')
} }
const dataSet = useMemo(() => { if (anchorNoUnderline) {
const ds = {...dataSetProp} dataSet = dataSet ?? {}
if (anchorNoUnderline) { dataSet.noUnderline = 1
ds.noUnderline = 1 }
}
return ds
}, [dataSetProp, anchorNoUnderline])
const onPress = useCallback( props.onPress = React.useCallback(
(e?: Event) => { (e?: Event) => {
const requiresWarning = const requiresWarning =
!disableMismatchWarning && !disableMismatchWarning &&
@@ -228,10 +225,10 @@ export const TextLink = memo(function TextLink({
return return
} }
onBeforePress?.() onBeforePress?.()
if (onPressProp) { if (onPress) {
e?.preventDefault?.() e?.preventDefault?.()
// @ts-expect-error function signature differs by platform -prf // @ts-ignore function signature differs by platform -prf
return onPressProp() return onPress()
} }
return onPressInner( return onPressInner(
closeModal, closeModal,
@@ -244,7 +241,7 @@ export const TextLink = memo(function TextLink({
}, },
[ [
onBeforePress, onBeforePress,
onPressProp, onPress,
closeModal, closeModal,
navigation, navigation,
href, href,
@@ -277,10 +274,8 @@ export const TextLink = memo(function TextLink({
title={title} title={title}
// @ts-ignore web only -prf // @ts-ignore web only -prf
hrefAttrs={hrefAttrs} // hack to get open in new tab to work on safari. without this, safari will open in a new window hrefAttrs={hrefAttrs} // hack to get open in new tab to work on safari. without this, safari will open in a new window
onPress={onPress} {...props}
accessibilityRole="link" {...orgProps}>
href={convertBskyAppUrlIfNeeded(sanitizeUrl(href))}
{...props}>
{text} {text}
</Text> </Text>
) )
+4 -18
View File
@@ -160,7 +160,7 @@ let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
// = // =
const onPressTab = React.useCallback( const onPressTab = React.useCallback(
(tab: 'Home' | 'Search' | 'Messages' | 'Notifications' | 'MyProfile') => { (tab: string) => {
const state = navigation.getState() const state = navigation.getState()
setDrawerOpen(false) setDrawerOpen(false)
if (isWeb) { if (isWeb) {
@@ -168,7 +168,7 @@ let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
if (tab === 'MyProfile') { if (tab === 'MyProfile') {
navigation.navigate('Profile', {name: currentAccount!.handle}) navigation.navigate('Profile', {name: currentAccount!.handle})
} else { } else {
// @ts-expect-error struggles with string unions, apparently // @ts-ignore must be Home, Search, Notifications, or MyProfile
navigation.navigate(tab) navigation.navigate(tab)
} }
} else { } else {
@@ -176,23 +176,9 @@ let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
if (tabState === TabState.InsideAtRoot) { if (tabState === TabState.InsideAtRoot) {
emitSoftReset() emitSoftReset()
} else if (tabState === TabState.Inside) { } else if (tabState === TabState.Inside) {
// find the correct navigator in which to pop-to-top navigation.dispatch(StackActions.popToTop())
const target = state.routes.find(route => route.name === `${tab}Tab`)
?.state?.key
if (target) {
// if we found it, trigger pop-to-top
navigation.dispatch({
...StackActions.popToTop(),
target,
})
} else {
// fallback: reset navigation
navigation.reset({
index: 0,
routes: [{name: `${tab}Tab`}],
})
}
} else { } else {
// @ts-ignore must be Home, Search, Notifications, or MyProfile
navigation.navigate(`${tab}Tab`) navigation.navigate(`${tab}Tab`)
} }
} }
+22 -30
View File
@@ -1,4 +1,4 @@
import {useCallback} from 'react' import React, {type ComponentProps} from 'react'
import {type GestureResponderEvent, View} from 'react-native' import {type GestureResponderEvent, View} from 'react-native'
import Animated from 'react-native-reanimated' import Animated from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
@@ -53,7 +53,13 @@ import {
import {useDemoMode} from '#/storage/hooks/demo-mode' import {useDemoMode} from '#/storage/hooks/demo-mode'
import {styles} from './BottomBarStyles' import {styles} from './BottomBarStyles'
type TabOptions = 'Home' | 'Search' | 'Messages' | 'Notifications' | 'MyProfile' type TabOptions =
| 'Home'
| 'Search'
| 'Notifications'
| 'MyProfile'
| 'Feeds'
| 'Messages'
export function BottomBar({navigation}: BottomTabBarProps) { export function BottomBar({navigation}: BottomTabBarProps) {
const {hasSession, currentAccount} = useSession() const {hasSession, currentAccount} = useSession()
@@ -77,62 +83,48 @@ export function BottomBar({navigation}: BottomTabBarProps) {
const hideBorder = useHideBottomBarBorder() const hideBorder = useHideBottomBarBorder()
const iconWidth = 28 const iconWidth = 28
const showSignIn = useCallback(() => { const showSignIn = React.useCallback(() => {
closeAllActiveElements() closeAllActiveElements()
requestSwitchToAccount({requestedAccount: 'none'}) requestSwitchToAccount({requestedAccount: 'none'})
}, [requestSwitchToAccount, closeAllActiveElements]) }, [requestSwitchToAccount, closeAllActiveElements])
const showCreateAccount = useCallback(() => { const showCreateAccount = React.useCallback(() => {
closeAllActiveElements() closeAllActiveElements()
requestSwitchToAccount({requestedAccount: 'new'}) requestSwitchToAccount({requestedAccount: 'new'})
// setShowLoggedOut(true) // setShowLoggedOut(true)
}, [requestSwitchToAccount, closeAllActiveElements]) }, [requestSwitchToAccount, closeAllActiveElements])
const onPressTab = useCallback( const onPressTab = React.useCallback(
(tab: TabOptions) => { (tab: TabOptions) => {
const state = navigation.getState() const state = navigation.getState()
const tabState = getTabState(state, tab) const tabState = getTabState(state, tab)
if (tabState === TabState.InsideAtRoot) { if (tabState === TabState.InsideAtRoot) {
emitSoftReset() emitSoftReset()
} else if (tabState === TabState.Inside) { } else if (tabState === TabState.Inside) {
// find the correct navigator in which to pop-to-top dedupe(() => navigation.dispatch(StackActions.popToTop()))
const target = state.routes.find(route => route.name === `${tab}Tab`)
?.state?.key
dedupe(() => {
if (target) {
// if we found it, trigger pop-to-top
navigation.dispatch({
...StackActions.popToTop(),
target,
})
} else {
// fallback: reset navigation
navigation.reset({
index: 0,
routes: [{name: `${tab}Tab`}],
})
}
})
} else { } else {
dedupe(() => navigation.navigate(`${tab}Tab`)) dedupe(() => navigation.navigate(`${tab}Tab`))
} }
}, },
[navigation, dedupe], [navigation, dedupe],
) )
const onPressHome = useCallback(() => onPressTab('Home'), [onPressTab]) const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab])
const onPressSearch = useCallback(() => onPressTab('Search'), [onPressTab]) const onPressSearch = React.useCallback(
const onPressNotifications = useCallback( () => onPressTab('Search'),
[onPressTab],
)
const onPressNotifications = React.useCallback(
() => onPressTab('Notifications'), () => onPressTab('Notifications'),
[onPressTab], [onPressTab],
) )
const onPressProfile = useCallback(() => { const onPressProfile = React.useCallback(() => {
onPressTab('MyProfile') onPressTab('MyProfile')
}, [onPressTab]) }, [onPressTab])
const onPressMessages = useCallback(() => { const onPressMessages = React.useCallback(() => {
onPressTab('Messages') onPressTab('Messages')
}, [onPressTab]) }, [onPressTab])
const onLongPressProfile = useCallback(() => { const onLongPressProfile = React.useCallback(() => {
playHaptic() playHaptic()
accountSwitchControl.open() accountSwitchControl.open()
}, [accountSwitchControl, playHaptic]) }, [accountSwitchControl, playHaptic])
@@ -371,7 +363,7 @@ export function BottomBar({navigation}: BottomTabBarProps) {
interface BtnProps interface BtnProps
extends Pick< extends Pick<
React.ComponentProps<typeof PressableScale>, ComponentProps<typeof PressableScale>,
| 'accessible' | 'accessible'
| 'accessibilityRole' | 'accessibilityRole'
| 'accessibilityHint' | 'accessibilityHint'
@@ -1,29 +1,25 @@
import * as React from 'react' import * as React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
// Based on @react-navigation/native-stack/src/navigators/createNativeStackNavigator.ts // Based on @react-navigation/native-stack/src/createNativeStackNavigator.ts
// MIT License // MIT License
// Copyright (c) 2017 React Navigation Contributors // Copyright (c) 2017 React Navigation Contributors
import { import {
createNavigatorFactory, createNavigatorFactory,
type EventArg, type EventArg,
type NavigatorTypeBagBase,
type ParamListBase, type ParamListBase,
type StackActionHelpers, type StackActionHelpers,
StackActions, StackActions,
type StackNavigationState, type StackNavigationState,
StackRouter, StackRouter,
type StackRouterOptions, type StackRouterOptions,
type StaticConfig,
type TypedNavigator,
useNavigationBuilder, useNavigationBuilder,
} from '@react-navigation/native' } from '@react-navigation/native'
import {NativeStackView} from '@react-navigation/native-stack'
import { import {
type NativeStackNavigationEventMap, type NativeStackNavigationEventMap,
type NativeStackNavigationOptions, type NativeStackNavigationOptions,
type NativeStackNavigationProp,
type NativeStackNavigatorProps,
} from '@react-navigation/native-stack' } from '@react-navigation/native-stack'
import {NativeStackView} from '@react-navigation/native-stack'
import {type NativeStackNavigatorProps} from '@react-navigation/native-stack/src/types'
import {PWI_ENABLED} from '#/lib/build-flags' import {PWI_ENABLED} from '#/lib/build-flags'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
@@ -52,14 +48,12 @@ function NativeStackNavigator({
id, id,
initialRouteName, initialRouteName,
children, children,
layout,
screenListeners, screenListeners,
screenOptions, screenOptions,
screenLayout,
...rest ...rest
}: NativeStackNavigatorProps) { }: NativeStackNavigatorProps) {
// --- this is copy and pasted from the original native stack navigator --- // --- this is copy and pasted from the original native stack navigator ---
const {state, describe, descriptors, navigation, NavigationContent} = const {state, descriptors, navigation, NavigationContent} =
useNavigationBuilder< useNavigationBuilder<
StackNavigationState<ParamListBase>, StackNavigationState<ParamListBase>,
StackRouterOptions, StackRouterOptions,
@@ -70,12 +64,9 @@ function NativeStackNavigator({
id, id,
initialRouteName, initialRouteName,
children, children,
layout,
screenListeners, screenListeners,
screenOptions, screenOptions,
screenLayout,
}) })
React.useEffect( React.useEffect(
() => () =>
// @ts-expect-error: there may not be a tab navigator in parent // @ts-expect-error: there may not be a tab navigator in parent
@@ -157,8 +148,7 @@ function NativeStackNavigator({
{...rest} {...rest}
state={state} state={state}
navigation={navigation} navigation={navigation}
descriptors={descriptors} descriptors={newDescriptors}
describe={describe}
/> />
</View> </View>
{isWeb && ( {isWeb && (
@@ -171,25 +161,9 @@ function NativeStackNavigator({
) )
} }
export function createNativeStackNavigatorWithAuth< export const createNativeStackNavigatorWithAuth = createNavigatorFactory<
const ParamList extends ParamListBase, StackNavigationState<ParamListBase>,
const NavigatorID extends string | undefined = undefined, NativeStackNavigationOptionsWithAuth,
const TypeBag extends NavigatorTypeBagBase = { NativeStackNavigationEventMap,
ParamList: ParamList typeof NativeStackNavigator
NavigatorID: NavigatorID >(NativeStackNavigator)
State: StackNavigationState<ParamList>
ScreenOptions: NativeStackNavigationOptionsWithAuth
EventMap: NativeStackNavigationEventMap
NavigationList: {
[RouteName in keyof ParamList]: NativeStackNavigationProp<
ParamList,
RouteName,
NavigatorID
>
}
Navigator: typeof NativeStackNavigator
},
const Config extends StaticConfig<TypeBag> = StaticConfig<TypeBag>,
>(config?: Config): TypedNavigator<TypeBag, Config> {
return createNavigatorFactory(NativeStackNavigator)(config)
}
+8 -8
View File
@@ -1,10 +1,10 @@
import {useCallback, useMemo, useState} from 'react' import React from 'react'
import {StyleSheet, View} from 'react-native' import {StyleSheet, View} from 'react-native'
import {type AppBskyActorDefs} from '@atproto/api' import {type AppBskyActorDefs} from '@atproto/api'
import {msg, plural, Trans} from '@lingui/macro' import {msg, plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import { import {
useLinkTo, useLinkProps,
useNavigation, useNavigation,
useNavigationState, useNavigationState,
} from '@react-navigation/native' } from '@react-navigation/native'
@@ -326,7 +326,7 @@ function NavItem({count, hasNew, href, icon, iconFilled, label}: NavItemProps) {
const {_} = useLingui() const {_} = useLingui()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const {leftNavMinimal} = useLayoutBreakpoints() const {leftNavMinimal} = useLayoutBreakpoints()
const [pathName] = useMemo(() => router.matchPath(href), [href]) const [pathName] = React.useMemo(() => router.matchPath(href), [href])
const currentRouteInfo = useNavigationState(state => { const currentRouteInfo = useNavigationState(state => {
if (!state) { if (!state) {
return {name: 'Home'} return {name: 'Home'}
@@ -339,8 +339,8 @@ function NavItem({count, hasNew, href, icon, iconFilled, label}: NavItemProps) {
(currentRouteInfo.params as CommonNavigatorParams['Profile']).name === (currentRouteInfo.params as CommonNavigatorParams['Profile']).name ===
currentAccount?.handle currentAccount?.handle
: isTab(currentRouteInfo.name, pathName) : isTab(currentRouteInfo.name, pathName)
const linkTo = useLinkTo() const {onPress} = useLinkProps({to: href})
const onPressWrapped = useCallback( const onPressWrapped = React.useCallback(
(e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => { (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
if (e.ctrlKey || e.metaKey || e.altKey) { if (e.ctrlKey || e.metaKey || e.altKey) {
return return
@@ -349,10 +349,10 @@ function NavItem({count, hasNew, href, icon, iconFilled, label}: NavItemProps) {
if (isCurrent) { if (isCurrent) {
emitSoftReset() emitSoftReset()
} else { } else {
linkTo(href) onPress()
} }
}, },
[linkTo, href, isCurrent], [onPress, isCurrent],
) )
return ( return (
@@ -468,7 +468,7 @@ function ComposeBtn() {
const {openComposer} = useOpenComposer() const {openComposer} = useOpenComposer()
const {_} = useLingui() const {_} = useLingui()
const {leftNavMinimal} = useLayoutBreakpoints() const {leftNavMinimal} = useLayoutBreakpoints()
const [isFetchingHandle, setIsFetchingHandle] = useState(false) const [isFetchingHandle, setIsFetchingHandle] = React.useState(false)
const fetchHandle = useFetchHandle() const fetchHandle = useFetchHandle()
const getProfileHandle = async () => { const getProfileHandle = async () => {
+64 -74
View File
@@ -6295,69 +6295,65 @@
invariant "^2.2.4" invariant "^2.2.4"
nullthrows "^1.1.1" nullthrows "^1.1.1"
"@react-navigation/bottom-tabs@^7.3.13": "@react-navigation/bottom-tabs@^6.5.20":
version "7.3.14" version "6.5.20"
resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-7.3.14.tgz#9ee02baea86ab24abe267726665bc69c6df0bf4c" resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.20.tgz#5335e75b02c527ef0569bd97d4f9185d65616e49"
integrity sha512-s2qinJggS2HYZdCOey9A+fN+bNpWeEKwiL/FjAVOTcv+uofxPWN6CtEZUZGPEjfRjis/srURBmCmpNZSI6sQ9Q== integrity sha512-ow6Z06iS4VqBO8d7FP+HsGjJLWt2xTWIvuWjpoCvsM/uQXzCRDIjBv9HaKcXbF0yTW7IMir0oDAbU5PFzEDdgA==
dependencies: dependencies:
"@react-navigation/elements" "^2.4.3" "@react-navigation/elements" "^1.3.30"
color "^4.2.3" color "^4.2.3"
warn-once "^0.1.0"
"@react-navigation/core@^7.10.0": "@react-navigation/core@^6.4.16":
version "7.10.0" version "6.4.16"
resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-7.10.0.tgz#8205ea6b84ce34b2fc2c196701b4cd9b434211b9" resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-6.4.16.tgz#f9369a134805174536b9aa0f0f483b930511caf9"
integrity sha512-qZBA5gGm+9liT4+EHk+kl9apwvqh7HqhLF1XeX6SQRmC/n2QI0u1B8OevKc+EPUDEM9Od15IuwT/GRbSs7/Umw== integrity sha512-UDTJBsHxnzgFETR3ZxhctP+RWr4SkyeZpbhpkQoIGOuwSCkt1SE0qjU48/u6r6w6XlX8OqVudn1Ab0QFXTHxuQ==
dependencies: dependencies:
"@react-navigation/routers" "^7.4.0" "@react-navigation/routers" "^6.1.9"
escape-string-regexp "^4.0.0" escape-string-regexp "^4.0.0"
nanoid "^3.3.11" nanoid "^3.1.23"
query-string "^7.1.3" query-string "^7.1.3"
react-is "^19.1.0" react-is "^16.13.0"
use-latest-callback "^0.2.3" use-latest-callback "^0.1.9"
use-sync-external-store "^1.5.0"
"@react-navigation/drawer@^7.3.12": "@react-navigation/drawer@^6.6.15":
version "7.4.1" version "6.6.15"
resolved "https://registry.yarnpkg.com/@react-navigation/drawer/-/drawer-7.4.1.tgz#50517d8c57f09cdbfc20a485c47016066b918e76" resolved "https://registry.yarnpkg.com/@react-navigation/drawer/-/drawer-6.6.15.tgz#fcedba68f735103dbc035911f5959ce926081d62"
integrity sha512-kj5wL31smDLw/6l+0KPR5cjaOZg6oHJCl3RPQonFPuYolUPZBVnuS++uvlifWcD/mqdGmhl3rgLTircRH4vQ7Q== integrity sha512-GLkFQNxjtmxB/qXSHmu1DfoB89jCzW64tmX68iPndth+9U+0IP27GcCCaMZxQfwj+nI8Kn2zlTlXAZDIIHE+DQ==
dependencies: dependencies:
"@react-navigation/elements" "^2.4.3" "@react-navigation/elements" "^1.3.30"
color "^4.2.3" color "^4.2.3"
react-native-drawer-layout "^4.1.10" warn-once "^0.1.0"
use-latest-callback "^0.2.3"
"@react-navigation/elements@^2.4.3": "@react-navigation/elements@^1.3.30":
version "2.4.3" version "1.3.30"
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-2.4.3.tgz#cc1dde4c98739d35a0c9c23872316063962cfaee" resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.30.tgz#a81371f599af1070b12014f05d6c09b1a611fd9a"
integrity sha512-psoNmnZ0DQIt9nxxPITVLtYW04PGCAfnmd/Pcd3yhiBs93aj+HYKH+SDZDpUnXMf3BN7Wvo4+jPI+/Xjqb+m9w== integrity sha512-plhc8UvCZs0UkV+sI+3bisIyn78wz9O/BiWZXpounu72k/R/Sj5PuZYFJ1fi6psvriUveMCGh4LeZckAZu2qiQ==
dependencies:
color "^4.2.3"
"@react-navigation/native-stack@^7.3.13": "@react-navigation/native-stack@^6.9.26":
version "7.3.14" version "6.9.26"
resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-7.3.14.tgz#d1c90f2e50cd13bbced923991cf2faee8083f725" resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.26.tgz#90facf7783c9927f094bc9f01c613af75b6c241e"
integrity sha512-45Sf7ReqSCIySXS5nrKtLGmNlFXm5x+u32YQMwKDONCqVGOBCfo4ryKqeQq1EMJ7Py6IDyOwHMhA+jhNOxnfPw== integrity sha512-++dueQ+FDj2XkZ902DVrK79ub1vp19nSdAZWxKRgd6+Bc0Niiesua6rMCqymYOVaYh+dagwkA9r00bpt/U5WLw==
dependencies: dependencies:
"@react-navigation/elements" "^2.4.3" "@react-navigation/elements" "^1.3.30"
warn-once "^0.1.1" warn-once "^0.1.0"
"@react-navigation/native@^7.1.9": "@react-navigation/native@^6.1.17":
version "7.1.10" version "6.1.17"
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-7.1.10.tgz#768f674f7c09b6a57215762052aa62a7dc107402" resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.1.17.tgz#439f15a99809d26ea4682d2a3766081cf2ca31cf"
integrity sha512-Ug4IML0DkAxZTMF/E7lyyLXSclkGAYElY2cxZWITwfBjtlVeda0NjsdnTWY5EGjnd7bwvhTIUC+CO6qSlrDn5A== integrity sha512-mer3OvfwWOHoUSMJyLa4vnBH3zpFmCwuzrBPlw7feXklurr/ZDiLjLxUScOot6jLRMz/67GyilEYMmP99LL0RQ==
dependencies: dependencies:
"@react-navigation/core" "^7.10.0" "@react-navigation/core" "^6.4.16"
escape-string-regexp "^4.0.0" escape-string-regexp "^4.0.0"
fast-deep-equal "^3.1.3" fast-deep-equal "^3.1.3"
nanoid "^3.3.11" nanoid "^3.1.23"
use-latest-callback "^0.2.3"
"@react-navigation/routers@^7.4.0": "@react-navigation/routers@^6.1.9":
version "7.4.0" version "6.1.9"
resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-7.4.0.tgz#5bace799713ac163310c18711b98dfbe418c6b36" resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-6.1.9.tgz#73f5481a15a38e36592a0afa13c3c064b9f90bed"
integrity sha512-th5THnuWKJlmr7GGHiicy979di11ycDWub9iIXbEDvQwmwmsRzppmVbfs2nD8bC/MgyMgqWu/gxfys+HqN+kcw== integrity sha512-lTM8gSFHSfkJvQkxacGM6VJtBt61ip2XO54aNfswD+KMw6eeZ4oehl7m0me3CR9hnDE4+60iAZR8sAhvCiI3NA==
dependencies: dependencies:
nanoid "^3.3.11" nanoid "^3.1.23"
"@remirror/core-constants@3.0.0": "@remirror/core-constants@3.0.0":
version "3.0.0" version "3.0.0"
@@ -14984,16 +14980,11 @@ mz@^2.7.0:
object-assign "^4.0.1" object-assign "^4.0.1"
thenify-all "^1.0.0" thenify-all "^1.0.0"
nanoid@^3.3.1, nanoid@^3.3.6: nanoid@^3.1.23, nanoid@^3.3.1, nanoid@^3.3.6:
version "3.3.6" version "3.3.6"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
nanoid@^3.3.11:
version "3.3.11"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b"
integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==
nanoid@^3.3.7: nanoid@^3.3.7:
version "3.3.7" version "3.3.7"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
@@ -16754,12 +16745,12 @@ react-image-crop@^11.0.7:
resolved "https://registry.yarnpkg.com/react-image-crop/-/react-image-crop-11.0.7.tgz#25f3d37ccbb65a05d19d23b4740a5912835c741e" resolved "https://registry.yarnpkg.com/react-image-crop/-/react-image-crop-11.0.7.tgz#25f3d37ccbb65a05d19d23b4740a5912835c741e"
integrity sha512-ZciKWHDYzmm366JDL18CbrVyjnjH0ojufGDmScfS4ZUqLHg4nm6ATY+K62C75W4ZRNt4Ii+tX0bSjNk9LQ2xzQ== integrity sha512-ZciKWHDYzmm366JDL18CbrVyjnjH0ojufGDmScfS4ZUqLHg4nm6ATY+K62C75W4ZRNt4Ii+tX0bSjNk9LQ2xzQ==
react-is@19, react-is@^19.0.0, react-is@^19.1.0: react-is@19, react-is@^19.0.0:
version "19.1.0" version "19.1.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.1.0.tgz#805bce321546b7e14c084989c77022351bbdd11b" resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.1.0.tgz#805bce321546b7e14c084989c77022351bbdd11b"
integrity sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg== integrity sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==
react-is@^16.13.1, react-is@^16.7.0: react-is@^16.13.0, react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1" version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -16791,12 +16782,12 @@ react-native-dotenv@^3.4.11:
dependencies: dependencies:
dotenv "^16.4.5" dotenv "^16.4.5"
react-native-drawer-layout@^4.1.10, react-native-drawer-layout@^4.1.8: react-native-drawer-layout@^4.1.8:
version "4.1.10" version "4.1.12"
resolved "https://registry.yarnpkg.com/react-native-drawer-layout/-/react-native-drawer-layout-4.1.10.tgz#9007cb747767ca8e1c9c3337671ad35ed95ad4d9" resolved "https://registry.yarnpkg.com/react-native-drawer-layout/-/react-native-drawer-layout-4.1.12.tgz#0cdfe2d2ca9288cb099f1e1808c8addf2fad25de"
integrity sha512-wejQo0F+EffCkOkRh+DP6ENWMB+aWEHkXV8Pd564PmtoySZLUsV/ksYrh/mrufh7T7EuvGT8+fNHz7mMRYftWg== integrity sha512-oKolvp5seiUieG+RHGjpFe8rH8Ds24iW0QBl31TlCVOX7tdn42IQIBl5tuD1i7h3q+VqqnbcT+NB2dcJ5suZkw==
dependencies: dependencies:
use-latest-callback "^0.2.3" use-latest-callback "^0.2.4"
react-native-edge-to-edge@1.6.0, react-native-edge-to-edge@^1.6.0: react-native-edge-to-edge@1.6.0, react-native-edge-to-edge@^1.6.0:
version "1.6.0" version "1.6.0"
@@ -16833,7 +16824,7 @@ react-native-ios-context-menu@^1.15.3:
dependencies: dependencies:
"@dominicstop/ts-event-emitter" "^1.1.0" "@dominicstop/ts-event-emitter" "^1.1.0"
react-native-is-edge-to-edge@1.1.7, react-native-is-edge-to-edge@^1.1.7: react-native-is-edge-to-edge@1.1.7:
version "1.1.7" version "1.1.7"
resolved "https://registry.yarnpkg.com/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.1.7.tgz#28947688f9fafd584e73a4f935ea9603bd9b1939" resolved "https://registry.yarnpkg.com/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.1.7.tgz#28947688f9fafd584e73a4f935ea9603bd9b1939"
integrity sha512-EH6i7E8epJGIcu7KpfXYXiV2JFIYITtq+rVS8uEb+92naMRBdxhTuS8Wn2Q7j9sqyO0B+Xbaaf9VdipIAmGW4w== integrity sha512-EH6i7E8epJGIcu7KpfXYXiV2JFIYITtq+rVS8uEb+92naMRBdxhTuS8Wn2Q7j9sqyO0B+Xbaaf9VdipIAmGW4w==
@@ -16902,13 +16893,12 @@ react-native-safe-area-context@5.4.0:
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-5.4.0.tgz#04b51940408c114f75628a12a93569d30c525454" resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-5.4.0.tgz#04b51940408c114f75628a12a93569d30c525454"
integrity sha512-JaEThVyJcLhA+vU0NU8bZ0a1ih6GiF4faZ+ArZLqpYbL6j7R3caRqj+mE3lEtKCuHgwjLg3bCxLL1GPUJZVqUA== integrity sha512-JaEThVyJcLhA+vU0NU8bZ0a1ih6GiF4faZ+ArZLqpYbL6j7R3caRqj+mE3lEtKCuHgwjLg3bCxLL1GPUJZVqUA==
react-native-screens@^4.11.1: react-native-screens@~4.10.0:
version "4.11.1" version "4.10.0"
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-4.11.1.tgz#7d0f3d313d8ddc1e55437c5e038f15f8805dc991" resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-4.10.0.tgz#40634aead590c6b7034ded6a9f92465d1d611906"
integrity sha512-F0zOzRVa3ptZfLpD0J8ROdo+y1fEPw+VBFq1MTY/iyDu08al7qFUO5hLMd+EYMda5VXGaTFCa8q7bOppUszhJw== integrity sha512-Tw21NGuXm3PbiUGtZd0AnXirUixaAbPXDjNR0baBH7/WJDaDTTELLcQ7QRXuqAWbmr/EVCrKj1348ei1KFIr8A==
dependencies: dependencies:
react-freeze "^1.0.0" react-freeze "^1.0.0"
react-native-is-edge-to-edge "^1.1.7"
warn-once "^0.1.0" warn-once "^0.1.0"
react-native-svg@15.12.0: react-native-svg@15.12.0:
@@ -19401,10 +19391,15 @@ use-isomorphic-layout-effect@^1.1.1:
resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
use-latest-callback@^0.2.3: use-latest-callback@^0.1.9:
version "0.2.3" version "0.1.9"
resolved "https://registry.yarnpkg.com/use-latest-callback/-/use-latest-callback-0.2.3.tgz#2d644d3063040b9bc2d4c55bb525a13ae3de9e16" resolved "https://registry.yarnpkg.com/use-latest-callback/-/use-latest-callback-0.1.9.tgz#10191dc54257e65a8e52322127643a8940271e2a"
integrity sha512-7vI3fBuyRcP91pazVboc4qu+6ZqM8izPWX9k7cRnT8hbD5svslcknsh3S9BUhaK11OmgTV4oWZZVSeQAiV53SQ== integrity sha512-CL/29uS74AwreI/f2oz2hLTW7ZqVeV5+gxFeGudzQrgkCytrHw33G4KbnQOrRlAEzzAFXi7dDLMC9zhWcVpzmw==
use-latest-callback@^0.2.4:
version "0.2.4"
resolved "https://registry.yarnpkg.com/use-latest-callback/-/use-latest-callback-0.2.4.tgz#35c0f028f85a3f4cf025b06011110e87cc18f57e"
integrity sha512-LS2s2n1usUUnDq4oVh1ca6JFX9uSqUncTfAm44WMg0v6TxL7POUTk1B044NH8TeLkFbNajIsgDHcgNpNzZucdg==
use-latest@^1.2.1: use-latest@^1.2.1:
version "1.2.1" version "1.2.1"
@@ -19434,11 +19429,6 @@ use-sync-external-store@^1.2.2:
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9"
integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw== integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==
use-sync-external-store@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz#55122e2a3edd2a6c106174c27485e0fd59bcfca0"
integrity sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
@@ -19540,7 +19530,7 @@ walker@^1.0.7, walker@^1.0.8:
dependencies: dependencies:
makeerror "1.0.12" makeerror "1.0.12"
warn-once@0.1.1, warn-once@^0.1.0, warn-once@^0.1.1: warn-once@0.1.1, warn-once@^0.1.0:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/warn-once/-/warn-once-0.1.1.tgz#952088f4fb56896e73fd4e6a3767272a3fccce43" resolved "https://registry.yarnpkg.com/warn-once/-/warn-once-0.1.1.tgz#952088f4fb56896e73fd4e6a3767272a3fccce43"
integrity sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q== integrity sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==