{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "color-contrast",
  "type": "registry:component",
  "title": "ColorContrast",
  "description": "A component for displaying accessibility contrast algorithms visually inline, natively hooking into ColorSwatch.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "@tokenui/color-swatch"
  ],
  "files": [
    {
      "path": "registry/components/color-contrast.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { useColorSwatch } from \"./color-swatch\";\nimport { Check, X } from \"lucide-react\";\n\n/**\n * Utility to calculate WCAG 2.0 contrast ratio\n */\nexport function getLuminance(hex: string) {\n  let cleanedHex = hex.replace(/^#/, \"\");\n  if (cleanedHex.length === 3) {\n    cleanedHex = cleanedHex\n      .split(\"\")\n      .map((c) => c + c)\n      .join(\"\");\n  }\n  if (cleanedHex.length !== 6) return 0;\n\n  const r = parseInt(cleanedHex.substring(0, 2), 16) / 255;\n  const g = parseInt(cleanedHex.substring(2, 4), 16) / 255;\n  const b = parseInt(cleanedHex.substring(4, 6), 16) / 255;\n\n  const toLinear = (c: number) =>\n    c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n\n  return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n}\n\nexport function getContrast(color1: string, color2: string) {\n  const l1 = getLuminance(color1);\n  const l2 = getLuminance(color2);\n  const lightest = Math.max(l1, l2);\n  const darkest = Math.min(l1, l2);\n  return (lightest + 0.05) / (darkest + 0.05);\n}\n\ntype ContrastLevel = \"AA\" | \"AAA\" | \"fail\" | boolean;\n\ntype ColorContrastContextValue = {\n  baseColor: string;\n  againstColor: string;\n  ratio: number | string;\n  passes: ContrastLevel;\n};\n\nconst ColorContrastContext =\n  React.createContext<ColorContrastContextValue | null>(null);\n\nexport function useColorContrast() {\n  return React.useContext(ColorContrastContext);\n}\n\ntype ColorContrastProps = React.HTMLAttributes<HTMLDivElement> & {\n  /** The color to check contrast against (often text color) */\n  against: string;\n  /** The underlying base color, automatically inferred if wrapped in ColorSwatch */\n  base?: string;\n  /** Custom ratio override, useful for specifying APCA variants where calculation isn't standard WCAG */\n  ratio?: number | string;\n  /** Manual override for pass/fail or AA/AAA level. Otherwise calculated automatically using WCAG normal text math */\n  passes?: ContrastLevel;\n};\n\nconst ColorContrast = React.forwardRef<HTMLDivElement, ColorContrastProps>(\n  ({ base, against, ratio, passes, className, children, ...props }, ref) => {\n    const swatch = useColorSwatch();\n    // Default base color either from prop or from parent ColorSwatch context\n    const baseColor = base || swatch?.value || \"#000000\";\n\n    const calculatedRatio = React.useMemo(() => {\n      if (ratio !== undefined) return ratio;\n      return Math.round(getContrast(baseColor, against) * 10) / 10;\n    }, [baseColor, against, ratio]);\n\n    const calculatedPasses = React.useMemo(() => {\n      if (passes !== undefined) return passes;\n      if (typeof calculatedRatio === \"number\") {\n        if (calculatedRatio >= 7) return \"AAA\";\n        if (calculatedRatio >= 4.5) return \"AA\";\n        // 3.0 is AA for large text, this assumes normal text for stricter validation\n        return \"fail\";\n      }\n      return \"fail\";\n    }, [calculatedRatio, passes]);\n\n    return (\n      <ColorContrastContext.Provider\n        value={{\n          baseColor,\n          againstColor: against,\n          ratio: calculatedRatio,\n          passes: calculatedPasses,\n        }}\n      >\n        <div\n          ref={ref}\n          className={cn(\"flex items-center gap-1.5 text-sm\", className)}\n          {...props}\n        >\n          {children}\n        </div>\n      </ColorContrastContext.Provider>\n    );\n  },\n);\nColorContrast.displayName = \"ColorContrast\";\n\nconst ColorContrastRatio = React.forwardRef<\n  HTMLSpanElement,\n  React.HTMLAttributes<HTMLSpanElement>\n>(({ className, ...props }, ref) => {\n  const context = useColorContrast();\n  if (!context) return null;\n\n  return (\n    <span\n      ref={ref}\n      className={cn(\"font-mono font-medium\", className)}\n      {...props}\n    >\n      {typeof context.ratio === \"number\"\n        ? `${context.ratio.toFixed(1)}:1`\n        : context.ratio}\n    </span>\n  );\n});\nColorContrastRatio.displayName = \"ColorContrastRatio\";\n\ntype ColorContrastBadgeProps = React.HTMLAttributes<HTMLSpanElement> & {\n  /** Visual variant of the badge, displaying raw icon or colored pill */\n  variant?: \"pill\" | \"icon\";\n};\n\nconst ColorContrastBadge = React.forwardRef<\n  HTMLSpanElement,\n  ColorContrastBadgeProps\n>(({ className, variant = \"pill\", ...props }, ref) => {\n  const context = useColorContrast();\n  if (!context) return null;\n  const { passes } = context;\n\n  if (passes === \"fail\" || passes === false) {\n    return (\n      <span\n        ref={ref}\n        className={cn(\"inline-flex items-center justify-center\", className)}\n        {...props}\n      >\n        <X className=\"h-4 w-4 text-red-500\" strokeWidth={3} />\n      </span>\n    );\n  }\n\n  if (variant === \"icon\" || passes === true) {\n    return (\n      <span\n        ref={ref}\n        className={cn(\"inline-flex items-center justify-center\", className)}\n        {...props}\n      >\n        <Check className=\"h-4 w-4 text-green-500\" strokeWidth={3} />\n      </span>\n    );\n  }\n\n  return (\n    <span\n      ref={ref}\n      className={cn(\n        \"inline-flex rounded-full px-1.5 py-0.5 text-[10px] font-bold leading-none tracking-wider text-white\",\n        passes === \"AAA\" ? \"bg-green-600\" : \"bg-green-500\",\n        className,\n      )}\n      {...props}\n    >\n      {passes}\n    </span>\n  );\n});\nColorContrastBadge.displayName = \"ColorContrastBadge\";\n\nexport {\n  ColorContrast,\n  ColorContrastRatio,\n  ColorContrastBadge,\n  type ColorContrastProps,\n  type ColorContrastBadgeProps,\n};\n",
      "type": "registry:component"
    }
  ]
}