Link updates (#2890)
* Link updates, add atoms * Update comments * Support download * Don't open new window for downloadzio/stable
parent
0ff61e08e9
commit
1d729721e5
|
@ -122,6 +122,9 @@ export const atoms = {
|
|||
flex_shrink: {
|
||||
flexShrink: 1,
|
||||
},
|
||||
justify_start: {
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
justify_center: {
|
||||
justifyContent: 'center',
|
||||
},
|
||||
|
@ -140,10 +143,31 @@ export const atoms = {
|
|||
align_end: {
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
self_auto: {
|
||||
alignSelf: 'auto',
|
||||
},
|
||||
self_start: {
|
||||
alignSelf: 'flex-start',
|
||||
},
|
||||
self_end: {
|
||||
alignSelf: 'flex-end',
|
||||
},
|
||||
self_center: {
|
||||
alignSelf: 'center',
|
||||
},
|
||||
self_stretch: {
|
||||
alignSelf: 'stretch',
|
||||
},
|
||||
self_baseline: {
|
||||
alignSelf: 'baseline',
|
||||
},
|
||||
|
||||
/*
|
||||
* Text
|
||||
*/
|
||||
text_left: {
|
||||
textAlign: 'left',
|
||||
},
|
||||
text_center: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
|
@ -195,10 +219,16 @@ export const atoms = {
|
|||
font_bold: {
|
||||
fontWeight: tokens.fontWeight.semibold,
|
||||
},
|
||||
italic: {
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
|
||||
/*
|
||||
* Border
|
||||
*/
|
||||
border_0: {
|
||||
borderWidth: 0,
|
||||
},
|
||||
border: {
|
||||
borderWidth: 1,
|
||||
},
|
||||
|
@ -208,6 +238,12 @@ export const atoms = {
|
|||
border_b: {
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
border_l: {
|
||||
borderLeftWidth: 1,
|
||||
},
|
||||
border_r: {
|
||||
borderRightWidth: 1,
|
||||
},
|
||||
|
||||
/*
|
||||
* Shadow
|
||||
|
|
|
@ -13,7 +13,7 @@ import {sanitizeUrl} from '@braintree/sanitize-url'
|
|||
|
||||
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {useTheme, web, flatten, TextStyleProp} from '#/alf'
|
||||
import {useTheme, web, flatten, TextStyleProp, atoms as a} from '#/alf'
|
||||
import {Button, ButtonProps} from '#/components/Button'
|
||||
import {AllNavigatorParams, NavigationProp} from '#/lib/routes/types'
|
||||
import {
|
||||
|
@ -35,6 +35,13 @@ type BaseLinkProps = Pick<
|
|||
Parameters<typeof useLinkProps<AllNavigatorParams>>[0],
|
||||
'to'
|
||||
> & {
|
||||
testID?: string
|
||||
|
||||
/**
|
||||
* Label for a11y. Defaults to the href.
|
||||
*/
|
||||
label?: string
|
||||
|
||||
/**
|
||||
* The React Navigation `StackAction` to perform when the link is pressed.
|
||||
*/
|
||||
|
@ -46,6 +53,18 @@ type BaseLinkProps = Pick<
|
|||
* Note: atm this only works for `InlineLink`s with a string child.
|
||||
*/
|
||||
warnOnMismatchingTextChild?: boolean
|
||||
|
||||
/**
|
||||
* Callback for when the link is pressed.
|
||||
*
|
||||
* DO NOT use this for navigation, that's what the `to` prop is for.
|
||||
*/
|
||||
onPress?: (e: GestureResponderEvent) => void
|
||||
|
||||
/**
|
||||
* Web-only attribute. Sets `download` attr on web.
|
||||
*/
|
||||
download?: string
|
||||
}
|
||||
|
||||
export function useLink({
|
||||
|
@ -53,6 +72,7 @@ export function useLink({
|
|||
displayText,
|
||||
action = 'push',
|
||||
warnOnMismatchingTextChild,
|
||||
onPress: outerOnPress,
|
||||
}: BaseLinkProps & {
|
||||
displayText: string
|
||||
}) {
|
||||
|
@ -66,6 +86,8 @@ export function useLink({
|
|||
|
||||
const onPress = React.useCallback(
|
||||
(e: GestureResponderEvent) => {
|
||||
outerOnPress?.(e)
|
||||
|
||||
const requiresWarning = Boolean(
|
||||
warnOnMismatchingTextChild &&
|
||||
displayText &&
|
||||
|
@ -132,6 +154,7 @@ export function useLink({
|
|||
displayText,
|
||||
closeModal,
|
||||
openModal,
|
||||
outerOnPress,
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -143,16 +166,7 @@ export function useLink({
|
|||
}
|
||||
|
||||
export type LinkProps = Omit<BaseLinkProps, 'warnOnMismatchingTextChild'> &
|
||||
Omit<ButtonProps, 'style' | 'onPress' | 'disabled' | 'label'> & {
|
||||
/**
|
||||
* Label for a11y. Defaults to the href.
|
||||
*/
|
||||
label?: string
|
||||
/**
|
||||
* Web-only attribute. Sets `download` attr on web.
|
||||
*/
|
||||
download?: string
|
||||
}
|
||||
Omit<ButtonProps, 'onPress' | 'disabled' | 'label'>
|
||||
|
||||
/**
|
||||
* A interactive element that renders as a `<a>` tag on the web. On mobile it
|
||||
|
@ -166,6 +180,7 @@ export function Link({
|
|||
children,
|
||||
to,
|
||||
action = 'push',
|
||||
onPress: outerOnPress,
|
||||
download,
|
||||
...rest
|
||||
}: LinkProps) {
|
||||
|
@ -173,24 +188,26 @@ export function Link({
|
|||
to,
|
||||
displayText: typeof children === 'string' ? children : '',
|
||||
action,
|
||||
onPress: outerOnPress,
|
||||
})
|
||||
|
||||
return (
|
||||
<Button
|
||||
label={href}
|
||||
{...rest}
|
||||
style={[a.justify_start, flatten(rest.style)]}
|
||||
role="link"
|
||||
accessibilityRole="link"
|
||||
href={href}
|
||||
onPress={onPress}
|
||||
onPress={download ? undefined : onPress}
|
||||
{...web({
|
||||
hrefAttrs: {
|
||||
target: isExternal ? 'blank' : undefined,
|
||||
target: download ? undefined : isExternal ? 'blank' : undefined,
|
||||
rel: isExternal ? 'noopener noreferrer' : undefined,
|
||||
download,
|
||||
},
|
||||
dataSet: {
|
||||
// default to no underline, apply this ourselves
|
||||
// no underline, only `InlineLink` has underlines
|
||||
noUnderline: '1',
|
||||
},
|
||||
})}>
|
||||
|
@ -200,13 +217,7 @@ export function Link({
|
|||
}
|
||||
|
||||
export type InlineLinkProps = React.PropsWithChildren<
|
||||
BaseLinkProps &
|
||||
TextStyleProp & {
|
||||
/**
|
||||
* Label for a11y. Defaults to the href.
|
||||
*/
|
||||
label?: string
|
||||
}
|
||||
BaseLinkProps & TextStyleProp
|
||||
>
|
||||
|
||||
export function InlineLink({
|
||||
|
@ -215,6 +226,8 @@ export function InlineLink({
|
|||
action = 'push',
|
||||
warnOnMismatchingTextChild,
|
||||
style,
|
||||
onPress: outerOnPress,
|
||||
download,
|
||||
...rest
|
||||
}: InlineLinkProps) {
|
||||
const t = useTheme()
|
||||
|
@ -224,18 +237,25 @@ export function InlineLink({
|
|||
displayText: stringChildren ? children : '',
|
||||
action,
|
||||
warnOnMismatchingTextChild,
|
||||
onPress: outerOnPress,
|
||||
})
|
||||
const {
|
||||
state: hovered,
|
||||
onIn: onHoverIn,
|
||||
onOut: onHoverOut,
|
||||
} = useInteractionState()
|
||||
const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
|
||||
const {
|
||||
state: pressed,
|
||||
onIn: onPressIn,
|
||||
onOut: onPressOut,
|
||||
} = useInteractionState()
|
||||
const flattenedStyle = flatten(style)
|
||||
|
||||
return (
|
||||
<TouchableWithoutFeedback
|
||||
accessibilityRole="button"
|
||||
onPress={onPress}
|
||||
onPress={download ? undefined : onPress}
|
||||
onPressIn={onPressIn}
|
||||
onPressOut={onPressOut}
|
||||
onFocus={onFocus}
|
||||
|
@ -245,24 +265,25 @@ export function InlineLink({
|
|||
{...rest}
|
||||
style={[
|
||||
{color: t.palette.primary_500},
|
||||
(focused || pressed) && {
|
||||
(hovered || focused || pressed) && {
|
||||
outline: 0,
|
||||
textDecorationLine: 'underline',
|
||||
textDecorationColor: t.palette.primary_500,
|
||||
textDecorationColor: flattenedStyle.color ?? t.palette.primary_500,
|
||||
},
|
||||
flatten(style),
|
||||
flattenedStyle,
|
||||
]}
|
||||
role="link"
|
||||
onMouseEnter={onHoverIn}
|
||||
onMouseLeave={onHoverOut}
|
||||
accessibilityRole="link"
|
||||
href={href}
|
||||
{...web({
|
||||
hrefAttrs: {
|
||||
target: isExternal ? 'blank' : undefined,
|
||||
target: download ? undefined : isExternal ? 'blank' : undefined,
|
||||
rel: isExternal ? 'noopener noreferrer' : undefined,
|
||||
download,
|
||||
},
|
||||
dataSet: stringChildren
|
||||
? {}
|
||||
: {
|
||||
dataSet: {
|
||||
// default to no underline, apply this ourselves
|
||||
noUnderline: '1',
|
||||
},
|
||||
|
|
|
@ -19,9 +19,14 @@ export function Links() {
|
|||
style={[a.text_md]}>
|
||||
External
|
||||
</InlineLink>
|
||||
<InlineLink to="https://bsky.social" style={[a.text_md]}>
|
||||
<InlineLink to="https://bsky.social" style={[a.text_md, t.atoms.text]}>
|
||||
<H3>External with custom children</H3>
|
||||
</InlineLink>
|
||||
<InlineLink
|
||||
to="https://bsky.social"
|
||||
style={[a.text_md, t.atoms.text_contrast_low]}>
|
||||
External with custom children
|
||||
</InlineLink>
|
||||
<InlineLink
|
||||
to="https://bsky.social"
|
||||
warnOnMismatchingTextChild
|
||||
|
|
Loading…
Reference in New Issue