Link updates, add atoms

This commit is contained in:
Eric Bailey
2024-02-16 10:55:50 -06:00
parent 1b992d5d6b
commit 677c4abece
3 changed files with 77 additions and 18 deletions
+36
View File
@@ -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
+35 -17
View File
@@ -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,8 @@ type BaseLinkProps = Pick<
Parameters<typeof useLinkProps<AllNavigatorParams>>[0],
'to'
> & {
testID?: string
/**
* The React Navigation `StackAction` to perform when the link is pressed.
*/
@@ -46,6 +48,13 @@ 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
}
export function useLink({
@@ -53,6 +62,7 @@ export function useLink({
displayText,
action = 'push',
warnOnMismatchingTextChild,
onPress: outerOnPress,
}: BaseLinkProps & {
displayText: string
}) {
@@ -66,6 +76,8 @@ export function useLink({
const onPress = React.useCallback(
(e: GestureResponderEvent) => {
outerOnPress?.(e)
const requiresWarning = Boolean(
warnOnMismatchingTextChild &&
displayText &&
@@ -132,6 +144,7 @@ export function useLink({
displayText,
closeModal,
openModal,
outerOnPress,
],
)
@@ -143,15 +156,11 @@ export function useLink({
}
export type LinkProps = Omit<BaseLinkProps, 'warnOnMismatchingTextChild'> &
Omit<ButtonProps, 'style' | 'onPress' | 'disabled' | 'label'> & {
Omit<ButtonProps, 'onPress' | 'disabled' | 'label'> & {
/**
* Label for a11y. Defaults to the href.
*/
label?: string
/**
* Web-only attribute. Sets `download` attr on web.
*/
download?: string
}
/**
@@ -166,19 +175,21 @@ export function Link({
children,
to,
action = 'push',
download,
onPress: outerOnPress,
...rest
}: LinkProps) {
const {href, isExternal, onPress} = useLink({
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}
@@ -187,7 +198,6 @@ export function Link({
hrefAttrs: {
target: isExternal ? 'blank' : undefined,
rel: isExternal ? 'noopener noreferrer' : undefined,
download,
},
dataSet: {
// default to no underline, apply this ourselves
@@ -215,6 +225,7 @@ export function InlineLink({
action = 'push',
warnOnMismatchingTextChild,
style,
onPress: outerOnPress,
...rest
}: InlineLinkProps) {
const t = useTheme()
@@ -224,13 +235,20 @@ 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
@@ -245,14 +263,16 @@ 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({
@@ -260,12 +280,10 @@ export function InlineLink({
target: isExternal ? 'blank' : undefined,
rel: isExternal ? 'noopener noreferrer' : undefined,
},
dataSet: stringChildren
? {}
: {
// default to no underline, apply this ourselves
noUnderline: '1',
},
dataSet: {
// default to no underline, apply this ourselves
noUnderline: '1',
},
})}>
{children}
</Text>
+6 -1
View File
@@ -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