{ "$schema": "https://ui.aodesu.com/schema/registry-item.json", "name": "button", "type": "registry:ui", "files": [ { "path": "registry/aodesu/ui/button.tsx", "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { Slot } from \"@/lib/slot\"\nimport { cn } from \"@/lib/utils\"\n\n/* ---------------------------------------------\n Tipos\n--------------------------------------------- */\n\ntype ButtonVariant = \"ghost\" | \"contained\" | \"outlined\" | \"text\"\ntype ButtonColor = \"neutral\" | \"primary\" | \"secondary\" | \"contrast\"\ntype ButtonSize = \"small\" | \"medium\" | \"big\"\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes {\n variant?: ButtonVariant\n color?: ButtonColor\n size?: ButtonSize\n icon?: boolean\n asChild?: boolean\n loading?: boolean\n fullWidth?: boolean\n}\n\n/* ---------------------------------------------\n Clases base\n--------------------------------------------- */\n\nconst baseClasses =\n \"relative overflow-hidden inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium shrink-0 outline-none transition-transform transition-colors disabled:pointer-events-none disabled:opacity-50 focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:text-[1.5em] [&_svg]:w-[1em] [&_svg]:h-[1em]\"\n\n/* ---------------------------------------------\n Sizes\n--------------------------------------------- */\n\nconst sizeClasses: Record = {\n small: \"rounded-md px-3 py-1.5 [&_svg]:size-4\",\n medium: \"rounded-lg px-4 py-2 [&_svg]:size-5\",\n big: \"rounded-xl px-6 py-3 [&_svg]:size-5\",\n}\n\nconst iconSizeClasses: Record = {\n small: \"size-8 rounded-md p-2\",\n medium: \"size-10 rounded-lg p-0\",\n big: \"size-12 rounded-xl p-0\",\n}\n\n/* ---------------------------------------------\n Variants base\n--------------------------------------------- */\n\nconst variantBaseClasses: Record = {\n ghost: \"\",\n contained: \"\",\n outlined: \"border border-[hsl(var(--neutral-dark))]\",\n text: \"!py-0 !px-0.5 !text-[1em] leading-none !h-lh !rounded-full ring-4 ring-transparent\",\n}\n\n/* ---------------------------------------------\n Colores por variante\n--------------------------------------------- */\n\nconst variantColorMap = {\n ghost: {\n neutral:\n \"hover:bg-[hsl(var(--neutral-dark))] active:bg-[hsl(var(--neutral))]\",\n primary:\n \"text-[hsl(var(--primary-light))] hover:bg-[hsl(var(--primary))] hover:text-[hsl(var(--primary-foreground))] active:bg-[hsl(var(--primary-light))]\",\n secondary:\n \"text-[hsl(var(--secondary-light))] hover:bg-[hsl(var(--secondary))] hover:text-[hsl(var(--secondary-foreground))] active:bg-[hsl(var(--secondary-light))]\",\n contrast:\n \"hover:bg-[hsl(var(--contrast-light))] hover:text-[hsl(var(--inverse-foreground))] active:bg-[hsl(var(--contrast))]\",\n },\n contained: {\n neutral:\n \"bg-[hsl(var(--neutral-dark))] hover:bg-[hsl(var(--neutral))] active:bg-[hsl(var(--neutral-light))]\",\n primary:\n \"bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] hover:bg-[hsl(var(--primary-dark))] active:bg-[hsl(var(--primary-light))]\",\n secondary:\n \"bg-[hsl(var(--secondary))] text-[hsl(var(--secondary-foreground))] hover:bg-[hsl(var(--secondary-dark))] active:bg-[hsl(var(--secondary-light))]\",\n contrast:\n \"text-[hsl(var(--inverse-foreground))] bg-[hsl(var(--contrast-light))] hover:bg-[hsl(var(--contrast))] active:bg-[hsl(var(--contrast-dark))]\",\n },\n outlined: {\n neutral:\n \"border-[hsl(var(--neutral-dark))] hover:bg-[hsl(var(--neutral-dark))] active:bg-[hsl(var(--neutral))]\",\n primary:\n \"text-[hsl(var(--primary-light))] border-[hsl(var(--primary-dark))] hover:bg-[hsl(var(--primary-dark))] hover:text-[hsl(var(--primary-foreground))]\",\n secondary:\n \"text-[hsl(var(--secondary-light))] border-[hsl(var(--secondary-dark))] hover:bg-[hsl(var(--secondary-dark))] hover:text-[hsl(var(--secondary-foreground))]\",\n contrast:\n \"border-[hsl(var(--foreground)/.7)] hover:bg-[hsl(var(--neutral-dark))]\",\n },\n text: {\n neutral:\n \"text-[hsl(var(--foreground-light))] hover:bg-[hsl(var(--neutral-dark))]\",\n primary:\n \"text-[hsl(var(--primary-light))] hover:bg-[hsl(var(--primary-light)/.15)]\",\n secondary:\n \"text-[hsl(var(--secondary-light))] hover:bg-[hsl(var(--secondary-light)/.15)]\",\n contrast:\n \"text-[hsl(var(--primary-light))] hover:bg-[hsl(var(--primary-light)/.15)]\",\n },\n} as const\n\n/* ---------------------------------------------\n Active behaviors\n--------------------------------------------- */\n\nconst activeIconClasses = \"active:[&_svg]:scale-90\"\nconst activeNormalClasses = \"active:opacity-70\"\n\n/* ---------------------------------------------\n Button\n--------------------------------------------- */\n\nexport function Button({\n className,\n variant = \"ghost\",\n color = \"neutral\",\n size = \"medium\",\n icon,\n asChild,\n loading,\n children,\n fullWidth,\n ...props\n}: ButtonProps) {\n const isIconButton =\n icon ??\n (React.Children.count(children) === 1 &&\n React.isValidElement(children) &&\n children.type === \"svg\")\n\n const composedClassName = cn(\n baseClasses,\n fullWidth && \"w-full\",\n variantBaseClasses[variant],\n variantColorMap[variant][color],\n isIconButton ? iconSizeClasses[size] : sizeClasses[size],\n isIconButton ? activeIconClasses : activeNormalClasses,\n className\n )\n\n if (asChild && React.isValidElement(children)) {\n return (\n \n {children}\n \n )\n }\n\n return (\n \n \n {children}\n \n \n \n \n \n \n \n )\n}\n", "type": "registry:ui" } ] }