diff options
author | Eric Bailey <git@esb.lol> | 2024-01-08 19:43:56 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-08 19:43:56 -0600 |
commit | a5b474895a27bb36381cca6a580dc19e4c4b10c2 (patch) | |
tree | 8540478dcd85cf095de50b8a8076a86a1ba28369 /src/view/com/Button.tsx | |
parent | 0ee0554b8632a9d32fa36ffa9fde8d719ab1527e (diff) | |
download | voidsky-a5b474895a27bb36381cca6a580dc19e4c4b10c2.tar.zst |
Application Layout Framework (#1732)
* Initial library setup * Add docblocks * Some cleanup * New storybook * Playing around * Remove silly test, use for...in * Memo * Memo * Add hooks example * Tweak colors, bit of cleanup * Improve macro handling * Add some more examples * Rename for better diff * Cleanup * Add nested context example * Add todo * Less break more perf * Buttons, you get the idea * Fix test * Remove temp colors * Add a few more common macros * Docs * Perf improvements * Alf go brrrr * Update breakpoint handling * I think it'll work * Better naming, better code * Fix typo * Some renaming * More complete pass at Tailwind naming * Build out storybook * Playing around with curves * Revert "Playing around with curves" This reverts commit 6b0e0e5c9d842a2d9af31b53affe2f6291c3fa0d. * Smooth brain * Remove outdated docs * Some docs, fix line-height values, export tokens
Diffstat (limited to 'src/view/com/Button.tsx')
-rw-r--r-- | src/view/com/Button.tsx | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/src/view/com/Button.tsx b/src/view/com/Button.tsx new file mode 100644 index 000000000..d1f70d4ae --- /dev/null +++ b/src/view/com/Button.tsx @@ -0,0 +1,204 @@ +import React from 'react' +import {Pressable, Text, PressableProps, TextProps} from 'react-native' +import * as tokens from '#/alf/tokens' +import {atoms} from '#/alf' + +export type ButtonType = + | 'primary' + | 'secondary' + | 'tertiary' + | 'positive' + | 'negative' +export type ButtonSize = 'small' | 'large' + +export type VariantProps = { + type?: ButtonType + size?: ButtonSize +} +type ButtonState = { + pressed: boolean + hovered: boolean + focused: boolean +} +export type ButtonProps = Omit<PressableProps, 'children'> & + VariantProps & { + children: + | ((props: { + state: ButtonState + type?: ButtonType + size?: ButtonSize + }) => React.ReactNode) + | React.ReactNode + | string + } +export type ButtonTextProps = TextProps & VariantProps + +export function Button({children, style, type, size, ...rest}: ButtonProps) { + const {baseStyles, hoverStyles} = React.useMemo(() => { + const baseStyles = [] + const hoverStyles = [] + + switch (type) { + case 'primary': + baseStyles.push({ + backgroundColor: tokens.color.blue_500, + }) + break + case 'secondary': + baseStyles.push({ + backgroundColor: tokens.color.gray_200, + }) + hoverStyles.push({ + backgroundColor: tokens.color.gray_100, + }) + break + default: + } + + switch (size) { + case 'large': + baseStyles.push( + atoms.py_md, + atoms.px_xl, + atoms.rounded_md, + atoms.gap_sm, + ) + break + case 'small': + baseStyles.push( + atoms.py_sm, + atoms.px_md, + atoms.rounded_sm, + atoms.gap_xs, + ) + break + default: + } + + return { + baseStyles, + hoverStyles, + } + }, [type, size]) + + const [state, setState] = React.useState({ + pressed: false, + hovered: false, + focused: false, + }) + + const onPressIn = React.useCallback(() => { + setState(s => ({ + ...s, + pressed: true, + })) + }, [setState]) + const onPressOut = React.useCallback(() => { + setState(s => ({ + ...s, + pressed: false, + })) + }, [setState]) + const onHoverIn = React.useCallback(() => { + setState(s => ({ + ...s, + hovered: true, + })) + }, [setState]) + const onHoverOut = React.useCallback(() => { + setState(s => ({ + ...s, + hovered: false, + })) + }, [setState]) + const onFocus = React.useCallback(() => { + setState(s => ({ + ...s, + focused: true, + })) + }, [setState]) + const onBlur = React.useCallback(() => { + setState(s => ({ + ...s, + focused: false, + })) + }, [setState]) + + return ( + <Pressable + {...rest} + style={state => [ + atoms.flex_row, + atoms.align_center, + ...baseStyles, + ...(state.hovered ? hoverStyles : []), + typeof style === 'function' ? style(state) : style, + ]} + onPressIn={onPressIn} + onPressOut={onPressOut} + onHoverIn={onHoverIn} + onHoverOut={onHoverOut} + onFocus={onFocus} + onBlur={onBlur}> + {typeof children === 'string' ? ( + <ButtonText type={type} size={size}> + {children} + </ButtonText> + ) : typeof children === 'function' ? ( + children({state, type, size}) + ) : ( + children + )} + </Pressable> + ) +} + +export function ButtonText({ + children, + style, + type, + size, + ...rest +}: ButtonTextProps) { + const textStyles = React.useMemo(() => { + const base = [] + + switch (type) { + case 'primary': + base.push({color: tokens.color.white}) + break + case 'secondary': + base.push({ + color: tokens.color.gray_700, + }) + break + default: + } + + switch (size) { + case 'small': + base.push(atoms.text_sm, {paddingBottom: 1}) + break + case 'large': + base.push(atoms.text_md, {paddingBottom: 1}) + break + default: + } + + return base + }, [type, size]) + + return ( + <Text + {...rest} + style={[ + atoms.flex_1, + atoms.font_semibold, + atoms.text_center, + ...textStyles, + style, + ]}> + {children} + </Text> + ) +} |