import { type ReactElement, type ComponentProps, forwardRef } from "react"; import { cva, type VariantProps } from "class-variance-authority"; import { Loader2 } from "lucide-react"; import { cn } from "@/lib/utils"; import { Slot } from "@/lib/slot"; /** * Button — WealthX Design System * Figma: https://www.figma.com/design/9V9F0NGVsif8LGmEhVjOcT/Design-System---shadcn?node-id=72-2719 * * Base: official shadcn new-york button (npx shadcn\@latest add button) * WealthX overrides: variants, square corners, font-sans, loading state */ const buttonVariants = cva( "inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 font-sans text-button whitespace-nowrap transition-all active:scale-[0.98] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", { variants: { variant: { default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", secondary: "bg-brand-secondary text-brand-secondary-foreground shadow-xs hover:bg-brand-secondary/80 focus-visible:ring-brand-secondary/30", destructive: "bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40", outline: "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground focus-visible:border-border focus-visible:ring-border/50 dark:bg-input/30 dark:border-input dark:hover:bg-input/50", "outline-primary": "border border-primary text-foreground bg-transparent shadow-xs hover:bg-primary/5 focus-visible:ring-primary/50", "outline-secondary": "border border-brand-secondary text-brand-secondary bg-transparent shadow-xs hover:bg-brand-secondary/10 focus-visible:border-brand-secondary focus-visible:ring-brand-secondary/30", ghost: "hover:bg-accent hover:text-accent-foreground hover:shadow-xs focus-visible:ring-border/50 dark:hover:bg-accent/50", link: "text-primary underline-offset-4 hover:underline", }, size: { default: "h-9 px-4 py-2 has-[>svg]:px-3", xs: "h-6 gap-1 px-2 text-button-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3", sm: "h-8 gap-1.5 px-3 has-[>svg]:px-2.5", lg: "h-10 px-6 has-[>svg]:px-4", icon: "size-9", "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3", "icon-sm": "size-8", "icon-lg": "size-10", }, }, defaultVariants: { variant: "default", size: "default", }, }, ); export type ButtonProps = ComponentProps<"button"> & VariantProps & { asChild?: boolean; /** Shows spinner and disables the button. Icon-only sizes hide the icon. */ loading?: boolean; }; const Button = forwardRef(function Button( { className, variant, size, asChild = false, loading = false, disabled, type = "button", children, ...props }, ref, ): ReactElement { const Comp = asChild ? Slot : "button"; const isIconOnly = size === "icon" || size === "icon-xs" || size === "icon-sm" || size === "icon-lg"; return ( {loading ? ( <> ); }); export { Button, buttonVariants };