{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"c-color-picker-13","type":"registry:block","title":"Contrast checker","description":"Text and background pickers with a live preview, the WCAG ratio and AA and AAA results.","dependencies":[],"registryDependencies":["@reui/badge","button","card","@reui/color-picker","field","@reui/frame"],"files":[{"path":"c-color-picker-13.tsx","type":"registry:block","content":"\"use client\"\n\nimport { useState } from \"react\"\nimport type { CSSProperties } from \"react\"\nimport { Badge } from \"@/components/reui/badge\"\nimport {\n  ColorPicker,\n  getContrastRatio,\n} from \"@/components/reui/color-picker\"\nimport { Frame, FramePanel } from \"@/components/reui/frame\"\n\nimport { Button } from \"@/components/ui/button\"\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardHeader,\n  CardTitle,\n} from \"@/components/ui/card\"\nimport { Field, FieldLabel } from \"@/components/ui/field\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\n/* WCAG 2.2 thresholds: 4.5 and 7 for body text, 3 for large text. */\nconst CHECKS = [\n  { level: \"AA\", text: \"Body\", min: 4.5 },\n  { level: \"AAA\", text: \"Body\", min: 7 },\n  { level: \"AA\", text: \"Large\", min: 3 },\n]\n\nexport function Pattern() {\n  const [text, setText] = useState<string | null>(\"#1e3a8a\")\n  const [background, setBackground] = useState<string | null>(\"#dbeafe\")\n  const ratio = text && background ? getContrastRatio(text, background) : null\n\n  return (\n    <Card className=\"w-full max-w-md\">\n      <CardHeader>\n        <CardTitle>Contrast checker</CardTitle>\n        <CardDescription>\n          WCAG ratios for a text and background pair.\n        </CardDescription>\n      </CardHeader>\n      <CardContent>\n        <div className=\"flex flex-col gap-5\">\n          <Frame>\n            <FramePanel\n              style={\n                {\n                  \"--frame-panel-bg\": background ?? undefined,\n                  color: text ?? undefined,\n                } as CSSProperties\n              }\n            >\n              <div className=\"flex flex-col gap-1\">\n                <p className=\"text-lg font-semibold\">\n                  Quarterly report is ready\n                </p>\n                <p className=\"text-sm\">\n                  Revenue grew 18% on the quarter, led by self-serve plans.\n                </p>\n              </div>\n            </FramePanel>\n          </Frame>\n          <div className=\"flex items-end gap-2\">\n            <Field className=\"min-w-0 flex-1\">\n              <FieldLabel id=\"contrast-text-label\" htmlFor=\"contrast-text\">\n                Text\n              </FieldLabel>\n              <ColorPicker\n                id=\"contrast-text\"\n                value={text}\n                onValueChange={setText}\n                aria-labelledby=\"contrast-text-label\"\n              />\n            </Field>\n            <Button\n              variant=\"outline\"\n              size=\"icon\"\n              aria-label=\"Swap text and background\"\n              onClick={() => {\n                setText(background)\n                setBackground(text)\n              }}\n            >\n              <IconPlaceholder\n                lucide=\"ArrowLeftRightIcon\"\n                tabler=\"IconArrowsExchange\"\n                hugeicons=\"ArrowDataTransferHorizontalIcon\"\n                phosphor=\"ArrowsLeftRightIcon\"\n                remixicon=\"RiArrowLeftRightLine\"\n                aria-hidden=\"true\"\n              />\n            </Button>\n            <Field className=\"min-w-0 flex-1\">\n              <FieldLabel\n                id=\"contrast-background-label\"\n                htmlFor=\"contrast-background\"\n              >\n                Background\n              </FieldLabel>\n              <ColorPicker\n                id=\"contrast-background\"\n                value={background}\n                onValueChange={setBackground}\n                aria-labelledby=\"contrast-background-label\"\n              />\n            </Field>\n          </div>\n          <div className=\"flex items-center justify-between gap-4\">\n            <div role=\"status\">\n              <p className=\"text-3xl font-semibold tabular-nums\">\n                {ratio ? `${ratio.toFixed(2)}:1` : \"None\"}\n              </p>\n              <p className=\"text-muted-foreground text-xs\">Contrast ratio</p>\n            </div>\n            <ul className=\"flex flex-col items-end gap-1.5\">\n              {CHECKS.map((check) => {\n                const pass = ratio !== null && ratio >= check.min\n                return (\n                  <li\n                    key={`${check.level}-${check.text}`}\n                    className=\"flex items-center gap-2 text-xs\"\n                  >\n                    <span className=\"text-muted-foreground\">\n                      {check.text} {check.level}\n                    </span>\n                    <Badge\n                      variant={pass ? \"success-light\" : \"destructive-light\"}\n                    >\n                      {pass ? \"Pass\" : \"Fail\"}\n                    </Badge>\n                  </li>\n                )\n              })}\n            </ul>\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n  )\n}","target":"components/examples/c-color-picker-13.tsx"}],"meta":{"order":13,"label":"Contrast Checker"}}