{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "button",
  "title": "Button",
  "description": "Triggers an action. The most important interactive element in any interface — and the easiest one to overuse.",
  "dependencies": [
    "@base-ui/react",
    "class-variance-authority"
  ],
  "registryDependencies": [
    "https://www.prfct.dev/r/utils.json",
    "https://www.prfct.dev/r/spinner.json"
  ],
  "files": [
    {
      "path": "components/ui/button.tsx",
      "content": "import { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"@/lib/utils\"\n\nimport { Spinner } from \"@/components/ui/spinner\"\n\nconst buttonVariants = cva(\n  [\n    \"group/button relative inline-flex shrink-0 items-center justify-center font-medium whitespace-nowrap outline-none select-none\",\n    \"transition-[background-color,border-color,color,box-shadow,scale,opacity] duration-fast ease-standard\",\n    \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\",\n    \"active:not-data-disabled:scale-[0.98]\",\n    \"disabled:pointer-events-none disabled:opacity-50 data-loading:cursor-progress data-disabled:not-data-loading:opacity-50\",\n    \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  ],\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground bevel hover:bg-primary/88\",\n        brand: \"bg-brand text-brand-foreground bevel hover:bg-brand-10\",\n        secondary:\n          \"bg-secondary text-secondary-foreground hover:bg-gray-4 active:bg-gray-5 aria-expanded:bg-gray-4\",\n        outline:\n          \"border border-border-strong bg-card text-foreground shadow-xs hover:border-gray-8 hover:bg-accent aria-expanded:bg-accent\",\n        ghost: \"text-foreground hover:bg-accent aria-expanded:bg-accent\",\n        destructive:\n          \"bg-danger-9 text-danger-contrast bevel hover:bg-danger-10\",\n        link: \"h-auto! px-0! text-link underline decoration-current/30 underline-offset-4 hover:decoration-current active:scale-100!\",\n      },\n      size: {\n        xs: \"h-7 gap-1 rounded-md px-2.5 text-[0.8125rem] has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3.5\",\n        sm: \"h-8 gap-1.5 rounded-lg px-3 text-sm has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5\",\n        default:\n          \"h-9 gap-2 rounded-lg px-3.5 text-sm has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3\",\n        lg: \"h-10 gap-2 rounded-lg px-4 text-sm has-data-[icon=inline-end]:pr-3.5 has-data-[icon=inline-start]:pl-3.5\",\n        xl: \"h-12 gap-2.5 rounded-xl px-5 text-base has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4 [&_svg:not([class*='size-'])]:size-[1.125rem]\",\n        icon: \"size-9 rounded-lg\",\n        \"icon-xs\": \"size-7 rounded-md [&_svg:not([class*='size-'])]:size-3.5\",\n        \"icon-sm\": \"size-8 rounded-lg\",\n        \"icon-lg\": \"size-10 rounded-lg\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\ntype ButtonProps = ButtonPrimitive.Props &\n  VariantProps<typeof buttonVariants> & {\n    /**\n     * Shows a spinner and blocks interaction while keeping the button's width\n     * and keyboard focus, so layouts don't jump and focus isn't lost.\n     */\n    loading?: boolean\n  }\n\nfunction Button({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  loading = false,\n  disabled,\n  focusableWhenDisabled,\n  children,\n  ...props\n}: ButtonProps) {\n  return (\n    <ButtonPrimitive\n      data-slot=\"button\"\n      data-variant={variant}\n      data-size={size}\n      data-loading={loading || undefined}\n      aria-busy={loading || undefined}\n      disabled={disabled || loading}\n      focusableWhenDisabled={loading || focusableWhenDisabled}\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    >\n      {loading ? (\n        <>\n          {/* Holds the button's width; invisible, so the spinner shows alone. */}\n          <span aria-hidden=\"true\" className=\"invisible contents\">\n            {children}\n          </span>\n          {/* Hidden content has no accessible name — the label lives on here. */}\n          <span className=\"sr-only\">{children}</span>\n          <span\n            aria-hidden=\"true\"\n            className=\"absolute inset-0 flex items-center justify-center\"\n          >\n            <Spinner label=\"\" />\n          </span>\n        </>\n      ) : (\n        children\n      )}\n    </ButtonPrimitive>\n  )\n}\n\nexport { Button, buttonVariants, type ButtonProps }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}