{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "checkbox",
  "type": "registry:component",
  "title": "Checkbox",
  "description": "One choice that is on or off, with a tick that draws itself and a parent box for a group.",
  "dependencies": [
    "@base-ui/react",
    "tailwind-variants"
  ],
  "registryDependencies": [],
  "cssVars": {
    "light": {
      "success": "oklch(0.696 0.17 162.48)",
      "info": "oklch(0.623 0.214 259.815)"
    },
    "dark": {
      "success": "oklch(0.696 0.17 162.48)",
      "info": "oklch(0.623 0.214 259.815)"
    }
  },
  "files": [
    {
      "path": "components/panelui/checkbox.tsx",
      "type": "registry:component",
      "target": "@components/panelui/checkbox.tsx",
      "content": "/**\n * Checkbox — one choice that is on or off, usually among others that are too.\n *\n * ```tsx\n * <Label>\n *   <Checkbox defaultChecked />\n *   <Label.Text>Email me a receipt</Label.Text>\n * </Label>\n *\n * <Checkbox.Group defaultValue={['sms']} aria-label=\"Notify me by\">\n *   <Label><Checkbox value=\"email\" /><Label.Text>Email</Label.Text></Label>\n *   <Label><Checkbox value=\"sms\" /><Label.Text>Text message</Label.Text></Label>\n * </Checkbox.Group>\n * ```\n *\n * ## The tick is drawn, not swapped in\n *\n * When it is checked, the tick is drawn as a line from its short end to its\n * long one, the way a pen would make it, and the box fills behind it. Unchecked,\n * the line goes back the way it came. A box that only changes colour is easy to\n * miss in a long list; one that draws its mark is not. With reduced motion the\n * tick appears at once.\n *\n * ## Some, but not all\n *\n * `indeterminate` draws a dash instead of a tick, for a box that stands for a\n * group whose members are mixed. A `Checkbox.Group` with `allValues` does the\n * bookkeeping: a checkbox in it marked `parent` is checked when every member\n * is, a dash when some are, and checks or clears them all when pressed.\n *\n * ## Choosing a colour\n *\n * A checkbox fills with `primary`. `success`, `info` and `destructive` are for\n * a box whose meaning is that colour — \"I accept the risk\" is `destructive`.\n */\nimport { Checkbox as BaseCheckbox } from '@base-ui/react/checkbox';\nimport { CheckboxGroup as BaseCheckboxGroup } from '@base-ui/react/checkbox-group';\nimport type { CSSProperties } from 'react';\nimport { tv } from 'tailwind-variants';\n\nexport type CheckboxSize = 'sm' | 'md' | 'lg';\nexport type CheckboxColor = 'primary' | 'success' | 'info' | 'destructive';\n\nconst checkboxVariants = tv({\n  slots: {\n    root: [\n      'group/checkbox relative inline-flex shrink-0 cursor-pointer items-center justify-center rounded-[0.3rem] border outline-none',\n      'border-input bg-background shadow-xs dark:bg-input/30',\n      'transition-[background-color,border-color,box-shadow] duration-150',\n      'hover:not-data-disabled:border-[color-mix(in_oklab,var(--input),var(--foreground)_25%)]',\n      'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',\n      // Checked or mixed: the box fills with the colour, and the border goes with it.\n      'data-checked:border-(--checkbox-color) data-checked:bg-(--checkbox-color)',\n      'data-indeterminate:border-(--checkbox-color) data-indeterminate:bg-(--checkbox-color)',\n      // Said again for dark mode: `dark:bg-input/30` above outranks a plain\n      // `data-checked:` fill there, which left a checked box empty and its tick\n      // drawn in the dark mark colour on nothing.\n      'dark:data-checked:bg-(--checkbox-color) dark:data-indeterminate:bg-(--checkbox-color)',\n      'aria-invalid:border-destructive aria-invalid:ring-destructive/20',\n      'data-disabled:cursor-not-allowed data-disabled:opacity-50',\n      // A wider target than the box, so it is not a fiddle to hit on a phone.\n      \"after:absolute after:-inset-2 after:content-['']\",\n    ],\n    indicator: 'pointer-events-none absolute inset-0 flex items-center justify-center text-(--checkbox-mark)',\n    mark: 'size-[78%] overflow-visible',\n    // The tick is one path of length ~1; the dash offset draws and undraws it.\n    tick: [\n      '[stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-200 ease-out',\n      'group-data-checked/checkbox:[stroke-dashoffset:0] group-data-checked/checkbox:delay-75',\n      'motion-reduce:transition-none',\n    ],\n    dash: 'origin-center scale-x-0 transition-transform duration-150 group-data-indeterminate/checkbox:scale-x-100 motion-reduce:transition-none',\n    group: 'flex flex-col gap-3',\n  },\n  variants: {\n    size: {\n      sm: { root: 'size-3.5' },\n      md: { root: 'size-4' },\n      lg: { root: 'size-5 rounded-[0.375rem]' },\n    },\n    color: {\n      primary: { root: '[--checkbox-color:var(--primary)] [--checkbox-mark:var(--primary-foreground)]' },\n      success: { root: '[--checkbox-color:var(--success)] [--checkbox-mark:white]' },\n      info: { root: '[--checkbox-color:var(--info)] [--checkbox-mark:white]' },\n      destructive: { root: '[--checkbox-color:var(--destructive)] [--checkbox-mark:white]' },\n    },\n  },\n  defaultVariants: { size: 'md', color: 'primary' },\n});\n\nexport interface CheckboxProps extends Omit<BaseCheckbox.Root.Props, 'className' | 'color'> {\n  /** Default `md`. */\n  size?: CheckboxSize;\n  /** The colour it fills with when checked. `primary` by default. */\n  color?: CheckboxColor;\n  /** What a screen reader calls it, when there is no visible label tied to it. */\n  label?: string;\n  className?: string;\n  style?: CSSProperties;\n}\n\n/**\n * A checkbox. Takes `checked`/`onCheckedChange` or `defaultChecked`,\n * `indeterminate`, and `name` and `value` for a form or a `Checkbox.Group`.\n */\nfunction CheckboxRoot({ size = 'md', color, label, className, ...props }: CheckboxProps) {\n  const slots = checkboxVariants({ size, color });\n  return (\n    <BaseCheckbox.Root data-slot=\"checkbox\" data-size={size} aria-label={label} className={slots.root({ className })} {...props}>\n      <BaseCheckbox.Indicator data-slot=\"checkbox-indicator\" keepMounted className={slots.indicator()}>\n        <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" fill=\"none\" className={slots.mark()}>\n          <path\n            className={slots.tick()}\n            pathLength={1}\n            d=\"M3.5 8.5 6.6 11.5 12.5 4.75\"\n            stroke=\"currentColor\"\n            strokeWidth={2}\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n          />\n          <path className={slots.dash()} d=\"M4 8h8\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" />\n        </svg>\n      </BaseCheckbox.Indicator>\n    </BaseCheckbox.Root>\n  );\n}\nCheckboxRoot.displayName = 'Checkbox';\n\nexport interface CheckboxGroupProps extends Omit<BaseCheckboxGroup.Props, 'className'> {\n  className?: string;\n}\n\n/**\n * Holds the values of the checkboxes inside it as one array. Takes\n * `value`/`onValueChange` or `defaultValue`, and `allValues` for a `parent` box.\n */\nfunction CheckboxGroup({ className, ...props }: CheckboxGroupProps) {\n  return <BaseCheckboxGroup data-slot=\"checkbox-group\" className={checkboxVariants().group({ className })} {...props} />;\n}\nCheckboxGroup.displayName = 'Checkbox.Group';\n\nexport const Checkbox = Object.assign(CheckboxRoot, { Group: CheckboxGroup });\n\nexport { CheckboxGroup };\n"
    }
  ]
}
