import { dripStitches } from '../../../theme'; import { CSS } from '@stitches/react'; type StyledButtonProps = React.ComponentProps; export interface ButtonProps extends StyledButtonProps { /** * If `true`, the button will show a spinner. */ isLoading?: boolean; /** * If `true`, the button will be styled in its active state. */ isActive?: boolean; /** * If `true`, the button will be disabled. */ isDisabled?: boolean; /** * The label to show in the button when `isLoading` is true * If no text is passed, it only shows the spinner */ loadingText?: string; /** * If `true`, the button will take up the full width of its container. */ isFullWidth?: boolean; /** * The html button type to use. */ type?: 'button' | 'reset' | 'submit'; /** * If added, the button will show an icon before the button's label. * @type React.ReactElement */ leftIcon?: React.ReactElement; /** * If added, the button will show an icon after the button's label. * @type React.ReactElement */ rightIcon?: React.ReactElement; /** * If added, the button will show an icon on top side from the button's label. * @type React.ReactElement */ topIcon?: React.ReactElement; /** * If added, the button will show an icon on bottom side from the button's label. * @type React.ReactElement */ bottomIcon?: React.ReactElement; /** * The space between the button icon and label. * @type SystemProps["marginRight"] */ iconSpacing?: string; /** * Replace the spinner component when `isLoading` is set to `true` * @type React.ReactElement */ spinner?: React.ReactElement; /** * It determines the placement of the spinner when isLoading is true * @default "start" */ spinnerPlacement?: 'start' | 'end'; } export type ButtonColor = 'gray' | 'blue'; export type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'link'; export type GetButtonCompoundVariantOptions = { color?: ButtonColor; variant?: ButtonVariant; }; const getButtonCompoundVariant = ({ color = 'gray', variant = 'solid', }: GetButtonCompoundVariantOptions): CSS => { switch (variant) { case 'solid': return { color: 'white', transition: '$all-200', backgroundColor: `$${color}9`, '&:focus, &:hover': { backgroundColor: `$${color}10`, }, '&:focus, &:active': { backgroundColor: `$${color}11`, }, }; case 'outline': return { color: `$${color}11`, transition: '$all-200', backgroundColor: `$${color}4`, '&:hover': { backgroundColor: `$${color}5`, }, '&:focus, &:active': { backgroundColor: `$${color}6`, }, }; case 'link': return { color: `$${color}11`, transition: '$all-200', height: 'auto', px: '0', '&:hover, &:focus': { textDecoration: 'underline', color: `$${color}12`, '&:disabled': { textDecoration: 'none', }, }, }; case 'ghost': return { color: `$slate11`, transition: '$all-200', '&:hover, &:focus, &:active': { color: `$slate12`, }, '&:hover': { backgroundColor: `$${color}4`, }, '&:focus, &:active': { backgroundColor: `$${color}3`, }, '&:disabled': { backgroundColor: `initial`, '&:hover': { color: `$${color}11`, backgroundColor: `initial`, }, '& img, & svg': { filter: 'grayscale(100%)', }, }, }; default: return {}; } }; const { styled } = dripStitches; export const StyledButton = styled('button', { all: 'unset', cursor: 'pointer', position: 'relative', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'nowrap', verticalAlign: 'middle', userSelect: 'none', fontWeight: '$medium', '&:disabled': { cursor: 'not-allowed', opacity: '0.4', }, variants: { size: { sm: { borderRadius: '$md', fontSize: '$xs', p: '$1 $3', }, md: { borderRadius: '$lg', fontSize: '$sm', p: '$3 $3h', }, lg: { borderRadius: '$xl', fontSize: '$md', p: '$4 $5', }, }, variant: { solid: { color: '$gray1', }, ghost: {}, outline: {}, link: {}, unstyled: {}, }, colorScheme: { gray: {}, blue: {}, red: {}, }, }, compoundVariants: [ { colorScheme: 'gray', variant: 'solid', css: getButtonCompoundVariant({ color: 'gray', variant: 'solid' }), }, { colorScheme: 'blue', variant: 'solid', css: getButtonCompoundVariant({ color: 'blue', variant: 'solid' }), }, { colorScheme: 'gray', variant: 'outline', css: getButtonCompoundVariant({ color: 'gray', variant: 'outline' }), }, { colorScheme: 'blue', variant: 'outline', css: getButtonCompoundVariant({ color: 'blue', variant: 'outline' }), }, { colorScheme: 'gray', variant: 'ghost', css: getButtonCompoundVariant({ color: 'gray', variant: 'ghost' }), }, { colorScheme: 'blue', variant: 'ghost', css: getButtonCompoundVariant({ color: 'blue', variant: 'ghost' }), }, { colorScheme: 'gray', variant: 'link', css: getButtonCompoundVariant({ color: 'gray', variant: 'link' }), }, { colorScheme: 'blue', variant: 'link', css: getButtonCompoundVariant({ color: 'blue', variant: 'link' }), }, ], defaultVariants: { colorScheme: 'gray', variant: 'solid', size: 'md', }, });