148 lines
5.3 KiB
TypeScript
148 lines
5.3 KiB
TypeScript
import type { ButtonProps as AriaButtonProps } from 'react-aria-components';
|
|
import { Button as AriaButton, composeRenderProps } from 'react-aria-components';
|
|
|
|
import { tv } from 'tailwind-variants';
|
|
import { LoadingSpinnerIcon } from '../icons/LoadingSpinner';
|
|
|
|
export interface ButtonProps extends AriaButtonProps {
|
|
color?: 'primary' | 'light' | 'green' | 'lightGreen' | 'black' | 'gray' | 'orange' | 'navy' | 'lightNavy';
|
|
size?: 'small' | 'medium' | 'large';
|
|
stopPropagation?: boolean;
|
|
}
|
|
|
|
const button = tv({
|
|
base: 'relative inline-flex items-center justify-center gap-2 border cursor-pointer box-border data-focus-visible:ring-2 ring-offset-2',
|
|
variants: {
|
|
size: {
|
|
small: 'h-6 px-3 text-xs font-medium',
|
|
medium: 'h-9 px-3 text-xs font-medium',
|
|
large: 'min-w-30 h-13 px-5 text-sm font-semibold',
|
|
},
|
|
color: {
|
|
primary: 'text-white bg-primary border-primary disabled:bg-kc-gray-be disabled:border-kc-gray-be ring-primary',
|
|
light:
|
|
'text-primary border-primary bg-primary-tertiary02 disabled:text-kc-gray-99 disabled:bg-kc-gray-eb disabled:border-kc-gray-be ring-primary',
|
|
green:
|
|
'text-white bg-kc-green-main border-kc-green-main disabled:bg-kc-gray-be disabled:border-kc-gray-be ring-kc-green-main',
|
|
lightGreen:
|
|
'text-kc-green-main border-kc-green-main bg-kc-green-tertiary02 disabled:text-kc-gray-99 disabled:bg-kc-gray-eb disabled:border-kc-gray-be ring-kc-green-main',
|
|
black:
|
|
'text-white bg-kc-black-34 border-kc-black-34 disabled:bg-kc-gray-be disabled:border-kc-gray-be ring-kc-black-34',
|
|
gray: 'text-kc-black-34 bg-kc-gray-eb border-kc-black-34 disabled:text-kc-gray-99 disabled:bg-kc-gray-eb disabled:border-kc-gray-be ring-kc-black-34',
|
|
orange:
|
|
'text-kc-orange-main bg-kc-orange-tertiary01 border-kc-orange-main disabled:text-kc-gray-99 disabled:bg-kc-gray-eb disabled:border-kc-gray-be ring-kc-orange-main',
|
|
navy: 'text-white bg-kc-navy-main border-kc-navy-main disabled:bg-kc-gray-be disabled:border-kc-gray-be ring-kc-navy-main',
|
|
lightNavy:
|
|
'text-kc-navy-main border-kc-navy-main bg-kc-navy-tertiary02 disabled:text-kc-gray-99 disabled:bg-kc-gray-eb disabled:border-kc-gray-be ring-kc-navy-main',
|
|
},
|
|
isDisabled: {
|
|
true: 'cursor-not-allowed',
|
|
},
|
|
isPending: {
|
|
true: 'text-transparent cursor-progress',
|
|
},
|
|
},
|
|
compoundVariants: [
|
|
{
|
|
color: 'primary',
|
|
isDisabled: false,
|
|
isPending: false,
|
|
className:
|
|
'hover:border-primary-tertiary hover:bg-primary-tertiary active:bg-primary-secondary active:border-primary-secondary',
|
|
},
|
|
{
|
|
color: 'light',
|
|
isDisabled: false,
|
|
isPending: false,
|
|
className:
|
|
'hover:bg-primary-tertiary01 active:text-primary-secondary active:bg-primary-tertiary01 active:border-primary-secondary',
|
|
},
|
|
{
|
|
color: 'green',
|
|
isDisabled: false,
|
|
isPending: false,
|
|
className:
|
|
'hover:bg-kc-green-tertiary hover:border-kc-green-tertiary active:bg-kc-green-secondary active:border-kc-green-secondary',
|
|
},
|
|
{
|
|
color: 'lightGreen',
|
|
isDisabled: false,
|
|
isPending: false,
|
|
className:
|
|
'hover:bg-kc-green-tertiary01 active:text-kc-green-secondary active:bg-kc-green-tertiary01 active:border-kc-green-secondary',
|
|
},
|
|
{
|
|
color: 'black',
|
|
isDisabled: false,
|
|
isPending: false,
|
|
className: 'hover:bg-kc-black-47 hover:border-kc-black-47 active:bg-kc-black-22 active:border-kc-black-22',
|
|
},
|
|
{
|
|
color: 'gray',
|
|
isDisabled: false,
|
|
isPending: false,
|
|
className:
|
|
'hover:bg-kc-gray-da hover:border-kc-black-47 active:text-kc-black-22 active:bg-kc-gray-da active:border-kc-black-22',
|
|
},
|
|
{
|
|
color: 'orange',
|
|
isDisabled: false,
|
|
isPending: false,
|
|
className:
|
|
'hover:bg-kc-orange-tertiary02 active:text-kc-orange-secondary active:bg-kc-orange-tertiary02 active:border-kc-orange-secondary',
|
|
},
|
|
{
|
|
color: 'navy',
|
|
isDisabled: false,
|
|
isPending: false,
|
|
className:
|
|
'hover:border-kc-navy-tertiary hover:bg-kc-navy-tertiary active:bg-kc-navy-secondary active:border-kc-navy-secondary',
|
|
},
|
|
{
|
|
color: 'lightNavy',
|
|
isDisabled: false,
|
|
isPending: false,
|
|
className:
|
|
'hover:bg-kc-navy-tertiary01 active:text-kc-navy-secondary active:bg-kc-navy-tertiary01 active:border-kc-navy-secondary',
|
|
},
|
|
],
|
|
});
|
|
|
|
export const Button = (props: ButtonProps) => {
|
|
const {
|
|
className,
|
|
onClick,
|
|
color = 'primary',
|
|
size = 'medium',
|
|
children,
|
|
stopPropagation = false,
|
|
...restProps
|
|
} = props;
|
|
|
|
return (
|
|
<AriaButton
|
|
className={composeRenderProps(className, (className, renderProps) => {
|
|
return button({ ...renderProps, color, size, className });
|
|
})}
|
|
onClick={(e) => {
|
|
if (stopPropagation) {
|
|
e.stopPropagation();
|
|
}
|
|
onClick?.(e);
|
|
}}
|
|
{...restProps}
|
|
>
|
|
{composeRenderProps(children, (children, { isPending }) => (
|
|
<>
|
|
{children}
|
|
{isPending && (
|
|
<span aria-hidden className="flex absolute inset-0 justify-center items-center">
|
|
<LoadingSpinnerIcon className="w-4 h-4 text-white animate-spin" />
|
|
</span>
|
|
)}
|
|
</>
|
|
))}
|
|
</AriaButton>
|
|
);
|
|
};
|