import React, { forwardRef } from "react"; import { motion, HTMLMotionProps } from "framer-motion"; import { Loader2, Plus, ArrowRight, Trash2, Settings } from "lucide-react"; // Types & Interfaces export type ButtonVariant = "primary" | "secondary" | "ghost" | "destructive" | "outline"; export type ButtonSize = "sm" | "md" | "lg"; export interface ButtonProps extends Omit, "children"> { variant?: ButtonVariant; size?: ButtonSize; isLoading?: boolean; leftIcon?: React.ReactNode; rightIcon?: React.ReactNode; fullWidth?: boolean; children?: React.ReactNode; } // Spring physics configuration for tactile feedback const springTransition = { type: "spring", stiffness: 400, damping: 25, }; // Variant class mappings adhering to WCAG 2.1 AA 4.5:1 contrast const variantClasses: Record = { primary: "bg-indigo-600 text-white hover:bg-indigo-700 active:bg-indigo-800 dark:bg-indigo-500 dark:hover:bg-indigo-600 focus-visible:ring-indigo-500", secondary: "bg-slate-100 text-slate-900 hover:bg-slate-200 active:bg-slate-300 dark:bg-slate-800 dark:text-slate-100 dark:hover:bg-slate-700 focus-visible:ring-slate-400", ghost: "bg-transparent text-slate-700 hover:bg-slate-100 active:bg-slate-200 dark:text-slate-300 dark:hover:bg-slate-800 focus-visible:ring-slate-400", destructive: "bg-red-600 text-white hover:bg-red-700 active:bg-red-800 dark:bg-red-500 dark:hover:bg-red-600 focus-visible:ring-red-500", outline: "bg-transparent text-slate-800 border border-slate-300 hover:bg-slate-50 active:bg-slate-100 dark:text-slate-200 dark:border-slate-700 dark:hover:bg-slate-800 focus-visible:ring-indigo-500", }; // Size scale following 8pt spatial grid const sizeClasses: Record = { sm: "h-8 px-3 text-xs gap-1.5 rounded-md", md: "h-10 px-4 text-sm gap-2 rounded-lg", lg: "h-12 px-6 text-base gap-2.5 rounded-xl", }; export const Button = forwardRef( ( { variant = "primary", size = "md", isLoading = false, isDisabled = false, leftIcon, rightIcon, fullWidth = false, children, className = "", disabled, ...props }, ref ) => { const isEffectivelyDisabled = isDisabled || disabled || isLoading; return ( {isLoading ? ( ); } ); Button.displayName = "Button"; // Example Showcase Component for documentation/testing export default function ButtonVariantsExample() { const [loadingState, setLoadingState] = React.useState(false); const toggleLoading = () => { setLoadingState(true); setTimeout(() => setLoadingState(false), 2000); }; return (

Button Variants & Interaction States

Accessible, spring-animated button primitives with micro-interactions.

{/* Main Variants */}

Variants

{/* Sizes */}

Sizes & Icons

{/* States */}

Interactive States

); }