{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "button",
  "type": "registry:ui",
  "title": "Button",
  "description": "A clickable action. Supports variants, sizes, icon-only buttons, loading state and links.",
  "dependencies": [
    "class-variance-authority@^0.7.1",
    "lucide-react@^1.48.0",
    "radix-ui@^1.6.7"
  ],
  "registryDependencies": [
    "https://blank.vageshwar.dev/r/theme.json",
    "https://blank.vageshwar.dev/r/utils.json"
  ],
  "files": [
    {
      "path": "ui/button.tsx",
      "type": "registry:ui",
      "content": "// BlankUI: button. Managed by BlankUI. Read button.md before editing. Add variants here instead of overriding classes at call sites.\nimport type { ComponentProps } from \"react\"\nimport { Slot } from \"radix-ui\"\nimport { cva } from \"class-variance-authority\"\nimport { LoaderCircle } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n  \"inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md border font-medium transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 aria-busy:cursor-progress [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n  {\n    variants: {\n      variant: {\n        default: \"border-edge bg-primary text-primary-foreground shadow-sm hover:bg-primary/90\",\n        secondary:\n          \"border-edge bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80\",\n        outline: \"border-input bg-surface text-foreground shadow-sm hover:bg-surface-hover\",\n        ghost: \"border-transparent text-foreground hover:bg-surface-hover\",\n        destructive:\n          \"border-edge bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90\",\n        link: \"border-transparent text-primary underline-offset-4 hover:underline\",\n      },\n      size: {\n        sm: \"h-8 px-3 text-sm [&_svg]:size-4\",\n        default: \"h-10 px-4 text-sm [&_svg]:size-4\",\n        lg: \"h-12 px-6 text-base [&_svg]:size-5\",\n        icon: \"size-10 [&_svg]:size-4\",\n      },\n    },\n    defaultVariants: { variant: \"default\", size: \"default\" },\n  },\n)\n\n/** Visual style. `default` is the main action, use one per view. */\nexport type ButtonVariant = \"default\" | \"secondary\" | \"outline\" | \"ghost\" | \"destructive\" | \"link\"\n/** Height and padding. `icon` is a square button for a single icon. */\nexport type ButtonSize = \"sm\" | \"default\" | \"lg\" | \"icon\"\n\ninterface ButtonBaseProps extends Omit<ComponentProps<\"button\">, \"aria-label\"> {\n  /** Visual style. Defaults to `default`. */\n  variant?: ButtonVariant\n  /** Render the child element (for example a link) with button styles. */\n  asChild?: boolean\n  /** Show a spinner, disable the button and set `aria-busy`. */\n  loading?: boolean\n}\n\ninterface TextButtonProps extends ButtonBaseProps {\n  /** Size. Defaults to `default`. */\n  size?: Exclude<ButtonSize, \"icon\">\n  /** Accessible name. Not needed when the button has visible text. */\n  \"aria-label\"?: string\n}\n\ninterface IconButtonProps extends ButtonBaseProps {\n  /** Square button for a single icon. */\n  size: \"icon\"\n  /** Required for icon buttons: screen readers announce this instead of the icon. */\n  \"aria-label\": string\n}\n\nexport type ButtonProps = TextButtonProps | IconButtonProps\n\n/**\n * A clickable action. Defaults to `type=\"button\"`, so it never submits a form by accident.\n * Pass `type=\"submit\"` for form submit buttons.\n *\n * @example\n * <Button onClick={save}>Save</Button>\n * <Button variant=\"outline\" size=\"sm\">Cancel</Button>\n * <Button size=\"icon\" aria-label=\"Close\"><X /></Button>\n * <Button asChild variant=\"link\"><a href=\"/docs\">Docs</a></Button>\n */\nexport function Button({\n  variant = \"default\",\n  size = \"default\",\n  asChild = false,\n  loading = false,\n  disabled,\n  className,\n  children,\n  type,\n  ...props\n}: ButtonProps) {\n  const classes = cn(buttonVariants({ variant, size }), className)\n\n  if (asChild) {\n    return (\n      <Slot.Root data-slot=\"button\" className={classes} aria-busy={loading || undefined} {...props}>\n        {children}\n      </Slot.Root>\n    )\n  }\n\n  return (\n    <button\n      data-slot=\"button\"\n      type={type ?? \"button\"}\n      className={classes}\n      disabled={disabled || loading}\n      aria-busy={loading || undefined}\n      {...props}\n    >\n      {loading && <LoaderCircle className=\"animate-spin\" aria-hidden=\"true\" />}\n      {loading && size === \"icon\" ? null : children}\n    </button>\n  )\n}\n\nexport { buttonVariants }\n"
    },
    {
      "path": "ui/button.md",
      "type": "registry:ui",
      "content": "---\nname: button\ntitle: Button\ndescription: A clickable action. Supports variants, sizes, icon-only buttons, loading state and links.\ncategory: action\nwhenToUse:\n  - Trigger an action like save, submit, delete or open a dialog.\n  - Style a link as a button with asChild.\nwhenNotToUse:\n  - when: Navigating to another page inside text.\n    use: a plain link (<a> or your router's Link)\n  - when: Switching between views of the same content.\n    use: tabs\n  - when: Toggling a setting on or off.\n    use: checkbox\nrelated: [layout, card, dialog, alert-dialog]\nrequiredParts: [Button]\nantiPatterns:\n  - avoid: \"<button className=...> (a raw button element)\"\n    instead: \"<Button>\"\n  - avoid: '<Button className=\"bg-red-500\">'\n    instead: '<Button variant=\"destructive\">'\n  - avoid: '<Button size=\"icon\"><Trash /></Button> without a label'\n    instead: '<Button size=\"icon\" aria-label=\"Delete\"><Trash /></Button>'\n  - avoid: \"<Button><a href=...>Docs</a></Button> (a link inside a button)\"\n    instead: '<Button asChild><a href=\"/docs\">Docs</a></Button>'\n  - avoid: \"{isSaving ? <Spinner /> : 'Save'} with disabled={isSaving}\"\n    instead: \"<Button loading={isSaving}>Save</Button>\"\n  - avoid: \"Several default (primary) buttons side by side\"\n    instead: 'One default button, the rest variant=\"outline\" or \"ghost\"'\n---\n\n# Button\n\n## Import\n\n```tsx\nimport { Button } from \"@/components/ui/button\"\n```\n\n## Variants\n\n| Variant       | Use for                                       |\n| ------------- | --------------------------------------------- |\n| `default`     | The main action in a view. One per view.      |\n| `secondary`   | A second, less important action.              |\n| `outline`     | Cancel, back, and other neutral actions.      |\n| `ghost`       | Toolbar and icon actions with little weight.  |\n| `destructive` | Delete or other actions that cannot be undone |\n| `link`        | An action that should look like a link.       |\n\nSizes: `sm`, `default`, `lg`, `icon`.\n\n## Examples\n\n```tsx\n<Inline gap={2} justify=\"end\">\n  <Button variant=\"outline\">Cancel</Button>\n  <Button type=\"submit\" loading={isSaving}>\n    Save changes\n  </Button>\n</Inline>\n```\n\nIcon buttons must have an `aria-label`. TypeScript reports an error without it.\n\n```tsx\nimport { Trash } from \"lucide-react\"\n\n;<Button size=\"icon\" variant=\"ghost\" aria-label=\"Delete project\">\n  <Trash />\n</Button>\n```\n\nIcons next to text go before the text:\n\n```tsx\nimport { Plus } from \"lucide-react\"\n\n;<Button>\n  <Plus /> New project\n</Button>\n```\n\nLinks that look like buttons:\n\n```tsx\n<Button asChild variant=\"outline\">\n  <a href=\"/pricing\">See pricing</a>\n</Button>\n```\n\n## Notes\n\n- `type` defaults to `\"button\"`, so a Button inside a form does not submit it. Use `type=\"submit\"` for the submit button.\n- `loading` shows a spinner, disables the button and sets `aria-busy`.\n"
    }
  ],
  "docs": "Read components/ui/button.md before using Button. Docs: https://blank.vageshwar.dev/docs/button",
  "meta": {
    "category": "action",
    "requiredParts": [
      "Button"
    ],
    "related": [
      "layout",
      "card",
      "dialog",
      "alert-dialog"
    ]
  }
}
