{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "checkbox",
  "title": "Checkbox",
  "description": "유니버설 체크박스 — 제어/비제어 checked, 중간 상태(aria-checked=mixed + − 글리프), 44px 터치 타깃 보정. role=checkbox.",
  "dependencies": [
    "@unikit-bridge/ui",
    "class-variance-authority",
    "clsx",
    "tailwind-merge",
    "tailwindcss"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/checkbox.tsx",
      "content": "// Checkbox — shadcn/ui new-york-v4 checkbox를 UniKit UI 브리지로 이식.\n// 포팅 판단:\n// - radix-ui Checkbox（Root/Indicator） 제거 — 체크 상태는 React state（제어/비제어）로\n//   직접 관리하고, 원본의 data-state=checked 셀렉터는 조건부 클래스 문자열로 전개\n//   （네이티브에 data 속성이 없어 상태 셀렉터를 쓸 수 없다）.\n// - CheckIcon·MinusIcon은 브리지 lucide 아이콘 프리미티브를 쓴다（lucide — primitives 경유）.\n// - aria-invalid:* 클래스는 v0.1 API에 invalid 상태가 없어 제외.\n// - 이중 지정 원칙（§0.5）: 체크 배경·테두리는 Pressable, 글리프 색은 내부 Text에 명시.\nimport { forwardRef, useState } from \"react\";\nimport {\n  CheckIcon,\n  MinusIcon,\n  Pressable,\n  type BridgePressableRef,\n  type PressableProps,\n} from \"@unikit-bridge/ui/primitives\";\n\nimport { cn } from \"@/lib/utils\";\n\n// 원본 크기 토큰 유지: size-4（16px） 박스·rounded-sm（UniKit UI 토큰 --radius-sm=4px）·border-input,\n// 체크 시 border/bg-primary.\n// 라벨 없음 — 라벨은 소비자가 Label과 조합한다（checkbox 원본과 동일한 계약）.\nexport type CheckboxProps = Omit<PressableProps, \"onPress\" | \"aria-checked\"> & {\n  /** 제어형 체크 상태（지정 시 내부 state를 대체） */\n  checked?: boolean;\n  /** 비제어형 초기 체크 상태 */\n  defaultChecked?: boolean;\n  /** 체크 전환 콜백 — indeterminate 상태에서 누르면 false가 전달된다 */\n  onCheckedChange?: (checked: boolean) => void;\n  /** 중간 상태 — aria-checked=\"mixed\" + − 글리프（shadcn checked=\"indeterminate\" 대응） */\n  indeterminate?: boolean;\n};\n\n// 터치 타깃 44px 보정: 16px 박스 → hitSlop = （44 − 16） / 2 = 14px.\nconst HIT_SLOP = 14;\n\nconst Checkbox = forwardRef<BridgePressableRef, CheckboxProps>(\n  (\n    {\n      className,\n      checked,\n      defaultChecked = false,\n      onCheckedChange,\n      indeterminate = false,\n      disabled,\n      hitSlop,\n      ...props\n    },\n    ref,\n  ) => {\n    // 제어（checked 지정）/비제어（내부 state） 통합 — 웹·네이티브 한 벌 로직.\n    const [uncontrolled, setUncontrolled] = useState(defaultChecked);\n    const isControlled = checked !== undefined;\n    const isChecked = isControlled ? checked : uncontrolled;\n\n    const handlePress = () => {\n      const next = !isChecked;\n      if (!isControlled) setUncontrolled(next);\n      onCheckedChange?.(next);\n    };\n\n    return (\n      <Pressable\n        ref={ref}\n        accessibilityRole=\"checkbox\"\n        aria-checked={indeterminate ? \"mixed\" : isChecked}\n        aria-disabled={disabled ? true : undefined}\n        disabled={disabled}\n        hitSlop={hitSlop ?? HIT_SLOP}\n        onPress={handlePress}\n        className={cn(\n          \"flex size-4 shrink-0 flex-row items-center justify-center rounded-sm border web:transition-colors web:outline-none web:focus-visible:border-ring web:focus-visible:ring-3 web:focus-visible:ring-ring/50\",\n          // 미체크 링은 border-input（라이트 1.27:1）이 배경에 묻혀 경계가 안\n          // 보이므로 foreground/50（양 모드 ≥3:1, G4）로 조정.\n          indeterminate || isChecked\n            ? \"border-primary bg-primary\"\n            : \"border-foreground/50 dark:bg-input/30\",\n          disabled && \"web:pointer-events-none web:cursor-not-allowed opacity-50\",\n          className,\n        )}\n        {...props}\n      >\n        {/* 아이콘 — 체크 CheckIcon / 중간 MinusIcon. 원본 Indicator처럼 상태일 때만 렌더.\n            원본 CheckIcon은 size-3.5·기본 strokeWidth(2)다. */}\n        {indeterminate ? (\n          <MinusIcon className=\"size-3.5 text-primary-foreground\" />\n        ) : isChecked ? (\n          <CheckIcon className=\"size-3.5 text-primary-foreground\" />\n        ) : null}\n      </Pressable>\n    );\n  },\n);\nCheckbox.displayName = \"Checkbox\";\n\nexport { Checkbox };\n",
      "type": "registry:ui",
      "target": "components/unikit/checkbox.tsx"
    }
  ],
  "type": "registry:ui"
}
