/** * Componentes atΓ΄micos β€” Receptor de className sempre no topo, * spread de props SEMPRE por ΓΊltimo. */ import { cn } from '../utils'; // ========================================================= // πŸ…± Button // ========================================================= type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger' | 'success'; type ButtonSize = 'sm' | 'md' | 'lg'; interface ButtonProps extends React.ButtonHTMLAttributes { variant?: ButtonVariant; size?: ButtonSize; loading?: boolean; leftIcon?: React.ReactNode; rightIcon?: React.ReactNode; } const variantStyles: Record = { primary: 'bg-indigo-600 text-white hover:bg-indigo-700 active:bg-indigo-800 disabled:bg-indigo-300', secondary: 'border border-gray-300 text-gray-700 bg-white hover:bg-gray-50 active:bg-gray-100', ghost: 'text-gray-600 hover:bg-gray-100 active:bg-gray-200', danger: 'bg-red-600 text-white hover:bg-red-700 active:bg-red-800', success: 'bg-emerald-600 text-white hover:bg-emerald-700 active:bg-emerald-800', }; const sizeStyles: Record = { sm: 'px-2.5 py-1 text-xs rounded', md: 'px-4 py-2 text-sm rounded-md', lg: 'px-6 py-3 text-base rounded-lg', }; export function Button({ className, variant = 'primary', size = 'md', loading, leftIcon, rightIcon, children, disabled, ...rest }: ButtonProps) { return ( ); } // ========================================================= // πŸ…Έ Input // ========================================================= interface InputProps extends React.InputHTMLAttributes { label?: string; error?: string; hint?: string; } export function Input({ className, label, error, hint, id, ...rest }: InputProps) { const inputId = id ?? label?.toLowerCase().replace(/\s+/g, '-'); return (
{label && } {error && {error}} {hint && !error && {hint}}
); } // ========================================================= // πŸ”” Toast / Alert // ========================================================= type AlertVariant = 'info' | 'success' | 'warning' | 'error'; interface AlertProps { variant?: AlertVariant; title?: string; children: React.ReactNode; onClose?: () => void; } const alertStyles: Record = { info: { container: 'bg-blue-50 border-blue-200 text-blue-800', icon: 'ℹ️' }, success: { container: 'bg-emerald-50 border-emerald-200 text-emerald-800', icon: 'βœ…' }, warning: { container: 'bg-amber-50 border-amber-200 text-amber-800', icon: '⚠️' }, error: { container: 'bg-red-50 border-red-200 text-red-800', icon: '❌' }, }; export function Alert({ variant = 'info', title, children, onClose }: AlertProps) { const s = alertStyles[variant]; return (
{s.icon}
{title &&

{title}

}

{children}

{onClose && }
); } // ========================================================= // πŸƒ Card // ========================================================= interface CardProps extends React.HTMLAttributes { children: React.ReactNode; } export const Card: React.FC = ({ className, children, ...rest }) => (
{children}
); export const CardHeader: React.FC = ({ className, children, ...rest }) => (
{children}
); export const CardTitle: React.FC<{ children: React.ReactNode }> = ({ children }) => (

{children}

); export const CardBody: React.FC = ({ className, children, ...rest }) => (
{children}
); // ── Spinner (reutilizΓ‘vel) ───────────────────────────────── export function Spinner({ size = 16, className = '' }: { size?: number; className?: string }) { return ( ); } // ── Cn helper re-export ──────────────────────────────────── export { cn } from '../utils';