diff options
author | Eric Bailey <git@esb.lol> | 2024-09-20 11:38:51 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-20 11:38:51 -0500 |
commit | 0eed1cfec1b0caac35930529dfd9ac92bf38606f (patch) | |
tree | c356b389bb5db2c5e531ec860b5a288bada4cbe6 /src/components/Button.tsx | |
parent | 27cceb96f33c86a06507a9ad3e631171474100b4 (diff) | |
download | voidsky-0eed1cfec1b0caac35930529dfd9ac92bf38606f.tar.zst |
[Neue] Buttons (#5406)
* Re-align button sizing (cherry picked from commit bcec243bb59dfe468313d98ba61f464d9750feec) * Use large, small, tiny (cherry picked from commit 1dc333c2993ab7f2e0ac750c0670dcec9a7069d0) * Tweaks
Diffstat (limited to 'src/components/Button.tsx')
-rw-r--r-- | src/components/Button.tsx | 148 |
1 files changed, 111 insertions, 37 deletions
diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 704aa9d98..8728b88c2 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -14,7 +14,7 @@ import { } from 'react-native' import {LinearGradient} from 'expo-linear-gradient' -import {android, atoms as a, flatten, select, tokens, useTheme} from '#/alf' +import {atoms as a, flatten, select, tokens, useTheme, web} from '#/alf' import {Props as SVGIconProps} from '#/components/icons/common' import {Text} from '#/components/Typography' @@ -30,7 +30,7 @@ export type ButtonColor = | 'gradient_sunset' | 'gradient_nordic' | 'gradient_bonfire' -export type ButtonSize = 'tiny' | 'xsmall' | 'small' | 'medium' | 'large' +export type ButtonSize = 'tiny' | 'small' | 'large' export type ButtonShape = 'round' | 'square' | 'default' export type VariantProps = { /** @@ -343,39 +343,46 @@ export const Button = React.forwardRef<View, ButtonProps>( if (shape === 'default') { if (size === 'large') { - baseStyles.push( - {paddingVertical: 15}, - a.px_2xl, - a.rounded_sm, - a.gap_md, - ) - } else if (size === 'medium') { - baseStyles.push( - {paddingVertical: 12}, - a.px_2xl, - a.rounded_sm, - a.gap_md, - ) + baseStyles.push({ + paddingVertical: 13, + paddingHorizontal: 20, + borderRadius: 8, + gap: 8, + }) } else if (size === 'small') { - baseStyles.push({paddingVertical: 9}, a.px_lg, a.rounded_sm, a.gap_sm) - } else if (size === 'xsmall') { - baseStyles.push({paddingVertical: 6}, a.px_sm, a.rounded_sm, a.gap_sm) + baseStyles.push({ + paddingVertical: 8, + paddingHorizontal: 12, + borderRadius: 6, + gap: 6, + }) } else if (size === 'tiny') { - baseStyles.push({paddingVertical: 4}, a.px_sm, a.rounded_xs, a.gap_xs) + baseStyles.push({ + paddingVertical: 4, + paddingHorizontal: 8, + borderRadius: 4, + gap: 4, + }) } } else if (shape === 'round' || shape === 'square') { if (size === 'large') { if (shape === 'round') { - baseStyles.push({height: 54, width: 54}) + baseStyles.push({height: 46, width: 46}) } else { - baseStyles.push({height: 50, width: 50}) + baseStyles.push({height: 44, width: 44}) } } else if (size === 'small') { - baseStyles.push({height: 34, width: 34}) - } else if (size === 'xsmall') { - baseStyles.push({height: 28, width: 28}) + if (shape === 'round') { + baseStyles.push({height: 36, width: 36}) + } else { + baseStyles.push({height: 34, width: 34}) + } } else if (size === 'tiny') { - baseStyles.push({height: 20, width: 20}) + if (shape === 'round') { + baseStyles.push({height: 22, width: 22}) + } else { + baseStyles.push({height: 21, width: 21}) + } } if (shape === 'round') { @@ -619,11 +626,11 @@ export function useSharedButtonTextStyles() { } if (size === 'large') { - baseStyles.push(a.text_md, android({paddingBottom: 1})) + baseStyles.push(a.text_md, a.leading_tight, web({paddingTop: 1})) + } else if (size === 'small') { + baseStyles.push(a.text_sm, a.leading_tight, web({paddingTop: 1})) } else if (size === 'tiny') { - baseStyles.push(a.text_xs, android({paddingBottom: 1})) - } else { - baseStyles.push(a.text_sm, android({paddingBottom: 1})) + baseStyles.push(a.text_xs, a.leading_tight) } return StyleSheet.flatten(baseStyles) @@ -643,31 +650,98 @@ export function ButtonText({children, style, ...rest}: ButtonTextProps) { export function ButtonIcon({ icon: Comp, position, - size: iconSize, + size, }: { icon: React.ComponentType<SVGIconProps> position?: 'left' | 'right' size?: SVGIconProps['size'] }) { - const {size, disabled} = useButtonContext() + const {size: buttonSize, disabled} = useButtonContext() const textStyles = useSharedButtonTextStyles() + const {iconSize, iconContainerSize} = React.useMemo(() => { + /** + * Pre-set icon sizes for different button sizes + */ + const iconSizeShorthand = + size ?? + (({ + large: 'sm', + small: 'xs', + tiny: 'xs', + }[buttonSize || 'small'] || 'sm') as Exclude< + SVGIconProps['size'], + undefined + >) + + /* + * Copied here from icons/common.tsx so we can tweak if we need to, but + * also so that we can calculate transforms. + */ + const iconSize = { + xs: 12, + sm: 16, + md: 20, + lg: 24, + xl: 28, + '2xl': 32, + }[iconSizeShorthand] + + /* + * Goal here is to match rendered text size so that different size icons + * don't increase button size + */ + const iconContainerSize = { + large: 18, + small: 16, + tiny: 13, + }[buttonSize || 'small'] + + return { + iconSize, + iconContainerSize, + } + }, [buttonSize, size]) return ( <View style={[ a.z_20, { + width: iconContainerSize, + height: iconContainerSize, opacity: disabled ? 0.7 : 1, marginLeft: position === 'left' ? -2 : 0, marginRight: position === 'right' ? -2 : 0, }, ]}> - <Comp - size={ - iconSize ?? (size === 'large' ? 'md' : size === 'tiny' ? 'xs' : 'sm') - } - style={[{color: textStyles.color, pointerEvents: 'none'}]} - /> + <View + style={[ + a.absolute, + { + width: iconSize, + height: iconSize, + top: '50%', + left: '50%', + transform: [ + { + translateX: (iconSize / 2) * -1, + }, + { + translateY: (iconSize / 2) * -1, + }, + ], + }, + ]}> + <Comp + width={iconSize} + style={[ + { + color: textStyles.color, + pointerEvents: 'none', + }, + ]} + /> + </View> </View> ) } |