{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "checkbox",
  "title": "Checkbox",
  "author": "andongmin94",
  "description": "A control for toggling one or more independent selections.",
  "dependencies": [
    "@base-ui/react@^1.6.0"
  ],
  "files": [
    {
      "path": "src/components/ui/checkbox.tsx",
      "content": "\"use client\";\n\nimport { Checkbox as CheckboxPrimitive } from \"@base-ui/react/checkbox\";\nimport { mergeProps } from \"@base-ui/react/merge-props\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { CheckIcon } from \"lucide-react\";\n\ntype CheckedState = boolean | \"indeterminate\";\ntype CheckboxProps = Omit<\n  CheckboxPrimitive.Root.Props,\n  \"checked\" | \"defaultChecked\" | \"onCheckedChange\" | \"ref\"\n> & {\n  asChild?: boolean;\n  checked?: CheckedState;\n  children?: React.ReactNode;\n  defaultChecked?: CheckedState;\n  forceMount?: true;\n  onCheckedChange?: (\n    checked: CheckedState,\n    eventDetails: CheckboxPrimitive.Root.ChangeEventDetails,\n  ) => void;\n};\n\ntype RenderProps = React.HTMLAttributes<HTMLElement> & { ref?: React.Ref<HTMLElement> };\n\nfunction mergeRefs(...refs: (React.Ref<HTMLElement> | undefined)[]) {\n  return (element: HTMLElement | null) => {\n    refs.forEach((ref) => {\n      if (typeof ref === \"function\") {\n        ref(element);\n      } else if (ref) {\n        ref.current = element;\n      }\n    });\n  };\n}\n\nfunction preserveRadixEventCancellation(\n  child: React.ReactElement<{ [key: string]: unknown; children?: React.ReactNode }>,\n) {\n  const eventProps: Record<string, unknown> = {};\n\n  for (const [name, handler] of Object.entries(child.props)) {\n    if (/^on[A-Z]/.test(name) && typeof handler === \"function\") {\n      eventProps[name] = (...args: unknown[]) => {\n        (handler as (...handlerArgs: unknown[]) => void)(...args);\n        const event = args[0] as\n          | { defaultPrevented?: boolean; preventBaseUIHandler?: () => void }\n          | undefined;\n        if (event?.defaultPrevented) event.preventBaseUIHandler?.();\n      };\n    }\n  }\n\n  return React.cloneElement(child, eventProps);\n}\n\nfunction renderWithAliases<State>(\n  render:\n    | React.ReactElement\n    | ((props: RenderProps, state: State) => React.ReactElement)\n    | undefined,\n  fallback: React.ReactElement,\n  getAliases: (state: State) => Record<string, string | undefined>,\n) {\n  return (elementProps: RenderProps, state: State) => {\n    const aliasedProps = mergeProps(\n      elementProps as React.ComponentPropsWithRef<\"button\">,\n      getAliases(state) as React.ComponentPropsWithRef<\"button\">,\n    ) as RenderProps;\n\n    if (typeof render === \"function\") {\n      return render(aliasedProps, state);\n    }\n\n    const element = (render ?? fallback) as React.ReactElement<RenderProps>;\n    const mergedProps = mergeProps(\n      aliasedProps as React.ComponentPropsWithRef<\"button\">,\n      element.props as React.ComponentPropsWithRef<\"button\">,\n    ) as RenderProps;\n    mergedProps.ref = mergeRefs(aliasedProps.ref, element.props.ref);\n    return React.cloneElement(element, mergedProps);\n  };\n}\n\nfunction getChildElement(children: React.ReactNode) {\n  const child = React.Children.toArray(children).find(React.isValidElement);\n  if (child === undefined) {\n    throw new Error(\"Checkbox with asChild requires a valid React element child.\");\n  }\n  return preserveRadixEventCancellation(\n    child as React.ReactElement<{ [key: string]: unknown; children?: React.ReactNode }>,\n  );\n}\n\nfunction setRefValue<T>(ref: React.Ref<T> | undefined, value: T | null) {\n  if (typeof ref === \"function\") {\n    ref(value);\n  } else if (ref) {\n    ref.current = value;\n  }\n}\n\nconst Checkbox = React.forwardRef<HTMLButtonElement, CheckboxProps>(function Checkbox(\n  {\n    asChild = false,\n    checked,\n    children,\n    className,\n    defaultChecked,\n    forceMount,\n    form,\n    indeterminate,\n    inputRef,\n    nativeButton,\n    onClick,\n    onCheckedChange,\n    render,\n    ...props\n  },\n  forwardedRef,\n) {\n  const [uncontrolledChecked, setUncontrolledChecked] = React.useState<CheckedState>(\n    defaultChecked ?? false,\n  );\n  const currentChecked = checked ?? uncontrolledChecked;\n  const initialCheckedRef = React.useRef<CheckedState>(defaultChecked ?? false);\n  const [associatedForm, setAssociatedForm] = React.useState<HTMLFormElement | null>(null);\n  const mergedInputRef = React.useCallback(\n    (input: HTMLInputElement | null) => {\n      setRefValue(inputRef, input);\n      setAssociatedForm(input?.form ?? null);\n    },\n    [inputRef],\n  );\n  const renderElement = asChild\n    ? getChildElement(children)\n    : (render ?? React.createElement(\"button\"));\n  const resolvedNativeButton =\n    nativeButton ??\n    (typeof renderElement !== \"function\" &&\n      typeof renderElement.type === \"string\" &&\n      renderElement.type === \"button\");\n\n  React.useEffect(() => {\n    if (checked !== undefined || associatedForm === null) {\n      return undefined;\n    }\n\n    const reset = () => setUncontrolledChecked(initialCheckedRef.current);\n    associatedForm.addEventListener(\"reset\", reset);\n    return () => associatedForm.removeEventListener(\"reset\", reset);\n  }, [associatedForm, checked]);\n\n  return (\n    <CheckboxPrimitive.Root\n      ref={forwardedRef}\n      data-slot=\"checkbox\"\n      checked={currentChecked === true}\n      className={cn(\n        \"peer relative flex size-4 shrink-0 items-center justify-center rounded-base border-2 border-border bg-secondary-background outline-hidden ring-offset-white transition-colors focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-checked:bg-main data-checked:text-main-foreground data-indeterminate:bg-main data-indeterminate:text-main-foreground\",\n        className,\n      )}\n      form={form}\n      indeterminate={indeterminate ?? currentChecked === \"indeterminate\"}\n      inputRef={mergedInputRef}\n      nativeButton={resolvedNativeButton}\n      onClick={(event) => {\n        onClick?.(event);\n        if (event.defaultPrevented) {\n          event.preventBaseUIHandler();\n        }\n      }}\n      onCheckedChange={(nextChecked, eventDetails) => {\n        onCheckedChange?.(nextChecked, eventDetails);\n        if (!eventDetails.isCanceled && checked === undefined) {\n          setUncontrolledChecked(nextChecked);\n        }\n      }}\n      render={renderWithAliases<CheckboxPrimitive.Root.State>(\n        renderElement,\n        React.createElement(\"button\"),\n        (state) => ({\n          \"data-disabled\": state.disabled ? \"\" : undefined,\n          \"data-state\": state.indeterminate\n            ? \"indeterminate\"\n            : state.checked\n              ? \"checked\"\n              : \"unchecked\",\n        }),\n      )}\n      {...props}\n    >\n      <CheckboxPrimitive.Indicator\n        data-slot=\"checkbox-indicator\"\n        className=\"grid place-content-center text-current transition-none [&>svg]:size-3.5\"\n        keepMounted={forceMount}\n        render={renderWithAliases<CheckboxPrimitive.Indicator.State>(\n          undefined,\n          <span />,\n          (state) => ({\n            \"data-disabled\": state.disabled ? \"\" : undefined,\n            \"data-state\": state.indeterminate\n              ? \"indeterminate\"\n              : state.checked\n                ? \"checked\"\n                : \"unchecked\",\n          }),\n        )}\n      >\n        <CheckIcon />\n      </CheckboxPrimitive.Indicator>\n    </CheckboxPrimitive.Root>\n  );\n});\n\nexport { Checkbox };\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "form",
    "selection"
  ],
  "type": "registry:ui"
}