import { forwardRef, type ButtonHTMLAttributes, type ReactNode } from "react"; // Minimal className joiner (no runtime dep). Falsy values are dropped. function cx(...parts: Array): string { return parts.filter(Boolean).join(" "); } type Variant = "primary" | "secondary" | "ghost" | "destructive"; type Size = "sm" | "md" | "lg"; export interface ButtonProps extends ButtonHTMLAttributes { variant?: Variant; size?: Size; /** Shows a spinner, sets aria-busy, and blocks interaction. Width stays fixed. */ loading?: boolean; /** Optional leading icon (hidden while loading). */ leadingIcon?: ReactNode; } const base = "relative inline-flex items-center justify-center gap-2 rounded-lg font-medium " + "select-none whitespace-nowrap transition-[transform,opacity,background-color,border-color] " + "duration-150 ease-out active:scale-[0.98] active:duration-75 active:ease-in " + "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 " + "focus-visible:ring-offset-white dark:focus-visible:ring-offset-neutral-950 " + "disabled:cursor-not-allowed disabled:opacity-50 " + "motion-reduce:transition-none motion-reduce:active:scale-100"; const variants: Record = { primary: "bg-indigo-600 text-white hover:bg-indigo-700 focus-visible:ring-indigo-600 " + "disabled:hover:bg-indigo-600", secondary: "border border-neutral-300 bg-white text-neutral-900 hover:bg-neutral-50 " + "focus-visible:ring-neutral-500 dark:border-neutral-700 dark:bg-neutral-900 " + "dark:text-neutral-100 dark:hover:bg-neutral-800", ghost: "text-neutral-700 hover:bg-neutral-100 focus-visible:ring-neutral-500 " + "dark:text-neutral-200 dark:hover:bg-neutral-800", destructive: "bg-red-600 text-white hover:bg-red-700 focus-visible:ring-red-600 " + "disabled:hover:bg-red-600", }; // md is 44px (h-11) to satisfy the ≥44px touch target as the default. const sizes: Record = { sm: "h-8 px-3 text-sm", md: "h-11 px-4 text-sm", lg: "h-[52px] px-6 text-base", }; const Spinner = () => ( ); export const Button = forwardRef(function Button( { variant = "secondary", size = "md", loading = false, leadingIcon, type = "button", disabled, className, children, ...rest }, ref ) { const isDisabled = disabled || loading; return ( ); });