'use client' import { Slot } from '@radix-ui/react-slot' import { cva } from 'class-variance-authority' import type * as React from 'react' import { cn } from '../../utils/cn' import { typographyVariants } from '../Typography' import { LoadingRing } from './LoadingRing' export const sizeVariants = { default: cn( 'max-h-12 min-h-12 px-6 py-3.5 [&_svg]:size-4', typographyVariants({ variant: 'body-semi-s' }), ), sm: cn( 'max-h-10 min-h-10 px-6 py-3 [&_svg]:size-3', typographyVariants({ variant: 'body-semi-xs' }), ), xs: cn( 'max-h-8 min-h-8 px-4 py-2 [&_svg]:size-3', typographyVariants({ variant: 'body-semi-xs' }), ), none: cn( 'w-none min-w-0 max-w-none', typographyVariants({ variant: 'body-semi-s' }), ), } as const export const widthVariants = { responsive: 'w-full md:w-fit', hug: 'w-fit', full: 'w-full', } as const export const visualVariants = { primary: cn(`bg-primary text-primary-foreground hover:bg-primary-hover`), secondary: cn( `border border-solid border-secondary-border bg-secondary text-secondary-foreground hover:border-secondary-border-hover`, ), tertiary: cn( `border border-solid border-tertiary-border bg-tertiary text-tertiary-foreground hover:border-tertiary-border-hover`, ), destructive: cn( `bg-destructive text-destructive-foreground hover:bg-destructive-hover`, ), ghost: cn(`bg-ghost text-ghost-foreground hover:bg-ghost-hover`), } as const const buttonVariants = cva( cn( 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded transition-colors duration-100 ease-linear focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:text-current', ), { variants: { size: sizeVariants, width: widthVariants, loading: { true: 'pointer-events-none', false: '', }, variant: visualVariants, }, compoundVariants: [ { variant: 'primary', loading: true, className: cn('bg-primary-disabled text-primary-foreground'), }, { variant: 'secondary', loading: true, className: cn( 'border-secondary-border-disabled text-secondary-foreground', ), }, { variant: 'tertiary', loading: true, className: cn( 'border-tertiary-border-disabled text-tertiary-foreground', ), }, { variant: 'ghost', loading: true, className: cn('bg-ghost-disabled text-ghost-foreground'), }, { variant: 'destructive', loading: true, className: cn('bg-destructive-disabled text-destructive-foreground'), }, { variant: 'primary', loading: false, className: 'disabled:bg-primary-disabled disabled:text-primary-disabled-foreground', }, { variant: 'secondary', loading: false, className: 'disabled:border-secondary-border-disabled disabled:text-secondary-disabled-foreground', }, { variant: 'tertiary', loading: false, className: 'disabled:border-tertiary-border-disabled disabled:text-tertiary-disabled-foreground', }, { variant: 'ghost', loading: false, className: 'disabled:bg-ghost-disabled disabled:text-ghost-disabled-foreground', }, { variant: 'destructive', loading: false, className: 'disabled:bg-destructive-disabled disabled:text-destructive-disabled-foreground', }, { size: 'default', loading: true, className: '[&_svg]:size-6', }, { size: 'sm', loading: true, className: '[&_svg]:size-5', }, { size: 'xs', loading: true, className: '[&_svg]:size-4', }, // min-widths for standalone buttons (max-width handled by ButtonSet) { width: 'hug', size: 'default', className: 'min-w-[120px]', }, { width: 'responsive', size: 'default', className: 'md:min-w-[120px]', }, { width: 'hug', size: 'sm', className: 'min-w-[96px]', }, { width: 'responsive', size: 'sm', className: 'md:min-w-[96px]', }, { width: 'hug', size: 'xs', className: 'min-w-[72px]', }, { width: 'responsive', size: 'xs', className: 'md:min-w-[72px]', }, // size-based loading svg size variants { size: 'default', loading: true, className: '[&_svg]:size-6', }, { size: 'sm', loading: true, className: '[&_svg]:size-5', }, { size: 'xs', loading: true, className: '[&_svg]:size-4', }, ], defaultVariants: { variant: 'primary', size: 'default', loading: false, width: 'responsive', }, }, ) export type ButtonVariant = keyof typeof visualVariants export type ButtonSize = Exclude export type ButtonWidth = keyof typeof widthVariants export type ButtonStyleProps = { /** Controls the visual hierarchy of the button. */ variant?: ButtonVariant /** Controls the height, padding, and typography density of the button. */ size?: ButtonSize /** * Width behavior of the button. * - `responsive` (default): full width on mobile, hugs content on desktop. * - `hug`: always fits content width. * - `full`: always fills the container. */ width?: ButtonWidth } /** * Button supports all native `