Spaces:
Paused
Paused
| import { cva, VariantProps } from 'class-variance-authority'; | |
| import * as React from 'react'; | |
| import { cn, ComponentAnatomy, defineStyleAnatomy } from '../core/styling'; | |
| /* ------------------------------------------------------------------------------------------------- | |
| * Anatomy | |
| * -----------------------------------------------------------------------------------------------*/ | |
| export const ButtonAnatomy = defineStyleAnatomy({ | |
| root: cva( | |
| [ | |
| 'UI-Button_root', | |
| 'shadow-sm whitespace-nowrap font-semibold rounded-[--radius]', | |
| 'inline-flex items-center text-white transition ease-in text-center text-base justify-center', | |
| 'focus-visible:outline-none focus-visible:ring-2 ring-offset-1 ring-offset-[--background] focus-visible:ring-[--ring]', | |
| 'disabled:opacity-50 disabled:pointer-events-none', | |
| ], | |
| { | |
| variants: { | |
| intent: { | |
| primary: | |
| 'bg-brand-500 hover:bg-brand-600 active:bg-brand-700 border border-transparent', | |
| 'primary-outline': | |
| 'text-[--brand] border border-[--brand] bg-transparent hover:bg-brand-500 active:bg-brand-600 active:border-transparent hover:text-white dark:hover:border-brand-500 dark:active:bg-brand-600 dark:hover:text-white dark:active:border-transparent dark:active:text-white', | |
| 'primary-subtle': | |
| 'shadow-none text-[--brand] border bg-brand-50 border-transparent hover:bg-brand-100 active:bg-brand-200 dark:bg-opacity-10 dark:hover:bg-opacity-20', | |
| 'primary-link': | |
| 'shadow-none text-[--brand] border border-transparent bg-transparent hover:underline active:text-brand-700 dark:active:text-brand-300', | |
| 'primary-basic': | |
| 'shadow-none text-[--brand] border border-transparent bg-transparent hover:bg-brand-100 active:bg-brand-200 dark:hover:bg-opacity-10 dark:active:text-brand-300', | |
| warning: | |
| 'bg-orange-500 hover:bg-orange-600 active:bg-orange-700 border border-transparent', | |
| 'warning-outline': | |
| 'text-[--orange] border border-[--orange] bg-transparent hover:bg-orange-500 active:bg-orange-600 active:border-transparent hover:text-white dark:hover:border-orange-500 dark:active:bg-orange-600 dark:hover:text-white dark:active:border-transparent dark:active:text-white', | |
| 'warning-subtle': | |
| 'shadow-none text-[--orange] border bg-orange-50 border-transparent hover:bg-orange-100 active:bg-orange-200 dark:bg-opacity-10 dark:hover:bg-opacity-20', | |
| 'warning-link': | |
| 'shadow-none text-[--orange] border border-transparent bg-transparent hover:underline active:text-orange-700 dark:active:text-orange-300', | |
| 'warning-basic': | |
| 'shadow-none text-[--orange] border border-transparent bg-transparent hover:bg-orange-100 active:bg-orange-200 dark:hover:bg-opacity-10 dark:active:text-orange-300', | |
| success: | |
| 'bg-green-500 hover:bg-green-600 active:bg-green-700 border border-transparent', | |
| 'success-outline': | |
| 'text-[--green] border border-[--green] bg-transparent hover:bg-green-500 active:bg-green-600 active:border-transparent hover:text-white dark:hover:border-green-500 dark:active:bg-green-600 dark:hover:text-white dark:active:border-transparent dark:active:text-white', | |
| 'success-subtle': | |
| 'shadow-none text-[--green] border bg-green-50 border-transparent hover:bg-green-100 active:bg-green-200 dark:bg-opacity-10 dark:hover:bg-opacity-20', | |
| 'success-link': | |
| 'shadow-none text-[--green] border border-transparent bg-transparent hover:underline active:text-green-700 dark:active:text-green-300', | |
| 'success-basic': | |
| 'shadow-none text-[--green] border border-transparent bg-transparent hover:bg-green-100 active:bg-green-200 dark:hover:bg-opacity-10 dark:active:text-green-300', | |
| alert: | |
| 'bg-red-500 hover:bg-red-600 active:bg-red-700 border border-transparent', | |
| 'alert-outline': | |
| 'text-[--red] border border-[--red] bg-transparent hover:bg-red-500 active:bg-red-600 active:border-transparent hover:text-white dark:hover:border-red-500 dark:active:bg-red-600 dark:hover:text-white dark:active:border-transparent dark:active:text-white', | |
| 'alert-subtle': | |
| 'shadow-none text-[--red] border bg-red-50 border-transparent hover:bg-red-100 active:bg-red-200 dark:bg-opacity-10 dark:hover:bg-opacity-20', | |
| 'alert-link': | |
| 'shadow-none text-[--red] border border-transparent bg-transparent hover:underline active:text-red-700 dark:active:text-red-300', | |
| 'alert-basic': | |
| 'shadow-none text-[--red] border border-transparent bg-transparent hover:bg-red-100 active:bg-red-200 dark:hover:bg-opacity-10 dark:active:text-red-300', | |
| gray: 'bg-gray-500 hover:bg-gray-600 active:bg-gray-700 border border-transparent', | |
| 'gray-outline': | |
| 'text-gray-600 border bg-transparent hover:bg-gray-100 active:border-transparent active:bg-gray-200 dark:text-gray-300 dark: dark:hover:bg-gray-800 dark:hover:bg-opacity-50 dark:active:bg-gray-700 dark:active:border-transparent dark:hover:text-gray-100', | |
| 'gray-subtle': | |
| 'shadow-none text-[--gray] border bg-gray-100 border-transparent hover:bg-gray-200 active:bg-gray-300 dark:text-gray-300 dark:bg-opacity-10 dark:hover:bg-opacity-20', | |
| 'gray-link': | |
| 'shadow-none text-[--gray] border border-transparent bg-transparent hover:underline active:text-gray-700 dark:text-gray-300 dark:active:text-gray-200', | |
| 'gray-basic': | |
| 'shadow-none text-[--gray] border border-transparent bg-transparent hover:bg-gray-100 active:bg-gray-200 dark:active:bg-opacity-20 dark:text-gray-200 dark:hover:bg-opacity-10 dark:active:text-gray-200', | |
| white: | |
| 'text-[#000] bg-white hover:bg-gray-200 active:bg-gray-300 border border-transparent', | |
| 'white-outline': | |
| 'text-white border border-gray-200 bg-transparent hover:bg-white hover:text-black active:bg-gray-100 active:text-[#000]', | |
| 'white-subtle': | |
| 'shadow-none text-white bg-white bg-opacity-15 hover:bg-opacity-20 border border-transparent active:bg-opacity-25', | |
| 'white-link': | |
| 'shadow-none text-white border border-transparent bg-transparent hover:underline active:text-gray-200', | |
| 'white-basic': | |
| 'shadow-none text-white border border-transparent bg-transparent hover:bg-white hover:bg-opacity-15 active:bg-opacity-20 active:text-white-300', | |
| }, | |
| rounded: { | |
| true: 'rounded-full', | |
| false: null, | |
| }, | |
| contentWidth: { | |
| true: 'w-fit', | |
| false: null, | |
| }, | |
| size: { | |
| xs: 'text-sm h-6 px-2', | |
| sm: 'text-sm h-8 px-3', | |
| md: 'text-sm h-10 px-4', | |
| lg: 'h-12 px-6 text-lg', | |
| xl: 'text-2xl h-14 px-8', | |
| }, | |
| }, | |
| defaultVariants: { | |
| intent: 'primary', | |
| size: 'md', | |
| }, | |
| } | |
| ), | |
| icon: cva(['UI-Button__icon', 'inline-flex self-center flex-shrink-0']), | |
| }); | |
| /* ------------------------------------------------------------------------------------------------- | |
| * Button | |
| * -----------------------------------------------------------------------------------------------*/ | |
| export type ButtonProps = React.ComponentPropsWithoutRef<'button'> & | |
| VariantProps<typeof ButtonAnatomy.root> & | |
| ComponentAnatomy<typeof ButtonAnatomy> & { | |
| loading?: boolean; | |
| leftIcon?: React.ReactNode; | |
| rightIcon?: React.ReactNode; | |
| iconSpacing?: React.CSSProperties['marginInline']; | |
| hideTextOnSmallScreen?: boolean; | |
| hideTextOnLargeScreen?: boolean; | |
| }; | |
| export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( | |
| (props, ref) => { | |
| const { | |
| children, | |
| size, | |
| className, | |
| rounded = false, | |
| contentWidth = false, | |
| intent, | |
| leftIcon, | |
| rightIcon, | |
| iconSpacing = '0.5rem', | |
| loading, | |
| iconClass, | |
| disabled, | |
| hideTextOnSmallScreen, | |
| hideTextOnLargeScreen, | |
| ...rest | |
| } = props; | |
| return ( | |
| <button | |
| type="button" | |
| className={cn( | |
| ButtonAnatomy.root({ | |
| size, | |
| intent, | |
| rounded, | |
| contentWidth, | |
| }), | |
| className | |
| )} | |
| disabled={disabled || loading} | |
| aria-disabled={disabled} | |
| {...rest} | |
| ref={ref} | |
| > | |
| {loading ? ( | |
| <> | |
| <svg | |
| width="15" | |
| height="15" | |
| fill="currentColor" | |
| className="animate-spin" | |
| viewBox="0 0 1792 1792" | |
| xmlns="http://www.w3.org/2000/svg" | |
| style={{ | |
| marginInlineEnd: !hideTextOnSmallScreen ? iconSpacing : 0, | |
| }} | |
| > | |
| <path d="M526 1394q0 53-37.5 90.5t-90.5 37.5q-52 0-90-38t-38-90q0-53 37.5-90.5t90.5-37.5 90.5 37.5 37.5 90.5zm498 206q0 53-37.5 90.5t-90.5 37.5-90.5-37.5-37.5-90.5 37.5-90.5 90.5-37.5 90.5 37.5 37.5 90.5zm-704-704q0 53-37.5 90.5t-90.5 37.5-90.5-37.5-37.5-90.5 37.5-90.5 90.5-37.5 90.5 37.5 37.5 90.5zm1202 498q0 52-38 90t-90 38q-53 0-90.5-37.5t-37.5-90.5 37.5-90.5 90.5-37.5 90.5 37.5 37.5 90.5zm-964-996q0 66-47 113t-113 47-113-47-47-113 47-113 113-47 113 47 47 113zm1170 498q0 53-37.5 90.5t-90.5 37.5-90.5-37.5-37.5-90.5 37.5-90.5 90.5-37.5 90.5 37.5 37.5 90.5zm-640-704q0 80-56 136t-136 56-136-56-56-136 56-136 136-56 136 56 56 136zm530 206q0 93-66 158.5t-158 65.5q-93 0-158.5-65.5t-65.5-158.5q0-92 65.5-158t158.5-66q92 0 158 66t66 158z"></path> | |
| </svg> | |
| {children} | |
| </> | |
| ) : ( | |
| <> | |
| {leftIcon && ( | |
| <span | |
| className={cn(ButtonAnatomy.icon(), iconClass)} | |
| style={{ | |
| marginInlineEnd: !hideTextOnSmallScreen ? iconSpacing : 0, | |
| }} | |
| > | |
| {leftIcon} | |
| </span> | |
| )} | |
| <span | |
| className={cn( | |
| hideTextOnSmallScreen && | |
| cn( | |
| 'hidden', | |
| leftIcon && 'pl-[0.5rem]', | |
| rightIcon && 'pr-[0.5rem]' | |
| ), | |
| hideTextOnLargeScreen | |
| ? 'inline-block lg:hidden' | |
| : 'md:inline-block' | |
| )} | |
| > | |
| {children} | |
| </span> | |
| {rightIcon && ( | |
| <span | |
| className={cn(ButtonAnatomy.icon(), iconClass)} | |
| style={{ | |
| marginInlineStart: !hideTextOnSmallScreen ? iconSpacing : 0, | |
| }} | |
| > | |
| {rightIcon} | |
| </span> | |
| )} | |
| </> | |
| )} | |
| </button> | |
| ); | |
| } | |
| ); | |
| Button.displayName = 'Button'; | |