import { cva } from 'class-variance-authority'
import * as React from 'react'
import { widthClasses } from '../styles'
import type { ButtonProps, IconNames } from '../types'
import { camelToPascal, cn } from '../utils'
import { Icon as UiIcon } from './icon'
import { Tooltip, TooltipContent, TooltipTrigger } from './tooltip'
const buttonVariants = cva(
'border rounded-default transition-all cursor-pointer justify-center inline-flex gap-1 items-center whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none',
{
compoundVariants: [
{
arrangement: 'leadingLabel',
className: 'px-2'
},
{
arrangement: 'leadingIcon',
className: 'px-2'
},
{
arrangement: 'hiddenLabel',
className: 'h-6 w-6 text-sm',
size: 'sm'
},
{
arrangement: 'hiddenLabel',
className: 'h-9 w-9 text-sm',
size: 'md'
},
{
arrangement: 'hiddenLabel',
className: 'h-12 w-12',
size: 'lg'
}
],
defaultVariants: {
arrangement: 'leadingLabel',
size: 'md',
variant: 'primary'
},
variants: {
arrangement: {
hiddenLabel: '',
leadingIcon: '',
leadingLabel: ''
},
size: {
lg: 'h-12',
md: 'h-9 text-sm',
sm: 'h-6 text-sm'
},
variant: {
destructive:
'bg-destructive/20 text-destructive/80 border-destructive hover:text-destructive/100 hover:bg-destructive/40',
ghost: 'bg-transparent border-transparent hover:border-accent hover:bg-accent',
outline: 'bg-background hover:bg-accent',
primary: 'bg-primary hover:bg-primary/90 text-background dark:text-foreground border-primary',
secondary: 'bg-accent hover:bg-hover'
}
}
}
)
interface ButtonContentProps {
iconName: IconNames | null
arrangement: ButtonProps['arrangement']
children: React.ReactNode
}
const ButtonContent = ({ arrangement, iconName, children }: ButtonContentProps) => (
<>
{iconName && arrangement === 'leadingIcon' && (
)}
{arrangement !== 'hiddenLabel' && children}
{iconName && arrangement === 'leadingLabel' && (
)}
{iconName && arrangement === 'hiddenLabel' && (
)}
>
)
type ButtonRef = HTMLButtonElement | HTMLAnchorElement
const Button = React.forwardRef(
(
{
type = 'button',
onClick,
disabled = false,
label,
href,
variant = 'secondary',
size = 'md',
width = 'fit',
arrangement = 'leadingLabel',
icon,
onMouseEnter,
onMouseLeave,
className
},
ref
) => {
const iconName = icon ? (camelToPascal(icon) as IconNames) : null
const buttonContent = (
{label}
)
const buttonElement = href ? (
}
href={href}
className={cn(
'no-underline',
buttonVariants({ arrangement, size, variant }),
arrangement !== 'hiddenLabel' && widthClasses[width], // TODO: clean up
className
)}
>
{buttonContent}
) : (
)
if (arrangement === 'hiddenLabel') {
return (
{buttonElement}
{label}
)
}
return buttonElement
}
)
Button.displayName = 'Button'
export { Button, buttonVariants }