{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "button",
  "title": "button",
  "dependencies": [
    "@radix-ui/react-slot",
    "class-variance-authority@^0.7"
  ],
  "registryDependencies": [
    "@dwellir/dwellir-theme",
    "@dwellir/utils",
    "@dwellir/spinner"
  ],
  "files": [
    {
      "path": "components/ui/button.tsx",
      "content": "import { Slot, Slottable } from '@radix-ui/react-slot';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport type { ComponentProps, MouseEvent } from 'react';\nimport { Spinner } from '@/components/ui/spinner';\nimport { cn } from '@/lib/utils';\n\nconst buttonVariants = cva('ui-button', {\n  variants: {\n    variant: {\n      /* The one action that matters on a screen. */\n      primary: 'button-primary',\n      /* A neutral fill for the second action. */\n      secondary: 'button-secondary',\n      /* With aria-pressed it is a toggle, such as a filter: on, it takes the accent tint. */\n      outline: 'button-outline',\n      ghost: 'text-foreground hover:bg-muted',\n      /* A text link with the button's API: underlined, so it does not rely on colour. */\n      link: 'button-link',\n      /* A link in ink, beside the view's one green action: underlined, firmer under the pointer. */\n      'link-ink': 'button-link-ink',\n      /* An action that deletes or cannot be undone. */\n      destructive:\n        'bg-destructive text-background hover:bg-destructive-90 focus-visible:outline-destructive',\n      warning:\n        'bg-warning-ink text-warning-foreground hover:bg-warning-ink-90 focus-visible:outline-warning-ink',\n      /*\n       * The children draw the control, such as a video's thumbnail or a chart:\n       * the part adds the focus ring and the disabled state, and no fill, edge,\n       * corners or size. Lay it out with layout classes, such as block.\n       */\n      visual: 'rounded-none',\n    },\n    size: {\n      /* Compact links in a row, such as the ways to follow the status page. */\n      xs: \"h-6 gap-1 px-2.5 text-xs [&_svg:not([class*='size-'])]:size-3\",\n      sm: 'h-8 px-3.5 text-sm',\n      /* Upstream's 36px default, for app UI such as the dashboard mock. The house default is md. */\n      default: 'h-9 px-4 text-sm',\n      md: 'h-10 px-5 text-sm',\n      lg: 'h-12 px-7 text-base',\n      icon: 'size-10',\n      'icon-sm': 'size-8',\n      'icon-xs': \"size-6 [&_svg:not([class*='size-'])]:size-3\",\n      'icon-lg': 'size-12',\n      /* A link row in a list, such as a chain's resources: block-level, its text wraps. Pair it with shape=\"rounded\". */\n      row: 'flex h-auto justify-start gap-3 px-2 py-2 whitespace-normal',\n    },\n    /*\n     * Legacy pins. New code passes no shape: the button then follows the\n     * theme's --radius-control, as every control does (a pill on this site).\n     * An app that wants square controls sets that token once, not a shape\n     * per button. The pins stay so existing callers keep their corners even\n     * where the token says otherwise.\n     */\n    shape: {\n      /* Pins a pill, whatever --radius-control says. */\n      pill: 'rounded-full',\n      /* Pins upstream's 6px corners, as the dashboard mock and link rows pass today. */\n      rounded: 'rounded-md',\n    },\n  },\n  compoundVariants: [{ variant: ['link', 'link-ink'], className: 'h-auto px-0' }],\n  /* No shape: ui-button's control corner applies. */\n  defaultVariants: { variant: 'primary', size: 'md' },\n});\n\ntype ButtonProps = ComponentProps<'button'> &\n  VariantProps<typeof buttonVariants> & {\n    /** Render the child element (a link) with the button's look. */\n    asChild?: boolean;\n    /**\n     * Show a Spinner before the label, disable the button and set aria-busy,\n     * as shadcn's Spinner-in-Button example does. Keep the label: it says what runs.\n     */\n    pending?: boolean;\n  };\n\n/*\n * A link has no disabled state: while pending, stop its click, from a pointer or\n * Enter, before the link navigates or its own onClick runs.\n */\nfunction blockActivation(event: MouseEvent) {\n  event.preventDefault();\n  event.stopPropagation();\n}\n\nfunction Button({\n  className,\n  variant,\n  size,\n  shape,\n  asChild = false,\n  pending = false,\n  disabled,\n  onClickCapture,\n  children,\n  ...props\n}: ButtonProps) {\n  const Comp = asChild ? Slot : 'button';\n  return (\n    <Comp\n      data-slot=\"button\"\n      data-variant={variant ?? 'primary'}\n      data-size={size ?? 'md'}\n      data-shape={shape === 'pill' ? shape : undefined}\n      data-pending={pending || undefined}\n      aria-busy={pending || undefined}\n      aria-disabled={pending || undefined}\n      disabled={pending && !asChild ? true : disabled}\n      onClickCapture={pending && asChild ? blockActivation : onClickCapture}\n      className={cn(\n        /* A visual button takes its size from its children. */\n        buttonVariants({\n          variant,\n          size: variant === 'visual' ? null : size,\n          shape: shape === 'pill' ? null : shape,\n        }),\n        /* An icon button has no room for two icons: the spinner takes the icon's place. */\n        pending && size?.startsWith('icon') && '[&>svg:not([data-slot=spinner])]:hidden',\n        className,\n      )}\n      {...props}\n    >\n      {/* No size class: the button's icon rule sizes the spinner, as it sizes an icon. */}\n      {pending ? <Spinner size={null} /> : null}\n      <Slottable>{children}</Slottable>\n    </Comp>\n  );\n}\n\nexport { Button, buttonVariants };\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}