{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "checkbox-pro",
  "type": "registry:ui",
  "title": "Checkbox Pro",
  "description": "A switchable element to mark an option as checked or unchecked.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["motion", "lucide-react", "clsx", "tailwind-merge"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/checkbox-pro.tsx",
      "content": "'use client';\nimport * as React from 'react';\nimport { CheckIcon, MinusIcon } from 'lucide-react';\nimport { motion } from 'motion/react';\nimport { cn } from '@/lib/utils';\n\ntype CheckedState = boolean | 'indeterminate';\n\ninterface CheckboxProProps {\n  className?: string;\n  onCheckedChange?: (checked: CheckedState) => void;\n  disabled?: boolean;\n  defaultChecked?: CheckedState;\n  checked?: CheckedState;\n  id?: string;\n  name?: string;\n  value?: string;\n  required?: boolean;\n  asChild?: boolean;\n  forceMount?: boolean;\n  'aria-label'?: string;\n  'aria-labelledby'?: string;\n  'aria-describedby'?: string;\n}\n\nfunction AsChild({\n  asChild,\n  children,\n  ...props\n}: {\n  asChild?: boolean;\n  children: React.ReactElement;\n} & React.HTMLAttributes<HTMLElement>) {\n  if (asChild && React.isValidElement(children)) {\n    return React.cloneElement(children, {\n      ...(children.props as Record<string, unknown>),\n      ...props,\n      className: cn(\n        (children.props as { className?: string }).className,\n        props.className,\n      ),\n    } as React.HTMLAttributes<HTMLElement>);\n  }\n  return children;\n}\n\nfunction CheckboxPro({\n  className,\n  onCheckedChange,\n  disabled = false,\n  defaultChecked = false,\n  checked: checkedProp,\n  id,\n  name,\n  value,\n  required = false,\n  asChild = false,\n  forceMount = false,\n  'aria-label': ariaLabel,\n  'aria-labelledby': ariaLabelledby,\n  'aria-describedby': ariaDescribedby,\n  children,\n  ...props\n}: CheckboxProProps &\n  React.HTMLAttributes<HTMLButtonElement> & { children?: React.ReactElement }) {\n  const [animationKey, setAnimationKey] = React.useState(0);\n  const [internalChecked, setInternalChecked] =\n    React.useState<CheckedState>(defaultChecked);\n  const [isKeyboardUser, setIsKeyboardUser] = React.useState(false);\n  const buttonRef = React.useRef<HTMLButtonElement>(null);\n\n  const isControlled = checkedProp !== undefined;\n  const checked = isControlled ? checkedProp : internalChecked;\n  const isIndeterminate = checked === 'indeterminate';\n  const isChecked = checked === true;\n\n  const getDataState = (\n    checked: CheckedState,\n  ): 'checked' | 'unchecked' | 'indeterminate' => {\n    if (checked === 'indeterminate') return 'indeterminate';\n    return checked ? 'checked' : 'unchecked';\n  };\n\n  const handleToggle = React.useCallback(() => {\n    if (disabled) return;\n\n    let newChecked: CheckedState;\n\n    if (isIndeterminate) {\n      newChecked = false;\n    } else {\n      newChecked = !isChecked;\n    }\n\n    setAnimationKey((prev) => prev + 1);\n\n    if (!isControlled) {\n      setInternalChecked(newChecked);\n    }\n\n    onCheckedChange?.(newChecked);\n\n    if (isKeyboardUser) {\n      requestAnimationFrame(() => {\n        buttonRef.current?.focus();\n      });\n    }\n  }, [\n    disabled,\n    isControlled,\n    onCheckedChange,\n    isKeyboardUser,\n    isIndeterminate,\n    isChecked,\n  ]);\n\n  const handleKeyDown = React.useCallback(\n    (event: React.KeyboardEvent<HTMLButtonElement>) => {\n      setIsKeyboardUser(true);\n\n      if (event.key === ' ') {\n        event.preventDefault();\n        event.stopPropagation();\n        handleToggle();\n      } else if (event.key === 'Enter') {\n        event.preventDefault();\n        event.stopPropagation();\n        handleToggle();\n      }\n    },\n    [handleToggle],\n  );\n\n  const handleClick = React.useCallback(\n    (event: React.MouseEvent<HTMLButtonElement>) => {\n      setIsKeyboardUser(false);\n      event.preventDefault();\n      event.stopPropagation();\n      handleToggle();\n    },\n    [handleToggle],\n  );\n\n  const handleFocus = React.useCallback(\n    (event: React.FocusEvent<HTMLButtonElement>) => {\n      props.onFocus?.(event);\n    },\n    [props],\n  );\n\n  const handleBlur = React.useCallback(\n    (event: React.FocusEvent<HTMLButtonElement>) => {\n      setIsKeyboardUser(false);\n      props.onBlur?.(event);\n    },\n    [props],\n  );\n\n  React.useEffect(() => {\n    const handleGlobalKeyDown = (event: KeyboardEvent) => {\n      if (event.key === 'Tab') {\n        setIsKeyboardUser(true);\n      }\n    };\n\n    const handleGlobalMouseDown = () => {\n      setIsKeyboardUser(false);\n    };\n\n    document.addEventListener('keydown', handleGlobalKeyDown);\n    document.addEventListener('mousedown', handleGlobalMouseDown);\n\n    return () => {\n      document.removeEventListener('keydown', handleGlobalKeyDown);\n      document.removeEventListener('mousedown', handleGlobalMouseDown);\n    };\n  }, []);\n\n  const getAriaChecked = (checked: CheckedState): boolean | 'mixed' => {\n    if (checked === 'indeterminate') return 'mixed';\n    return checked === true;\n  };\n\n  const checkboxButton = (\n    <motion.button\n      ref={buttonRef}\n      key={`checkbox-${animationKey}`}\n      type='button'\n      role='checkbox'\n      aria-checked={getAriaChecked(checked)}\n      aria-label={ariaLabel}\n      aria-labelledby={ariaLabelledby}\n      aria-describedby={ariaDescribedby}\n      aria-required={required}\n      disabled={disabled}\n      id={id}\n      data-state={getDataState(checked)}\n      data-disabled={disabled ? '' : undefined}\n      className={cn(\n        'relative peer border bg-input-background dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground dark:data-[state=checked]:bg-primary dark:data-[state=indeterminate]:bg-primary data-[state=checked]:border-primary data-[state=indeterminate]:border-primary size-4 shrink-0 rounded-[4px] shadow-2xs transition-colors outline-hidden',\n        isKeyboardUser &&\n          'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n        disabled\n          ? 'opacity-50 cursor-not-allowed'\n          : 'cursor-pointer hover:bg-accent/50',\n        className,\n      )}\n      onClick={handleClick}\n      onKeyDown={handleKeyDown}\n      onFocus={handleFocus}\n      onBlur={handleBlur}\n      tabIndex={disabled ? -1 : 0}\n      initial={{ scale: 1, rotate: 0, x: 0, y: 0 }}\n      animate={{\n        x: [0, -2, 2, -1.5, 1.5, 0],\n        y: [0, -1, 1, -0.5, 0.5, 0],\n        scale: [1, 0.9, 1.1, 0.95, 1.05, 1],\n        rotate: [0, -3, 3, -2, 2, 0],\n      }}\n      transition={{\n        duration: 0.4,\n        ease: 'easeInOut',\n        times: [0, 0.15, 0.3, 0.5, 0.7, 1],\n      }}\n      whileHover={\n        disabled ? {} : { scale: 1.05, transition: { duration: 0.1 } }\n      }\n      whileTap={disabled ? {} : { scale: 0.95, transition: { duration: 0.05 } }}\n      style={{ transformOrigin: 'center' }}\n    >\n      {(forceMount || isChecked || isIndeterminate) && (\n        <CheckboxProIndicator forceMount={forceMount} checked={checked} />\n      )}\n    </motion.button>\n  );\n\n  const hiddenInput = (name || value) && (\n    <input\n      type='checkbox'\n      name={name}\n      value={value}\n      checked={isChecked}\n      onChange={() => {}}\n      tabIndex={-1}\n      aria-hidden='true'\n      className='sr-only absolute -left-2499.75'\n      disabled={disabled}\n      required={required}\n    />\n  );\n\n  return (\n    <>\n      <AsChild\n        asChild={asChild}\n        {...(asChild ? { children: children as React.ReactElement } : {})}\n      >\n        {asChild && children ? children : checkboxButton}\n      </AsChild>\n      {hiddenInput}\n    </>\n  );\n}\n\ninterface CheckboxProIndicatorProps {\n  forceMount?: boolean;\n  checked: CheckedState;\n  className?: string;\n  asChild?: boolean;\n  children?: React.ReactElement;\n}\n\nfunction CheckboxProIndicator({\n  forceMount = false,\n  checked,\n  className,\n  asChild = false,\n  children,\n}: CheckboxProIndicatorProps) {\n  const isIndeterminate = checked === 'indeterminate';\n  const isChecked = checked === true;\n  const shouldShow = forceMount || isChecked || isIndeterminate;\n\n  if (!shouldShow) return null;\n\n  const indicator = (\n    <motion.div\n      data-slot='checkbox-indicator'\n      className={cn(\n        'flex items-center justify-center text-current w-full h-full pointer-events-none absolute inset-0',\n        className,\n      )}\n      initial={{ scale: 0, opacity: 0, rotate: isIndeterminate ? 0 : -90 }}\n      animate={{ scale: 1, opacity: 1, rotate: 0 }}\n      exit={{ scale: 0, opacity: 0, rotate: isIndeterminate ? 0 : 90 }}\n      transition={{\n        delay: 0.1,\n        duration: 0.2,\n        type: 'spring',\n        stiffness: 400,\n        damping: 25,\n      }}\n    >\n      <motion.div\n        initial={{ scale: 0 }}\n        animate={{ scale: 1 }}\n        transition={{\n          delay: 0.15,\n          type: 'spring',\n          stiffness: 600,\n          damping: 30,\n          duration: 0.15,\n        }}\n      >\n        {isIndeterminate ? (\n          <MinusIcon className='size-3.5 pointer-events-none' />\n        ) : (\n          <CheckIcon className='size-3.5 pointer-events-none' />\n        )}\n      </motion.div>\n    </motion.div>\n  );\n\n  return (\n    <AsChild asChild={asChild} className={className}>\n      {asChild && children ? children : indicator}\n    </AsChild>\n  );\n}\n\nexport { CheckboxPro, CheckboxProIndicator, type CheckedState };\n"
    },
    {
      "type": "registry:lib",
      "path": "lib/utils.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}"
    }
  ]
}
