{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "checkbox",
  "title": "Checkbox",
  "description": "A checkbox component.",
  "dependencies": [
    "@hugeicons/react",
    "@hugeicons/core-free-icons"
  ],
  "files": [
    {
      "path": "registry/default/checkbox/checkbox.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Checkbox as BaseCheckbox } from \"@base-ui/react/checkbox\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { CheckIcon, MinusSignIcon } from \"@hugeicons/core-free-icons\";\n\nimport { cn } from \"@/lib/utils\";\n\n// Both marks draw themselves in. `pathLength` restates each path as 1 unit\n// long, so the dash values are fractions of the stroke and survive a HugeIcons\n// reshape. Deriving the icon array is the only way to reach the path.\nconst checkIcon = CheckIcon.map(([tag, attrs]) => [\n  tag,\n  { ...attrs, pathLength: 1 },\n]) as typeof CheckIcon;\n\nconst minusIcon = MinusSignIcon.map(([tag, attrs]) => [\n  tag,\n  { ...attrs, pathLength: 1 },\n]) as typeof MinusSignIcon;\n\n// Shared crossfade: the two marks stack in one grid cell, so each scales and\n// blurs past the other instead of popping. `base` holds the hidden resting\n// state; the active state is restored by the per-mark variant.\nconst markBase =\n  \"scale-90 opacity-0 ease-out-expo transition-[opacity,filter,transform,scale] duration-200 in-data-starting-style:scale-90 in-data-starting-style:opacity-0 motion-reduce:transition-none\";\n\n// Draw-on: dasharray 1 is the whole stroke (see `pathLength` above), so\n// offset 1 -> 0 sweeps the mark in. The delay lets the outgoing mark clear\n// first during an indeterminate swap.\nconst checkClasses = cn(\n  markBase,\n  \"not-in-data-indeterminate:scale-100 not-in-data-indeterminate:opacity-100 in-data-indeterminate:blur-[2px]\",\n  \"[&_path]:ease-out-expo [&_path]:transition-[stroke-dashoffset] [&_path]:duration-200 [&_path]:[stroke-dasharray:1]\",\n  \"not-in-data-indeterminate:[&_path]:delay-15 not-in-data-indeterminate:[&_path]:[stroke-dashoffset:0]\",\n  \"in-data-indeterminate:[&_path]:[stroke-dashoffset:1] in-data-starting-style:[&_path]:[stroke-dashoffset:1]\",\n  \"motion-reduce:[&_path]:transition-none\",\n);\n\nconst minusClasses = cn(\n  markBase,\n  \"in-data-indeterminate:scale-100 in-data-indeterminate:opacity-100 not-in-data-indeterminate:blur-[2px]\",\n  \"[&_path]:ease-out-expo [&_path]:transition-[stroke-dashoffset] [&_path]:duration-200 [&_path]:[stroke-dasharray:1]\",\n  \"not-in-data-indeterminate:[&_path]:[stroke-dashoffset:1] in-data-starting-style:[&_path]:[stroke-dashoffset:1]\",\n  \"in-data-indeterminate:[&_path]:delay-15 in-data-indeterminate:[&_path]:[stroke-dashoffset:0]\",\n  \"motion-reduce:[&_path]:transition-none\",\n);\n\nfunction Checkbox({\n  className,\n  variant = \"default\",\n  ...props\n}: React.ComponentProps<typeof BaseCheckbox.Root> & {\n  variant?: \"default\" | \"elevated\";\n}) {\n  return (\n    <BaseCheckbox.Root\n      data-slot=\"checkbox\"\n      className={cn(\n        \"peer text-primary-foreground aria-invalid:outline-destructive/50 aria-invalid:text-destructive focus-visible:outline-ring/50 ease-out-expo relative flex aspect-square size-4.5 shrink-0 items-center justify-center rounded-xs outline-0 outline-offset-0 outline-transparent transition-[outline-width,outline-offset,outline-color] duration-200 outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 aria-invalid:outline-2 aria-invalid:outline-offset-2 aria-invalid:outline-solid data-disabled:cursor-not-allowed data-disabled:opacity-60 motion-reduce:transition-none sm:not-pointer-coarse:size-4\",\n        // Edge: real border + bg-clip-padding so the border draws on the\n        // substrate (matches Input). The ::before fill uses -inset-px to\n        // extend over the border area when checked, hiding it completely.\n        \"border bg-clip-padding\",\n        variant === \"default\" ? \"bg-input\" : \"bg-input-elevated\",\n        // Background scale animation using ::before pseudo-element\n        \"before:bg-primary before:absolute before:-inset-px before:rounded-xs before:content-['']\",\n        \"before:ease-out-expo before:origin-center before:scale-80 before:transform-gpu before:opacity-0 before:transition-[transform,opacity,scale] before:duration-200 before:will-change-transform motion-reduce:before:transition-none\",\n        \"data-checked:before:scale-100 data-checked:before:opacity-100\",\n        \"data-indeterminate:before:scale-100 data-indeterminate:before:opacity-100\",\n        className,\n      )}\n      {...props}\n    >\n      <BaseCheckbox.Indicator\n        data-slot=\"checkbox-indicator\"\n        className=\"ease-out-expo grid place-items-center transition-opacity duration-200 *:col-start-1 *:row-start-1 data-ending-style:opacity-0 data-starting-style:opacity-0 motion-reduce:transition-none\"\n      >\n        <HugeiconsIcon\n          icon={checkIcon}\n          strokeWidth={2.5}\n          className={cn(\"size-3.5\", checkClasses)}\n        />\n        <HugeiconsIcon\n          icon={minusIcon}\n          strokeWidth={2.5}\n          className={cn(\"size-3.5\", minusClasses)}\n        />\n      </BaseCheckbox.Indicator>\n    </BaseCheckbox.Root>\n  );\n}\n\nexport { Checkbox };\n",
      "type": "registry:ui",
      "target": "components/ui/cubby-ui/checkbox.tsx"
    }
  ],
  "type": "registry:ui"
}