{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "color-swatch",
  "title": "Color Swatch",
  "description": "A rounded colour chip with a checkerboard alpha backing, selectable standalone or in a radio-style swatch grid.",
  "dependencies": [
    "@untitledui/icons@^0.0.22"
  ],
  "registryDependencies": [
    "@nx-ui/utils"
  ],
  "files": [
    {
      "path": "components/ui/color-swatch.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Check } from \"@untitledui/icons\"\n\nimport { cn } from \"@/lib/utils\"\n\n/**\n * ColorSwatch / ColorSwatchGroup — a rounded colour chip with a checkerboard\n * backing (so alpha values read correctly) and a selected-ring state, plus a\n * radio-group-semantics grid for picking one colour from a set.\n *\n * ColorSwatch is a plain, uncontrolled button — pass `selected` yourself for\n * a single standalone chip. ColorSwatchGroup wires up `role=\"radiogroup\"` /\n * `role=\"radio\"` semantics (mirrors components/ui/rating.tsx) and supports\n * both controlled (`value` + `onValueChange`) and uncontrolled\n * (`defaultValue`) usage.\n */\n\nconst sizeClass = {\n  sm: \"size-6\",\n  md: \"size-8\",\n  lg: \"size-10\",\n} as const\n\n/** Checkerboard backing so translucent colours are legible, light + dark. */\nconst CHECKERBOARD_STYLE: React.CSSProperties = {\n  backgroundImage:\n    \"linear-gradient(45deg, var(--color-border) 25%, transparent 25%), linear-gradient(-45deg, var(--color-border) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--color-border) 75%), linear-gradient(-45deg, transparent 75%, var(--color-border) 75%)\",\n  backgroundSize: \"8px 8px\",\n  backgroundPosition: \"0 0, 0 4px, 4px -4px, -4px 0px\",\n}\n\nfunction ColorSwatch({\n  className,\n  color,\n  size = \"md\",\n  selected = false,\n  disabled = false,\n  \"aria-label\": ariaLabel,\n  style,\n  ...props\n}: Omit<React.ComponentProps<\"button\">, \"color\"> & {\n  /** Any valid CSS colour (hex, rgb, rgba, hsl…). */\n  color: string\n  size?: keyof typeof sizeClass\n  selected?: boolean\n}) {\n  return (\n    <button\n      type=\"button\"\n      data-slot=\"color-swatch\"\n      data-selected={selected ? \"\" : undefined}\n      aria-label={ariaLabel ?? color}\n      disabled={disabled}\n      className={cn(\n        \"relative shrink-0 cursor-pointer rounded-lg border border-border shadow-xs outline-none transition-[box-shadow] focus-visible:ring-4 focus-visible:ring-ring/25 disabled:cursor-not-allowed disabled:opacity-50 data-selected:ring-2 data-selected:ring-ring data-selected:ring-offset-2 data-selected:ring-offset-background\",\n        sizeClass[size],\n        className\n      )}\n      style={{ ...CHECKERBOARD_STYLE, ...style }}\n      {...props}\n    >\n      <span\n        aria-hidden=\"true\"\n        className=\"absolute inset-0 rounded-[calc(var(--radius-lg)-1px)]\"\n        style={{ backgroundColor: color }}\n      />\n      {selected ? (\n        <Check\n          aria-hidden=\"true\"\n          className={cn(\n            \"relative m-auto size-3.5 drop-shadow-[0_1px_1px_rgb(0_0_0_/_0.5)]\",\n            \"text-white\"\n          )}\n        />\n      ) : null}\n    </button>\n  )\n}\n\nfunction ColorSwatchGroup({\n  className,\n  colors,\n  value,\n  defaultValue,\n  onValueChange,\n  size = \"md\",\n  disabled = false,\n  \"aria-label\": ariaLabel = \"Colour\",\n  ...props\n}: Omit<React.ComponentProps<\"div\">, \"defaultValue\" | \"onChange\"> & {\n  /** Swatch colours, either plain CSS colour strings or `{ value, label }` pairs. */\n  colors: (string | { value: string; label?: string })[]\n  value?: string\n  defaultValue?: string\n  onValueChange?: (value: string) => void\n  size?: keyof typeof sizeClass\n  disabled?: boolean\n}) {\n  const isControlled = value !== undefined\n  const [internal, setInternal] = React.useState(defaultValue)\n  const current = isControlled ? value : internal\n\n  const set = (next: string) => {\n    if (!isControlled) setInternal(next)\n    onValueChange?.(next)\n  }\n\n  return (\n    <div\n      data-slot=\"color-swatch-group\"\n      role=\"radiogroup\"\n      aria-label={ariaLabel}\n      className={cn(\"flex flex-wrap gap-2\", className)}\n      {...props}\n    >\n      {colors.map((entry) => {\n        const color = typeof entry === \"string\" ? entry : entry.value\n        const label = typeof entry === \"string\" ? entry : (entry.label ?? entry.value)\n        const checked = current === color\n        return (\n          <ColorSwatch\n            key={color}\n            role=\"radio\"\n            aria-checked={checked}\n            aria-label={label}\n            color={color}\n            size={size}\n            selected={checked}\n            disabled={disabled}\n            onClick={() => set(color)}\n          />\n        )\n      })}\n    </div>\n  )\n}\n\nexport { ColorSwatch, ColorSwatchGroup }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}