{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "checkbox-card",
  "title": "Card checkbox",
  "description": "Styled checkbox: the Card set. 5 decorative checkbox variations (CardCheckbox, TileCheckbox, PanelCheckbox, BorderedCheckbox, FilledCardCheckbox) on the ai2 token system, powered by framer-motion, reduced-motion aware and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "motion@^12.42.2",
    "lucide-react@^1.23.0"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/checkbox-card.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Check } from \"lucide-react\"\nimport { motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Card checkbox family: 5 selection cards. The difference is not in the box\n   itself but in the SHELL: the whole card/tile/panel is the clickable control\n   (role=\"checkbox\") and the box is only an indicator. The accessible name comes\n   from the visible label inside the card via aria-labelledby; the ids are\n   produced by React.useId(). Because the box stays under 24px it keeps the\n   standard invisible touch-area extension (after:-inset-1.5), even though the\n   card itself is already a large target. Color comes ONLY from tokens, via alpha\n   color-mix. framer-motion switches instantly under reduced-motion. Used\n   uncontrolled (defaultChecked) or controlled (checked/onCheckedChange). */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nconst boxSize: Record<StyledSize, string> = {\n  sm: \"size-4\",\n  md: \"size-5\",\n  lg: \"size-6\",\n  xl: \"size-7\",\n}\n\nconst iconSize: Record<StyledSize, string> = {\n  sm: \"size-3\",\n  md: \"size-3.5\",\n  lg: \"size-4\",\n  xl: \"size-5\",\n}\n\nconst textSize: Record<StyledSize, string> = {\n  sm: \"text-xs\",\n  md: \"text-sm\",\n  lg: \"text-sm\",\n  xl: \"text-base\",\n}\n\nconst cardPad: Record<StyledSize, string> = {\n  sm: \"gap-2.5 p-2.5\",\n  md: \"gap-3 p-3\",\n  lg: \"gap-3 p-4\",\n  xl: \"gap-4 p-5\",\n}\n\n/* Kart kabugu: genis hedef, focus halkasi, gecerlilik gorunumu. */\nconst cardBase =\n  \"relative flex w-full max-w-xs cursor-pointer select-none items-center text-left outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-danger aria-invalid:ring-danger/20 dark:aria-invalid:ring-danger/40 [&_svg]:shrink-0 [&_i]:leading-none\"\n\n/* The box indicator: the touch-area extension stays even though the card itself is\n   the control. */\nconst boxBase =\n  \"relative inline-flex shrink-0 items-center justify-center rounded-md border transition-colors after:absolute after:-inset-1.5\"\n\n/* Transition type: instant under reduced-motion, spring otherwise. */\ntype SpringLike = { duration: number } | { type: \"spring\"; stiffness: number; damping: number }\n\ntype CheckboxProps = Omit<React.ComponentProps<\"button\">, \"onChange\"> & {\n  size?: StyledSize\n  label?: string\n  checked?: boolean\n  defaultChecked?: boolean\n  onCheckedChange?: (checked: boolean) => void\n}\n\nfunction useCheckbox(props: {\n  checked?: boolean\n  defaultChecked?: boolean\n  onCheckedChange?: (checked: boolean) => void\n}) {\n  const { checked, defaultChecked, onCheckedChange } = props\n  const reduce = useReducedMotion()\n  const [internal, setInternal] = React.useState(defaultChecked ?? false)\n  const on = checked ?? internal\n  const toggle = () => {\n    if (checked === undefined) setInternal((v) => !v)\n    onCheckedChange?.(!on)\n  }\n  const spring: SpringLike = reduce\n    ? { duration: 0 }\n    : { type: \"spring\" as const, stiffness: 500, damping: 30 }\n  return { on, toggle, spring, reduce }\n}\n\n/* Kutu icindeki isaret: yay ile olceklenerek girer. */\nfunction CheckMark({\n  on,\n  size,\n  spring,\n}: {\n  on: boolean\n  size: StyledSize\n  spring: SpringLike\n}) {\n  return (\n    <motion.span\n      initial={false}\n      animate={{ scale: on ? 1 : 0, opacity: on ? 1 : 0 }}\n      transition={spring}\n      className=\"flex items-center justify-center\"\n    >\n      <Check className={cn(iconSize[size], \"stroke-[3]\")} />\n    </motion.span>\n  )\n}\n\n/* Card: a card with a soft token fill whose border turns primary when selected. */\nexport function CardCheckbox({\n  className,\n  size = \"md\",\n  label = \"Enable notifications\",\n  checked,\n  defaultChecked,\n  onCheckedChange,\n  ...props\n}: CheckboxProps) {\n  const { on, toggle, spring } = useCheckbox({ checked, defaultChecked, onCheckedChange })\n  const labelId = React.useId()\n  return (\n    <button\n      type=\"button\"\n      role=\"checkbox\"\n      aria-checked={on}\n      aria-labelledby={labelId}\n      data-slot=\"styled-checkbox\"\n      onClick={toggle}\n      className={cn(\n        cardBase,\n        cardPad[size],\n        \"rounded-lg border\",\n        on\n          ? \"border-primary bg-[color-mix(in_oklab,var(--color-primary)_8%,transparent)]\"\n          : \"border-border bg-card hover:bg-[color-mix(in_oklab,var(--color-foreground)_4%,transparent)]\",\n        className\n      )}\n      {...props}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          boxBase,\n          boxSize[size],\n          on ? \"border-primary bg-primary text-primary-foreground\" : \"border-field-border text-transparent\"\n        )}\n      >\n        <CheckMark on={on} size={size} spring={spring} />\n      </span>\n      <span id={labelId} className={cn(textSize[size], \"font-medium text-foreground\")}>\n        {label}\n      </span>\n    </button>\n  )\n}\n\n/* Tile: dikey ortalanmis kare tile, isaret rozeti sag ustte belirir. */\nexport function TileCheckbox({\n  className,\n  size = \"md\",\n  label = \"Compact\",\n  checked,\n  defaultChecked,\n  onCheckedChange,\n  ...props\n}: CheckboxProps) {\n  const { on, toggle, spring } = useCheckbox({ checked, defaultChecked, onCheckedChange })\n  const labelId = React.useId()\n  return (\n    <button\n      type=\"button\"\n      role=\"checkbox\"\n      aria-checked={on}\n      aria-labelledby={labelId}\n      data-slot=\"styled-checkbox\"\n      onClick={toggle}\n      className={cn(\n        cardBase,\n        cardPad[size],\n        \"w-auto flex-col items-center justify-center rounded-xl border text-center\",\n        on\n          ? \"border-primary bg-[color-mix(in_oklab,var(--color-primary)_10%,transparent)]\"\n          : \"border-border bg-card hover:bg-[color-mix(in_oklab,var(--color-foreground)_4%,transparent)]\",\n        className\n      )}\n      {...props}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          boxBase,\n          boxSize[size],\n          \"rounded-full\",\n          on ? \"border-primary bg-primary text-primary-foreground\" : \"border-field-border text-transparent\"\n        )}\n      >\n        <CheckMark on={on} size={size} spring={spring} />\n      </span>\n      <span id={labelId} className={cn(textSize[size], \"font-medium text-foreground\")}>\n        {label}\n      </span>\n    </button>\n  )\n}\n\n/* Panel: sol tarafta isaretlenince buyuyen aksan cubugu tasiyan genis panel. */\nexport function PanelCheckbox({\n  className,\n  size = \"md\",\n  label = \"Weekly digest\",\n  checked,\n  defaultChecked,\n  onCheckedChange,\n  ...props\n}: CheckboxProps) {\n  const { on, toggle, spring } = useCheckbox({ checked, defaultChecked, onCheckedChange })\n  const labelId = React.useId()\n  return (\n    <button\n      type=\"button\"\n      role=\"checkbox\"\n      aria-checked={on}\n      aria-labelledby={labelId}\n      data-slot=\"styled-checkbox\"\n      onClick={toggle}\n      className={cn(\n        cardBase,\n        cardPad[size],\n        \"overflow-hidden rounded-lg border border-border bg-card pl-4\",\n        on\n          ? \"bg-[color-mix(in_oklab,var(--color-primary)_6%,transparent)]\"\n          : \"hover:bg-[color-mix(in_oklab,var(--color-foreground)_4%,transparent)]\",\n        className\n      )}\n      {...props}\n    >\n      <motion.span\n        aria-hidden=\"true\"\n        initial={false}\n        animate={{ scaleY: on ? 1 : 0 }}\n        transition={spring}\n        className=\"absolute inset-y-0 left-0 w-1 origin-center bg-primary\"\n      />\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          boxBase,\n          boxSize[size],\n          on ? \"border-primary bg-primary text-primary-foreground\" : \"border-field-border text-transparent\"\n        )}\n      >\n        <CheckMark on={on} size={size} spring={spring} />\n      </span>\n      <span id={labelId} className={cn(textSize[size], \"font-medium text-foreground\")}>\n        {label}\n      </span>\n    </button>\n  )\n}\n\n/* Bordered: no fill, only the border and the ring thicken. */\nexport function BorderedCheckbox({\n  className,\n  size = \"md\",\n  label = \"Outline only\",\n  checked,\n  defaultChecked,\n  onCheckedChange,\n  ...props\n}: CheckboxProps) {\n  const { on, toggle, spring } = useCheckbox({ checked, defaultChecked, onCheckedChange })\n  const labelId = React.useId()\n  return (\n    <button\n      type=\"button\"\n      role=\"checkbox\"\n      aria-checked={on}\n      aria-labelledby={labelId}\n      data-slot=\"styled-checkbox\"\n      onClick={toggle}\n      className={cn(\n        cardBase,\n        cardPad[size],\n        \"rounded-lg border-2 bg-transparent\",\n        on\n          ? \"border-primary text-foreground\"\n          : \"border-border hover:border-[color-mix(in_oklab,var(--color-foreground)_24%,transparent)]\",\n        className\n      )}\n      {...props}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          boxBase,\n          boxSize[size],\n          on ? \"border-primary text-primary\" : \"border-field-border text-transparent\"\n        )}\n      >\n        <CheckMark on={on} size={size} spring={spring} />\n      </span>\n      <span id={labelId} className={cn(textSize[size], \"font-medium text-foreground\")}>\n        {label}\n      </span>\n    </button>\n  )\n}\n\n/* FilledCard: isaretlenince kartin tamami primary yuzeye doner. */\nexport function FilledCardCheckbox({\n  className,\n  size = \"md\",\n  label = \"Solid card\",\n  checked,\n  defaultChecked,\n  onCheckedChange,\n  ...props\n}: CheckboxProps) {\n  const { on, toggle, spring } = useCheckbox({ checked, defaultChecked, onCheckedChange })\n  const labelId = React.useId()\n  return (\n    <button\n      type=\"button\"\n      role=\"checkbox\"\n      aria-checked={on}\n      aria-labelledby={labelId}\n      data-slot=\"styled-checkbox\"\n      onClick={toggle}\n      className={cn(\n        cardBase,\n        cardPad[size],\n        \"rounded-lg border\",\n        on\n          ? \"border-primary bg-primary text-primary-foreground\"\n          : \"border-border bg-card text-foreground hover:bg-[color-mix(in_oklab,var(--color-foreground)_4%,transparent)]\",\n        className\n      )}\n      {...props}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          boxBase,\n          boxSize[size],\n          on\n            ? \"border-primary-foreground bg-primary-foreground text-primary\"\n            : \"border-field-border text-transparent\"\n        )}\n      >\n        <CheckMark on={on} size={size} spring={spring} />\n      </span>\n      <span id={labelId} className={cn(textSize[size], \"font-medium\")}>\n        {label}\n      </span>\n    </button>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/checkbox-card.tsx"
    }
  ],
  "categories": [
    "styled",
    "checkbox"
  ],
  "type": "registry:component"
}