Some button updates (#2889)

* Some button updates

* Better name
zio/stable
Eric Bailey 2024-02-16 11:50:24 -06:00 committed by GitHub
parent 1b992d5d6b
commit ae9f893723
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 67 additions and 35 deletions

View File

@ -27,7 +27,7 @@ export type ButtonColor =
| 'gradient_sunset' | 'gradient_sunset'
| 'gradient_nordic' | 'gradient_nordic'
| 'gradient_bonfire' | 'gradient_bonfire'
export type ButtonSize = 'small' | 'large' export type ButtonSize = 'tiny' | 'small' | 'large'
export type ButtonShape = 'round' | 'square' | 'default' export type ButtonShape = 'round' | 'square' | 'default'
export type VariantProps = { export type VariantProps = {
/** /**
@ -48,25 +48,32 @@ export type VariantProps = {
shape?: ButtonShape shape?: ButtonShape
} }
export type ButtonProps = React.PropsWithChildren< export type ButtonState = {
Pick<PressableProps, 'disabled' | 'onPress'> & hovered: boolean
AccessibilityProps & focused: boolean
VariantProps & { pressed: boolean
testID?: string disabled: boolean
label: string }
style?: StyleProp<ViewStyle>
} export type ButtonContext = VariantProps & ButtonState
>
export type ButtonProps = Pick<
PressableProps,
'disabled' | 'onPress' | 'testID'
> &
AccessibilityProps &
VariantProps & {
testID?: string
label: string
style?: StyleProp<ViewStyle>
children:
| React.ReactNode
| string
| ((context: ButtonContext) => React.ReactNode | string)
}
export type ButtonTextProps = TextProps & VariantProps & {disabled?: boolean} export type ButtonTextProps = TextProps & VariantProps & {disabled?: boolean}
const Context = React.createContext< const Context = React.createContext<VariantProps & ButtonState>({
VariantProps & {
hovered: boolean
focused: boolean
pressed: boolean
disabled: boolean
}
>({
hovered: false, hovered: false,
focused: false, focused: false,
pressed: false, pressed: false,
@ -277,6 +284,8 @@ export function Button({
baseStyles.push({paddingVertical: 15}, a.px_2xl, a.rounded_sm, a.gap_md) baseStyles.push({paddingVertical: 15}, a.px_2xl, a.rounded_sm, a.gap_md)
} else if (size === 'small') { } else if (size === 'small') {
baseStyles.push({paddingVertical: 9}, a.px_lg, a.rounded_sm, a.gap_sm) baseStyles.push({paddingVertical: 9}, a.px_lg, a.rounded_sm, a.gap_sm)
} else if (size === 'tiny') {
baseStyles.push({paddingVertical: 4}, a.px_sm, a.rounded_xs, a.gap_xs)
} }
} else if (shape === 'round' || shape === 'square') { } else if (shape === 'round' || shape === 'square') {
if (size === 'large') { if (size === 'large') {
@ -287,12 +296,18 @@ export function Button({
} }
} else if (size === 'small') { } else if (size === 'small') {
baseStyles.push({height: 40, width: 40}) baseStyles.push({height: 40, width: 40})
} else if (size === 'tiny') {
baseStyles.push({height: 20, width: 20})
} }
if (shape === 'round') { if (shape === 'round') {
baseStyles.push(a.rounded_full) baseStyles.push(a.rounded_full)
} else if (shape === 'square') { } else if (shape === 'square') {
baseStyles.push(a.rounded_sm) if (size === 'tiny') {
baseStyles.push(a.rounded_xs)
} else {
baseStyles.push(a.rounded_sm)
}
} }
} }
@ -338,7 +353,7 @@ export function Button({
} }
}, [variant, color]) }, [variant, color])
const context = React.useMemo( const context = React.useMemo<ButtonContext>(
() => ({ () => ({
...state, ...state,
variant, variant,
@ -349,6 +364,8 @@ export function Button({
[state, variant, color, size, disabled], [state, variant, color, size, disabled],
) )
const flattenedBaseStyles = flatten(baseStyles)
return ( return (
<Pressable <Pressable
role="button" role="button"
@ -362,15 +379,14 @@ export function Button({
disabled: disabled || false, disabled: disabled || false,
}} }}
style={[ style={[
flatten(style),
a.flex_row, a.flex_row,
a.align_center, a.align_center,
a.justify_center, a.justify_center,
a.overflow_hidden,
a.justify_center, a.justify_center,
...baseStyles, flattenedBaseStyles,
...(state.hovered || state.pressed ? hoverStyles : []), ...(state.hovered || state.pressed ? hoverStyles : []),
...(state.focused ? focusStyles : []), ...(state.focused ? focusStyles : []),
flatten(style),
]} ]}
onPressIn={onPressIn} onPressIn={onPressIn}
onPressOut={onPressOut} onPressOut={onPressOut}
@ -379,21 +395,31 @@ export function Button({
onFocus={onFocus} onFocus={onFocus}
onBlur={onBlur}> onBlur={onBlur}>
{variant === 'gradient' && ( {variant === 'gradient' && (
<LinearGradient <View
colors={ style={[
state.hovered || state.pressed || state.focused a.absolute,
? gradientHoverColors a.inset_0,
: gradientColors a.overflow_hidden,
} {borderRadius: flattenedBaseStyles.borderRadius},
locations={gradientLocations} ]}>
start={{x: 0, y: 0}} <LinearGradient
end={{x: 1, y: 1}} colors={
style={[a.absolute, a.inset_0]} state.hovered || state.pressed || state.focused
/> ? gradientHoverColors
: gradientColors
}
locations={gradientLocations}
start={{x: 0, y: 0}}
end={{x: 1, y: 1}}
style={[a.absolute, a.inset_0]}
/>
</View>
)} )}
<Context.Provider value={context}> <Context.Provider value={context}>
{typeof children === 'string' ? ( {typeof children === 'string' ? (
<ButtonText>{children}</ButtonText> <ButtonText>{children}</ButtonText>
) : typeof children === 'function' ? (
children(context)
) : ( ) : (
children children
)} )}
@ -493,6 +519,8 @@ export function useSharedButtonTextStyles() {
if (size === 'large') { if (size === 'large') {
baseStyles.push(a.text_md, android({paddingBottom: 1})) baseStyles.push(a.text_md, android({paddingBottom: 1}))
} else if (size === 'tiny') {
baseStyles.push(a.text_xs, android({paddingBottom: 1}))
} else { } else {
baseStyles.push(a.text_sm, android({paddingBottom: 1})) baseStyles.push(a.text_sm, android({paddingBottom: 1}))
} }
@ -514,9 +542,11 @@ export function ButtonText({children, style, ...rest}: ButtonTextProps) {
export function ButtonIcon({ export function ButtonIcon({
icon: Comp, icon: Comp,
position, position,
size: iconSize,
}: { }: {
icon: React.ComponentType<SVGIconProps> icon: React.ComponentType<SVGIconProps>
position?: 'left' | 'right' position?: 'left' | 'right'
size?: SVGIconProps['size']
}) { }) {
const {size, disabled} = useButtonContext() const {size, disabled} = useButtonContext()
const textStyles = useSharedButtonTextStyles() const textStyles = useSharedButtonTextStyles()
@ -532,7 +562,9 @@ export function ButtonIcon({
}, },
]}> ]}>
<Comp <Comp
size={size === 'large' ? 'md' : 'sm'} size={
iconSize ?? (size === 'large' ? 'md' : size === 'tiny' ? 'xs' : 'sm')
}
style={[{color: textStyles.color, pointerEvents: 'none'}]} style={[{color: textStyles.color, pointerEvents: 'none'}]}
/> />
</View> </View>