{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "icon-button",
  "type": "registry:ui",
  "title": "IconButton",
  "description": "Accessible token-backed icon-only action button for Dethink Components.",
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://components.dethink.co.uk/r/dethink-base.json",
    "https://components.dethink.co.uk/r/button.json"
  ],
  "files": [
    {
      "path": "packages/components/src/components/icon-button/icon-button.tsx",
      "type": "registry:file",
      "target": "~/components/dethink/components/icon-button/icon-button.tsx",
      "content": "import {\n  forwardRef,\n  type ButtonHTMLAttributes,\n  type MouseEventHandler,\n  type ReactNode,\n} from \"react\";\nimport type { ButtonVariant } from \"../button\";\nimport { cn } from \"../../utils/cn\";\n\nexport type IconButtonVariant = Exclude<ButtonVariant, \"link\">;\nexport type IconButtonSize = \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\nexport type IconButtonShape = \"square\" | \"circle\";\n\nexport type IconButtonAccessibleName =\n  | { \"aria-label\": string; \"aria-labelledby\"?: never }\n  | { \"aria-label\"?: never; \"aria-labelledby\": string };\n\nexport type IconButtonProps = Omit<\n  ButtonHTMLAttributes<HTMLButtonElement>,\n  \"aria-label\" | \"aria-labelledby\"\n> &\n  IconButtonAccessibleName & {\n    variant?: IconButtonVariant;\n    size?: IconButtonSize;\n    shape?: IconButtonShape;\n    loading?: boolean;\n    children: ReactNode;\n  };\n\nconst iconButtonBaseClasses =\n  \"relative inline-flex shrink-0 items-center justify-center border border-transparent font-medium motion-safe:transition-[color,background-color,border-color,opacity,scale] motion-safe:duration-[var(--dt-motion-fast)] motion-safe:ease-control motion-safe:enabled:active:scale-[var(--dt-control-press-scale,0.96)] motion-safe:active:duration-[var(--dt-motion-press)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[loading=true]:cursor-wait data-[loading=true]:opacity-80\";\n\nconst iconButtonVariantClasses: Record<IconButtonVariant, string> = {\n  solid:\n    \"bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/80\",\n  soft: \"bg-primary/10 text-primary hover:bg-primary/15 active:bg-primary/20\",\n  outline:\n    \"border-border bg-background text-foreground hover:bg-muted active:bg-muted/80\",\n  ghost: \"bg-transparent text-foreground hover:bg-muted active:bg-muted/80\",\n  destructive:\n    \"bg-destructive text-destructive-foreground hover:bg-destructive/90 active:bg-destructive/80\",\n};\n\nconst iconButtonSizeClasses: Record<IconButtonSize, string> = {\n  xs: \"size-7 text-xs\",\n  sm: \"size-8 text-sm\",\n  md: \"size-density-control text-sm\",\n  lg: \"size-11 text-base\",\n  xl: \"size-12 text-base\",\n};\n\nconst iconButtonIconSizeClasses: Record<IconButtonSize, string> = {\n  xs: \"size-3.5 [&>svg]:size-3.5\",\n  sm: \"size-4 [&>svg]:size-4\",\n  md: \"size-4 [&>svg]:size-4\",\n  lg: \"size-5 [&>svg]:size-5\",\n  xl: \"size-5 [&>svg]:size-5\",\n};\n\nconst iconButtonShapeClasses: Record<IconButtonShape, string> = {\n  square: \"rounded-md\",\n  circle: \"rounded-full\",\n};\n\nconst iconButtonIconClasses =\n  \"pointer-events-none inline-flex shrink-0 items-center justify-center\";\n\nconst iconButtonSpinnerClasses =\n  \"pointer-events-none shrink-0 rounded-full border-2 border-current border-r-transparent animate-spin motion-reduce:animate-none\";\n\nexport function iconButtonClassNames({\n  variant = \"ghost\",\n  size = \"md\",\n  shape = \"square\",\n  className,\n}: Pick<IconButtonProps, \"variant\" | \"size\" | \"shape\" | \"className\"> = {}) {\n  return cn(\n    iconButtonBaseClasses,\n    iconButtonSizeClasses[size],\n    iconButtonShapeClasses[shape],\n    iconButtonVariantClasses[variant],\n    className,\n  );\n}\n\nexport const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(\n  (\n    {\n      \"aria-busy\": ariaBusy,\n      children,\n      className,\n      disabled = false,\n      loading = false,\n      onClick,\n      shape = \"square\",\n      size = \"md\",\n      type = \"button\",\n      variant = \"ghost\",\n      ...props\n    },\n    ref,\n  ) => {\n    const isDisabled = disabled || loading;\n    const handleClick: MouseEventHandler<HTMLButtonElement> = (event) => {\n      if (isDisabled) {\n        event.preventDefault();\n        return;\n      }\n\n      onClick?.(event);\n    };\n\n    return (\n      <button\n        {...props}\n        ref={ref}\n        type={type}\n        disabled={isDisabled}\n        aria-busy={loading ? true : ariaBusy}\n        data-slot=\"icon-button\"\n        data-variant={variant}\n        data-size={size}\n        data-shape={shape}\n        data-disabled={isDisabled ? \"true\" : undefined}\n        data-loading={loading ? \"true\" : undefined}\n        className={iconButtonClassNames({ variant, size, shape, className })}\n        onClick={handleClick}\n      >\n        {loading ? (\n          <span\n            aria-hidden=\"true\"\n            data-slot=\"icon-button-spinner\"\n            className={cn(\n              iconButtonSpinnerClasses,\n              iconButtonIconSizeClasses[size],\n              \"absolute\",\n            )}\n          />\n        ) : null}\n        <span\n          aria-hidden=\"true\"\n          data-slot=\"icon-button-icon\"\n          className={cn(\n            iconButtonIconClasses,\n            iconButtonIconSizeClasses[size],\n            \"motion-safe:ease-control motion-safe:transition-[opacity,scale] motion-safe:duration-[var(--dt-motion-fast)]\",\n            loading && \"opacity-0 motion-safe:scale-75\",\n          )}\n        >\n          {children}\n        </span>\n      </button>\n    );\n  },\n);\n\nIconButton.displayName = \"IconButton\";\n"
    },
    {
      "path": "packages/components/src/components/icon-button/index.ts",
      "type": "registry:file",
      "target": "~/components/dethink/components/icon-button/index.ts",
      "content": "export {\n  IconButton,\n  iconButtonClassNames,\n  type IconButtonAccessibleName,\n  type IconButtonProps,\n  type IconButtonShape,\n  type IconButtonSize,\n  type IconButtonVariant,\n} from \"./icon-button\";\n"
    },
    {
      "path": "packages/components/src/utils/cn.ts",
      "type": "registry:file",
      "target": "~/components/dethink/utils/cn.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n"
    }
  ]
}
