Fix using screen names in Link (#8473)

* use our router in favour of useLinkBuilder

* test feature using Home header feeds button

* handle non-string params properly
This commit is contained in:
Samuel Newman
2025-06-11 20:12:05 +03:00
committed by GitHub
parent 269105371b
commit 7341294df6
4 changed files with 11 additions and 21 deletions
+3 -5
View File
@@ -4,7 +4,6 @@ import {sanitizeUrl} from '@braintree/sanitize-url'
import { import {
type LinkProps as RNLinkProps, type LinkProps as RNLinkProps,
StackActions, StackActions,
useLinkBuilder,
} from '@react-navigation/native' } from '@react-navigation/native'
import {BSKY_DOWNLOAD_URL} from '#/lib/constants' import {BSKY_DOWNLOAD_URL} from '#/lib/constants'
@@ -95,20 +94,19 @@ export function useLink({
shouldProxy?: boolean shouldProxy?: boolean
}) { }) {
const navigation = useNavigationDeduped() const navigation = useNavigationDeduped()
const {buildHref} = useLinkBuilder()
const href = useMemo(() => { const href = useMemo(() => {
return typeof to === 'string' return typeof to === 'string'
? convertBskyAppUrlIfNeeded(sanitizeUrl(to)) ? convertBskyAppUrlIfNeeded(sanitizeUrl(to))
: to.screen : to.screen
? buildHref(to.screen, to.params) ? router.matchName(to.screen)?.build(to.params)
: to.href : to.href
? convertBskyAppUrlIfNeeded(sanitizeUrl(to.href)) ? convertBskyAppUrlIfNeeded(sanitizeUrl(to.href))
: undefined : undefined
}, [to, buildHref]) }, [to])
if (!href) { if (!href) {
throw new Error( throw new Error(
'Link `to` prop must be a string or an object with `screen` and `params` properties', 'Could not resolve screen. Link `to` prop must be a string or an object with `screen` and `params` properties',
) )
} }
+4 -4
View File
@@ -1,4 +1,4 @@
import {Route, RouteParams} from './types' import {type Route, type RouteParams} from './types'
export class Router { export class Router {
routes: [string, Route][] = [] routes: [string, Route][] = []
@@ -45,7 +45,7 @@ function createRoute(pattern: string): Route {
}) })
const matcherRe = new RegExp(`^${matcherReInternal}([?]|$)`, 'i') const matcherRe = new RegExp(`^${matcherReInternal}([?]|$)`, 'i')
return { return {
match(path: string) { match(path) {
const {pathname, searchParams} = new URL(path, 'http://throwaway.com') const {pathname, searchParams} = new URL(path, 'http://throwaway.com')
const addedParams = Object.fromEntries(searchParams.entries()) const addedParams = Object.fromEntries(searchParams.entries())
@@ -55,10 +55,10 @@ function createRoute(pattern: string): Route {
} }
return undefined return undefined
}, },
build(params: Record<string, string>) { build(params = {}) {
const str = pattern.replace( const str = pattern.replace(
/:([\w]+)/g, /:([\w]+)/g,
(_m, name) => params[name] || 'undefined', (_m, name) => params[encodeURIComponent(name)] || 'undefined',
) )
let hasQp = false let hasQp = false
+1 -1
View File
@@ -143,5 +143,5 @@ export type RouteParams = Record<string, string>
export type MatchResult = {params: RouteParams} export type MatchResult = {params: RouteParams}
export type Route = { export type Route = {
match: (path: string) => MatchResult | undefined match: (path: string) => MatchResult | undefined
build: (params: RouteParams) => string build: (params?: Record<string, any>) => string
} }
+3 -11
View File
@@ -1,4 +1,3 @@
import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import Animated from 'react-native-reanimated' import Animated from 'react-native-reanimated'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
@@ -56,13 +55,8 @@ export function HomeHeaderLayoutMobile({
<PressableScale <PressableScale
targetScale={0.9} targetScale={0.9}
onPress={() => { onPress={() => {
emitSoftReset()
}}
onPressIn={() => {
playHaptic('Heavy')
}}
onPressOut={() => {
playHaptic('Light') playHaptic('Light')
emitSoftReset()
}}> }}>
<Logo width={30} /> <Logo width={30} />
</PressableScale> </PressableScale>
@@ -72,7 +66,7 @@ export function HomeHeaderLayoutMobile({
{hasSession && ( {hasSession && (
<Link <Link
testID="viewHeaderHomeFeedPrefsBtn" testID="viewHeaderHomeFeedPrefsBtn"
to="/feeds" to={{screen: 'Feeds'}}
hitSlop={HITSLOP_10} hitSlop={HITSLOP_10}
label={_(msg`View your feeds and explore more`)} label={_(msg`View your feeds and explore more`)}
size="small" size="small"
@@ -81,9 +75,7 @@ export function HomeHeaderLayoutMobile({
shape="square" shape="square"
style={[ style={[
a.justify_center, a.justify_center,
{ {marginRight: -Layout.BUTTON_VISUAL_ALIGNMENT_OFFSET},
marginRight: -Layout.BUTTON_VISUAL_ALIGNMENT_OFFSET,
},
]}> ]}>
<ButtonIcon icon={FeedsIcon} size="lg" /> <ButtonIcon icon={FeedsIcon} size="lg" />
</Link> </Link>