Fix link warnings (#3058)
* fix problems where www.bsky.app shows as a potential danger * never default to disabling warning * remove more defaults * update storybook cases * oops * reverse
This commit is contained in:
parent
1a5afccdb8
commit
39d324ab8b
6 changed files with 24 additions and 44 deletions
|
@ -49,7 +49,7 @@ type BaseLinkProps = Pick<
|
||||||
*
|
*
|
||||||
* Note: atm this only works for `InlineLink`s with a string child.
|
* Note: atm this only works for `InlineLink`s with a string child.
|
||||||
*/
|
*/
|
||||||
warnOnMismatchingTextChild?: boolean
|
disableMismatchWarning?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for when the link is pressed. Prevent default and return `false`
|
* Callback for when the link is pressed. Prevent default and return `false`
|
||||||
|
@ -69,7 +69,7 @@ export function useLink({
|
||||||
to,
|
to,
|
||||||
displayText,
|
displayText,
|
||||||
action = 'push',
|
action = 'push',
|
||||||
warnOnMismatchingTextChild,
|
disableMismatchWarning,
|
||||||
onPress: outerOnPress,
|
onPress: outerOnPress,
|
||||||
}: BaseLinkProps & {
|
}: BaseLinkProps & {
|
||||||
displayText: string
|
displayText: string
|
||||||
|
@ -90,7 +90,7 @@ export function useLink({
|
||||||
if (exitEarlyIfFalse === false) return
|
if (exitEarlyIfFalse === false) return
|
||||||
|
|
||||||
const requiresWarning = Boolean(
|
const requiresWarning = Boolean(
|
||||||
warnOnMismatchingTextChild &&
|
!disableMismatchWarning &&
|
||||||
displayText &&
|
displayText &&
|
||||||
isExternal &&
|
isExternal &&
|
||||||
linkRequiresWarning(href, displayText),
|
linkRequiresWarning(href, displayText),
|
||||||
|
@ -148,7 +148,7 @@ export function useLink({
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
outerOnPress,
|
outerOnPress,
|
||||||
warnOnMismatchingTextChild,
|
disableMismatchWarning,
|
||||||
displayText,
|
displayText,
|
||||||
isExternal,
|
isExternal,
|
||||||
href,
|
href,
|
||||||
|
@ -167,7 +167,7 @@ export function useLink({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LinkProps = Omit<BaseLinkProps, 'warnOnMismatchingTextChild'> &
|
export type LinkProps = Omit<BaseLinkProps, 'disableMismatchWarning'> &
|
||||||
Omit<ButtonProps, 'onPress' | 'disabled' | 'label'>
|
Omit<ButtonProps, 'onPress' | 'disabled' | 'label'>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -226,7 +226,7 @@ export function InlineLink({
|
||||||
children,
|
children,
|
||||||
to,
|
to,
|
||||||
action = 'push',
|
action = 'push',
|
||||||
warnOnMismatchingTextChild,
|
disableMismatchWarning,
|
||||||
style,
|
style,
|
||||||
onPress: outerOnPress,
|
onPress: outerOnPress,
|
||||||
download,
|
download,
|
||||||
|
@ -239,7 +239,7 @@ export function InlineLink({
|
||||||
to,
|
to,
|
||||||
displayText: stringChildren ? children : '',
|
displayText: stringChildren ? children : '',
|
||||||
action,
|
action,
|
||||||
warnOnMismatchingTextChild,
|
disableMismatchWarning,
|
||||||
onPress: outerOnPress,
|
onPress: outerOnPress,
|
||||||
})
|
})
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -105,8 +105,7 @@ export function RichText({
|
||||||
to={link.uri}
|
to={link.uri}
|
||||||
style={[...styles, {pointerEvents: 'auto'}]}
|
style={[...styles, {pointerEvents: 'auto'}]}
|
||||||
// @ts-ignore TODO
|
// @ts-ignore TODO
|
||||||
dataSet={WORD_WRAP}
|
dataSet={WORD_WRAP}>
|
||||||
warnOnMismatchingLabel>
|
|
||||||
{toShortUrl(segment.text)}
|
{toShortUrl(segment.text)}
|
||||||
</InlineLink>,
|
</InlineLink>,
|
||||||
)
|
)
|
||||||
|
|
|
@ -157,17 +157,11 @@ export function linkRequiresWarning(uri: string, label: string) {
|
||||||
|
|
||||||
const host = urip.hostname.toLowerCase()
|
const host = urip.hostname.toLowerCase()
|
||||||
|
|
||||||
if (host === 'bsky.app') {
|
// Hosts that end with bsky.app or bsky.social should be trusted by default.
|
||||||
|
if (host.endsWith('bsky.app') || host.endsWith('bsky.social')) {
|
||||||
// if this is a link to internal content,
|
// if this is a link to internal content,
|
||||||
// warn if it represents itself as a URL to another app
|
// warn if it represents itself as a URL to another app
|
||||||
if (
|
return !!labelDomain && labelDomain !== host && isPossiblyAUrl(labelDomain)
|
||||||
labelDomain &&
|
|
||||||
labelDomain !== 'bsky.app' &&
|
|
||||||
isPossiblyAUrl(labelDomain)
|
|
||||||
) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
} else {
|
} else {
|
||||||
// if this is a link to external content,
|
// if this is a link to external content,
|
||||||
// warn if the label doesnt match the target
|
// warn if the label doesnt match the target
|
||||||
|
|
|
@ -159,7 +159,7 @@ export const TextLink = memo(function TextLink({
|
||||||
dataSet,
|
dataSet,
|
||||||
title,
|
title,
|
||||||
onPress,
|
onPress,
|
||||||
warnOnMismatchingLabel,
|
disableMismatchWarning,
|
||||||
navigationAction,
|
navigationAction,
|
||||||
...orgProps
|
...orgProps
|
||||||
}: {
|
}: {
|
||||||
|
@ -172,7 +172,7 @@ export const TextLink = memo(function TextLink({
|
||||||
lineHeight?: number
|
lineHeight?: number
|
||||||
dataSet?: any
|
dataSet?: any
|
||||||
title?: string
|
title?: string
|
||||||
warnOnMismatchingLabel?: boolean
|
disableMismatchWarning?: boolean
|
||||||
navigationAction?: 'push' | 'replace' | 'navigate'
|
navigationAction?: 'push' | 'replace' | 'navigate'
|
||||||
} & TextProps) {
|
} & TextProps) {
|
||||||
const {...props} = useLinkProps({to: sanitizeUrl(href)})
|
const {...props} = useLinkProps({to: sanitizeUrl(href)})
|
||||||
|
@ -180,14 +180,14 @@ export const TextLink = memo(function TextLink({
|
||||||
const {openModal, closeModal} = useModalControls()
|
const {openModal, closeModal} = useModalControls()
|
||||||
const openLink = useOpenLink()
|
const openLink = useOpenLink()
|
||||||
|
|
||||||
if (warnOnMismatchingLabel && typeof text !== 'string') {
|
if (!disableMismatchWarning && typeof text !== 'string') {
|
||||||
console.error('Unable to detect mismatching label')
|
console.error('Unable to detect mismatching label')
|
||||||
}
|
}
|
||||||
|
|
||||||
props.onPress = React.useCallback(
|
props.onPress = React.useCallback(
|
||||||
(e?: Event) => {
|
(e?: Event) => {
|
||||||
const requiresWarning =
|
const requiresWarning =
|
||||||
warnOnMismatchingLabel &&
|
!disableMismatchWarning &&
|
||||||
linkRequiresWarning(href, typeof text === 'string' ? text : '')
|
linkRequiresWarning(href, typeof text === 'string' ? text : '')
|
||||||
if (requiresWarning) {
|
if (requiresWarning) {
|
||||||
e?.preventDefault?.()
|
e?.preventDefault?.()
|
||||||
|
@ -227,7 +227,7 @@ export const TextLink = memo(function TextLink({
|
||||||
navigation,
|
navigation,
|
||||||
href,
|
href,
|
||||||
text,
|
text,
|
||||||
warnOnMismatchingLabel,
|
disableMismatchWarning,
|
||||||
navigationAction,
|
navigationAction,
|
||||||
openLink,
|
openLink,
|
||||||
],
|
],
|
||||||
|
|
|
@ -114,7 +114,6 @@ export function RichText({
|
||||||
href={link.uri}
|
href={link.uri}
|
||||||
style={[style, lineHeightStyle, pal.link, {pointerEvents: 'auto'}]}
|
style={[style, lineHeightStyle, pal.link, {pointerEvents: 'auto'}]}
|
||||||
dataSet={WORD_WRAP}
|
dataSet={WORD_WRAP}
|
||||||
warnOnMismatchingLabel
|
|
||||||
selectable={selectable}
|
selectable={selectable}
|
||||||
/>,
|
/>,
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {View} from 'react-native'
|
||||||
import {useTheme, atoms as a} from '#/alf'
|
import {useTheme, atoms as a} from '#/alf'
|
||||||
import {ButtonText} from '#/components/Button'
|
import {ButtonText} from '#/components/Button'
|
||||||
import {InlineLink, Link} from '#/components/Link'
|
import {InlineLink, Link} from '#/components/Link'
|
||||||
import {H1, H3, Text} from '#/components/Typography'
|
import {H1, Text} from '#/components/Typography'
|
||||||
|
|
||||||
export function Links() {
|
export function Links() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
@ -13,31 +13,19 @@ export function Links() {
|
||||||
<H1>Links</H1>
|
<H1>Links</H1>
|
||||||
|
|
||||||
<View style={[a.gap_md, a.align_start]}>
|
<View style={[a.gap_md, a.align_start]}>
|
||||||
<InlineLink
|
<InlineLink to="https://google.com" style={[a.text_lg]}>
|
||||||
to="https://bsky.social"
|
https://google.com
|
||||||
warnOnMismatchingTextChild
|
|
||||||
style={[a.text_md]}>
|
|
||||||
External
|
|
||||||
</InlineLink>
|
</InlineLink>
|
||||||
<InlineLink to="https://bsky.social" style={[a.text_md, t.atoms.text]}>
|
<InlineLink to="https://google.com" style={[a.text_lg]}>
|
||||||
<H3>External with custom children</H3>
|
External with custom children (google.com)
|
||||||
</InlineLink>
|
</InlineLink>
|
||||||
<InlineLink
|
<InlineLink
|
||||||
to="https://bsky.social"
|
to="https://bsky.social"
|
||||||
style={[a.text_md, t.atoms.text_contrast_low]}>
|
style={[a.text_md, t.atoms.text_contrast_low]}>
|
||||||
External with custom children
|
Internal (bsky.social)
|
||||||
</InlineLink>
|
</InlineLink>
|
||||||
<InlineLink
|
<InlineLink to="https://bsky.app/profile/bsky.app" style={[a.text_md]}>
|
||||||
to="https://bsky.social"
|
Internal (bsky.app)
|
||||||
warnOnMismatchingTextChild
|
|
||||||
style={[a.text_lg]}>
|
|
||||||
https://bsky.social
|
|
||||||
</InlineLink>
|
|
||||||
<InlineLink
|
|
||||||
to="https://bsky.app/profile/bsky.app"
|
|
||||||
warnOnMismatchingTextChild
|
|
||||||
style={[a.text_md]}>
|
|
||||||
Internal
|
|
||||||
</InlineLink>
|
</InlineLink>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue