| 1 | import { type VariantProps, cva } from "class-variance-authority"; |
| 2 | import { Slot } from "radix-ui"; |
| 3 | import type { ComponentProps } from "react"; |
| 4 | |
| 5 | import { cn } from "../../lib/cn"; |
| 6 | |
| 7 | // shadcn/ui's button, styled with g1t's tokens. `asChild` puts its look on |
| 8 | // a <Link> or a menu's trigger. The older `Button` in ./index stays until |
| 9 | // its callers move here. |
| 10 | // |
| 11 | // Sizes: `default` 36px, `sm` 32px, `lg` 40px; the icon sizes are squares |
| 12 | // of the same. `bar` is the top bar's: 32px on a computer, 44px to a finger |
| 13 | // on a phone, and `icon-bar` its square. |
| 14 | |
| 15 | export const buttonVariants = cva( |
| 16 | "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap outline-none transition-[color,background-color,border-color,box-shadow] focus-visible:ring-2 focus-visible:ring-accent disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", |
| 17 | { |
| 18 | variants: { |
| 19 | variant: { |
| 20 | default: "bg-fg text-bg hover:bg-fg-hover", |
| 21 | accent: "bg-accent text-bg hover:bg-accent-hover", |
| 22 | outline: "border border-line bg-bg text-fg/90 hover:border-line-strong hover:bg-surface hover:text-fg", |
| 23 | secondary: "bg-raised text-fg hover:bg-raised/80", |
| 24 | ghost: "text-muted hover:bg-raised hover:text-fg data-[state=open]:bg-raised data-[state=open]:text-fg aria-pressed:bg-raised aria-pressed:text-fg", |
| 25 | // The accent as a wash: the one tinted control in a row, such as Ask g1t. |
| 26 | soft: "bg-accent/10 text-fg ring-1 ring-accent/20 ring-inset hover:bg-accent/15 hover:ring-accent/35", |
| 27 | destructive: "border border-danger/40 text-danger hover:border-danger hover:bg-danger/10", |
| 28 | link: "text-accent underline-offset-4 hover:underline", |
| 29 | }, |
| 30 | size: { |
| 31 | default: "h-9 px-3.5", |
| 32 | sm: "h-8 gap-1.5 px-2.5 text-[0.8125rem]", |
| 33 | lg: "h-10 px-5", |
| 34 | bar: "h-8 gap-1.5 px-2 text-[0.8125rem] max-md:h-11 max-md:min-w-11", |
| 35 | icon: "size-9", |
| 36 | "icon-sm": "size-8", |
| 37 | "icon-lg": "size-10", |
| 38 | "icon-bar": "size-8 max-md:size-11", |
| 39 | }, |
| 40 | }, |
| 41 | defaultVariants: { variant: "default", size: "default" }, |
| 42 | }, |
| 43 | ); |
| 44 | |
| 45 | export type ButtonProps = ComponentProps<"button"> & VariantProps<typeof buttonVariants> & { asChild?: boolean }; |
| 46 | |
| 47 | export function Button({ className, variant, size, asChild = false, ...props }: ButtonProps) { |
| 48 | const Comp = asChild ? Slot.Root : "button"; |
| 49 | return <Comp data-slot="button" className={cn(buttonVariants({ variant, size }), className)} {...props} />; |
| 50 | } |