import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode, } from 'react'; import { forwardRef } from 'react'; import classNames from 'classnames'; import type { IconName } from '../icon'; import { Icon } from '../icon'; import { includesLeftPadding, includesRightPadding, includesBorderWidth, includesHeight, } from '../../utils/class-names'; import classnames from 'classnames'; type Variant = 'primary' | 'secondary' | 'trade' | 'accent' | 'inline-link'; interface CommonProps { children?: ReactNode; variant?: Variant; className?: string; prependIconName?: IconName; appendIconName?: IconName; boxShadow?: boolean; } export interface ButtonProps extends ButtonHTMLAttributes, CommonProps {} export interface AnchorButtonProps extends AnchorHTMLAttributes, CommonProps {} export const getButtonClasses = ( className?: string, variant?: Variant, boxShadow?: boolean ) => { const paddingLeftProvided = includesLeftPadding(className); const paddingRightProvided = includesRightPadding(className); const borderWidthProvided = includesBorderWidth(className); const heightProvided = includesHeight(className); // Add classes into variables if there are multiple classes shared in multiple button styles const sharedClasses = 'inline-flex items-center justify-center box-border transition-[background-color] ease-linear duration-50 disabled:no-underline'; const commonButtonClasses = classnames( 'relative disabled:static', 'text-ui font-semibold focus-visible:outline-none border no-underline hover:no-underline', 'py-[3px]', { 'shadow-none': !boxShadow, 'shadow-[3px_3px_0_0] focus-visible:shadow-vega-pink dark:focus-visible:shadow-vega-yellow active:top-[1px] active:left-[1px] active:shadow-[2px_2px_0_0]': boxShadow === undefined || boxShadow, } ); const commonDisabled = 'disabled:bg-black-10 dark:disabled:bg-white-10 disabled:text-black-60 dark:disabled:text-white-60 disabled:border-black-25 dark:disabled:border-white-25 disabled:shadow-none dark:disabled:shadow-none'; const inlineTextColour = 'text-black-95 dark:text-white-95 hover:text-black hover:dark:text-white active:text-black dark:active:text-vega-yellow'; const standardButtonPaddingLeft = `${ paddingLeftProvided ? paddingLeftProvided : 'pl-28' }`; const standardButtonPaddingRight = `${ paddingRightProvided ? paddingRightProvided : 'pr-28' }`; const inlineButtonPaddingLeft = `${ paddingLeftProvided ? paddingLeftProvided : 'pl-4' }`; const inlineButtonPaddingRight = `${ paddingRightProvided ? paddingRightProvided : 'pr-4' }`; const standardButtonBorderWidth = `${ borderWidthProvided ? borderWidthProvided : 'border' }`; const buttonHeight = `${heightProvided ? heightProvided : ''}`; const primaryClasses = [ sharedClasses, commonButtonClasses, commonDisabled, standardButtonPaddingLeft, standardButtonPaddingRight, standardButtonBorderWidth, buttonHeight, 'bg-black dark:bg-white hover:bg-black-80 dark:hover:bg-white-90 active:bg-black-80 dark:active:bg-white-90', 'border-white dark:border-black shadow-black active:shadow-black dark:shadow-white-80 dark:active:shadow-white', 'text-white dark:text-black', ]; const secondaryClasses = [ sharedClasses, commonButtonClasses, commonDisabled, standardButtonPaddingLeft, standardButtonPaddingRight, standardButtonBorderWidth, buttonHeight, 'bg-white dark:bg-black hover:bg-black-25 dark:hover:bg-white-25', 'border-black dark:border-white shadow-black dark:shadow-white', 'text-black dark:text-white', ]; const tradeClasses = [ sharedClasses, commonButtonClasses, commonDisabled, standardButtonPaddingLeft, standardButtonPaddingRight, standardButtonBorderWidth, buttonHeight, 'bg-vega-green hover:bg-vega-green-medium', 'border-black disabled:shadow-none dark:disabled:shadow-none shadow-black dark:shadow-white', 'text-black', ]; const accentClasses = [ sharedClasses, commonDisabled, standardButtonPaddingLeft, standardButtonPaddingRight, standardButtonBorderWidth, buttonHeight, 'bg-vega-yellow dark:bg-vega-yellow hover:bg-vega-yellow-dark dark:hover:bg-vega-yellow-dark active:bg-white dark:active:bg-black', 'uppercase text-black dark:text-black hover:text-white dark:hover:text-white active:text-black dark:active:text-white', 'border-transparent dark:border-transparent', ]; const inlineLinkClasses = [ sharedClasses, inlineButtonPaddingLeft, inlineButtonPaddingRight, buttonHeight, inlineTextColour, 'underline hover:underline hover:text-black-60 dark:hover:text-white-80', 'border-none', ]; let variantClasses: string[]; switch (variant) { case 'primary': variantClasses = primaryClasses; break; case 'secondary': variantClasses = secondaryClasses; break; case 'trade': variantClasses = tradeClasses; break; case 'accent': variantClasses = accentClasses; break; case 'inline-link': variantClasses = inlineLinkClasses; break; default: variantClasses = ['']; } return classNames(...variantClasses, className); }; export const getButtonContent = ( children: ReactNode, prependIconName?: IconName, appendIconName?: IconName ) => { const iconName = prependIconName || appendIconName; if (iconName === undefined) { return children; } const iconClassName = classNames(['fill-current'], { 'mr-8': prependIconName, 'ml-8': appendIconName, }); const icon = ; return ( <> {prependIconName && icon} {children} {appendIconName && icon} ); }; export const Button = forwardRef( ( { variant = 'primary', type = 'button', children, className, prependIconName, appendIconName, boxShadow, ...props }, ref ) => { return ( ); } ); export const AnchorButton = forwardRef( ( { variant = 'primary', children, className, prependIconName, appendIconName, boxShadow, ...props }, ref ) => { return ( {getButtonContent(children, prependIconName, appendIconName)} ); } );