{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "impossible-checkbox",
  "title": "Impossible Checkbox",
  "description": "A playful checkbox that a determined bear refuses to leave on.",
  "dependencies": [
    "motion@^13.1.0"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/default/impossible-checkbox/impossible-checkbox.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { motion, useAnimationControls, useReducedMotion } from \"motion/react\"\nimport { cn } from \"@/lib/utils\"\n\nexport interface ImpossibleCheckboxProps extends Omit<\n  React.InputHTMLAttributes<HTMLInputElement>,\n  \"checked\" | \"defaultChecked\" | \"onChange\" | \"type\"\n> {\n  onAttempt?: (attempt: number) => void\n  revealAfter?: number\n  angryAfter?: number\n  className?: string\n}\n\nfunction BearFace({ angry }: { angry: boolean }) {\n  return (\n    <svg\n      viewBox=\"0 0 284.94574 359.73706\"\n      preserveAspectRatio=\"xMinYMin\"\n      aria-hidden=\"true\"\n      className=\"size-full\"\n    >\n      <g transform=\"translate(-7.5271369,-761.38595)\">\n        <g transform=\"matrix(1.2335313,0,0,1.2335313,-35.029693,-212.83637)\">\n          <path\n            d=\"M 263.90933,1081.4151 A 113.96792,96.862576 0 0 0 149.99132,985.71456 113.96792,96.862576 0 0 0 36.090664,1081.4151 l 227.818666,0 z\"\n            fill=\"var(--impossible-bear)\"\n          />\n          <path\n            d=\"m 250.42825,903.36218 c 2e-5,66.27108 -44.75411,114.99442 -102.42825,114.99442 -57.674143,0 -98.428271,-48.72334 -98.428251,-114.99442 4e-6,-66.27106 40.754125,-92.99437 98.428251,-92.99437 57.67413,0 102.42825,26.72331 102.42825,92.99437 z\"\n            fill=\"var(--impossible-bear)\"\n          />\n          <path\n            d=\"m 217,972.86218 c 2e-5,21.53911 -30.44462,42.00002 -68,42.00002 -37.55538,0 -66.000019,-20.46091 -66,-42.00002 0,-21.53911 28.44464,-36 66,-36 37.55536,0 68,14.46089 68,36 z\"\n            fill=\"var(--impossible-muzzle)\"\n          />\n          <path\n            d=\"m 181.5,944.36218 c 0,8.28427 -20.59974,26.5 -32.75,26.5 -12.15026,0 -34.75,-18.21573 -34.75,-26.5 0,-8.28427 22.59974,-13.5 34.75,-13.5 12.15026,0 32.75,5.21573 32.75,13.5 z\"\n            fill=\"var(--impossible-features)\"\n          />\n          <g>\n            <ellipse\n              cx=\"69\"\n              cy=\"823.07269\"\n              rx=\"34.5\"\n              ry=\"33.289474\"\n              fill=\"var(--impossible-bear)\"\n            />\n            <path\n              d=\"M 69,47.310547 A 24.25,23.399124 0 0 0 44.75,70.710938 24.25,23.399124 0 0 0 64.720703,93.720703 c 0.276316,-0.40734 0.503874,-0.867778 0.787109,-1.267578 1.70087,-2.400855 3.527087,-4.666237 5.470704,-6.798828 1.943616,-2.132591 4.004963,-4.133318 6.179687,-6.003906 2.174725,-1.870589 4.461274,-3.611714 6.855469,-5.226563 2.394195,-1.614848 4.896019,-3.10338 7.498047,-4.46875 0.539935,-0.283322 1.133058,-0.500695 1.68164,-0.773437 A 24.25,23.399124 0 0 0 69,47.310547 Z\"\n              transform=\"translate(0,752.36216)\"\n              fill=\"var(--impossible-muzzle)\"\n            />\n          </g>\n          <g transform=\"matrix(-1,0,0,1,300,0)\">\n            <ellipse\n              cx=\"69\"\n              cy=\"823.07269\"\n              rx=\"34.5\"\n              ry=\"33.289474\"\n              fill=\"var(--impossible-bear)\"\n            />\n            <path\n              d=\"M 69,47.310547 A 24.25,23.399124 0 0 0 44.75,70.710938 24.25,23.399124 0 0 0 64.720703,93.720703 c 0.276316,-0.40734 0.503874,-0.867778 0.787109,-1.267578 1.70087,-2.400855 3.527087,-4.666237 5.470704,-6.798828 1.943616,-2.132591 4.004963,-4.133318 6.179687,-6.003906 2.174725,-1.870589 4.461274,-3.611714 6.855469,-5.226563 2.394195,-1.614848 4.896019,-3.10338 7.498047,-4.46875 0.539935,-0.283322 1.133058,-0.500695 1.68164,-0.773437 A 24.25,23.399124 0 0 0 69,47.310547 Z\"\n              transform=\"translate(0,752.36216)\"\n              fill=\"var(--impossible-muzzle)\"\n            />\n          </g>\n          <ellipse\n            cx=\"105.83063\"\n            cy=\"900.38916\"\n            rx=\"9.2701159\"\n            ry=\"9.6790915\"\n            fill=\"var(--impossible-features)\"\n          />\n          <ellipse\n            cx=\"186.89894\"\n            cy=\"900.38916\"\n            rx=\"9.2701159\"\n            ry=\"9.6790915\"\n            fill=\"var(--impossible-features)\"\n          />\n          {angry && (\n            <>\n              <path\n                d=\"m 92.05833,865.4614 39.42665,22.76299\"\n                fill=\"none\"\n                stroke=\"var(--impossible-features)\"\n                strokeLinecap=\"round\"\n                strokeWidth=\"4.86408424\"\n              />\n              <path\n                d=\"m 202.82482,865.4614 -39.42664,22.76299\"\n                fill=\"none\"\n                stroke=\"var(--impossible-features)\"\n                strokeLinecap=\"round\"\n                strokeWidth=\"4.86408424\"\n              />\n            </>\n          )}\n        </g>\n      </g>\n    </svg>\n  )\n}\n\nfunction BearArm() {\n  return (\n    <svg\n      viewBox=\"0 0 250 100\"\n      preserveAspectRatio=\"xMinYMin\"\n      aria-hidden=\"true\"\n      className=\"size-full\"\n    >\n      <g transform=\"translate(868.57141,-900.93359)\">\n        <path\n          d=\"m -619.43416,945.05124 c 4.18776,73.01076 -78.25474,53.24342 -150.21568,52.94118 -82.38711,-0.34602 -98.92158,-19.44459 -98.92157,-47.05883 0,-27.61424 4.78794,-42.54902 73.82353,-42.54902 69.03559,0 171.43607,-30.93764 175.31372,36.66667 z\"\n          fill=\"var(--impossible-bear)\"\n        />\n        <ellipse\n          cx=\"-683.02264\"\n          cy=\"950.98572\"\n          rx=\"29.910826\"\n          ry=\"29.414362\"\n          fill=\"var(--impossible-muzzle)\"\n        />\n      </g>\n    </svg>\n  )\n}\n\nexport const ImpossibleCheckbox = React.forwardRef<\n  HTMLInputElement,\n  ImpossibleCheckboxProps\n>(function ImpossibleCheckbox(\n  {\n    onAttempt,\n    revealAfter = 2,\n    angryAfter = 5,\n    className,\n    \"aria-label\": ariaLabel = \"Impossible checkbox\",\n    \"aria-describedby\": ariaDescribedBy,\n    disabled,\n    ...inputProps\n  },\n  forwardedRef\n) {\n  const [checked, setChecked] = React.useState(false)\n  const [attempts, setAttempts] = React.useState(0)\n  const [busy, setBusy] = React.useState(false)\n  const [message, setMessage] = React.useState(\"Off\")\n  const generatedId = React.useId()\n  const prefersReducedMotion = useReducedMotion()\n  const bear = useAnimationControls()\n  const armWrap = useAnimationControls()\n  const arm = useAnimationControls()\n  const paw = useAnimationControls()\n  const runRef = React.useRef(0)\n\n  React.useEffect(() => {\n    return () => {\n      runRef.current += 1\n      bear.stop()\n      armWrap.stop()\n      arm.stop()\n      paw.stop()\n    }\n  }, [arm, armWrap, bear, paw])\n\n  const bearIsVisible = attempts >= revealAfter\n  const bearIsAngry = attempts >= angryAfter\n  const statusId = `${inputProps.id ?? generatedId}-status`\n\n  async function refuse() {\n    if (busy || disabled) return\n\n    const run = runRef.current + 1\n    runRef.current = run\n    const nextAttempt = attempts + 1\n    const duration = prefersReducedMotion ? 0 : 0.2\n    setBusy(true)\n    setChecked(true)\n    setMessage(\"On, briefly\")\n    onAttempt?.(nextAttempt)\n\n    if (!prefersReducedMotion) {\n      await new Promise((resolve) => window.setTimeout(resolve, 180))\n      if (runRef.current !== run) return\n\n      if (nextAttempt > revealAfter) {\n        await bear.start({\n          y: nextAttempt >= angryAfter ? \"0%\" : \"40%\",\n          transition: { duration: 0.24 },\n        })\n        if (runRef.current !== run) return\n      }\n\n      await armWrap.start({ x: 32, transition: { duration } })\n      if (runRef.current !== run) return\n      await Promise.all([\n        arm.start({ scaleX: 0.7, transition: { duration } }),\n        paw.start({ scaleX: 0.85, transition: { duration: 0.1 } }),\n      ])\n      if (runRef.current !== run) return\n    }\n\n    setChecked(false)\n    setMessage(\"The bear switched it back off\")\n    setAttempts(nextAttempt)\n\n    if (!prefersReducedMotion) {\n      await Promise.all([\n        paw.start({ scaleX: 0, transition: { duration: 0.1 } }),\n        arm.start({ scaleX: 1, transition: { duration: 0.1 } }),\n        armWrap.start({ x: 0, transition: { duration } }),\n        bear.start({ y: \"100%\", transition: { duration: 0.24 } }),\n      ])\n      if (runRef.current !== run) return\n    }\n\n    setBusy(false)\n  }\n\n  function peek() {\n    if (!busy && bearIsVisible && !prefersReducedMotion) {\n      void bear.start({ y: \"40%\", transition: { duration: 0.12 } })\n    }\n  }\n\n  function hide() {\n    if (!busy && !prefersReducedMotion) {\n      void bear.start({ y: \"100%\", transition: { duration: 0.12 } })\n    }\n  }\n\n  return (\n    <div\n      data-slot=\"impossible-checkbox\"\n      className={cn(\n        \"bg-muted relative isolate h-80 w-full max-w-xl overflow-hidden rounded-[var(--radius)] [--impossible-bear:var(--foreground)] [--impossible-features:var(--background)] [--impossible-muzzle:color-mix(in_oklch,var(--background)_82%,var(--foreground))]\",\n        className\n      )}\n    >\n      <motion.div\n        className=\"absolute top-1/2 left-1/2 z-0 h-36 w-28 -translate-x-[15%] -translate-y-3/4\"\n        initial={{ y: \"100%\" }}\n        animate={bear}\n      >\n        {bearIsAngry && (\n          <span className=\"bg-background text-foreground absolute -top-8 left-full z-10 rounded-md px-2.5 py-1.5 text-xs font-bold whitespace-nowrap shadow-sm\">\n            #@$%*!\n          </span>\n        )}\n        <BearFace angry={bearIsAngry} />\n      </motion.div>\n\n      <div className=\"absolute inset-x-0 top-1/2 bottom-0 z-10 bg-inherit\" />\n\n      <motion.div\n        className={cn(\n          \"absolute top-1/2 left-1/2 z-30 h-5 w-14 -translate-y-1/2\",\n          busy ? \"opacity-100\" : \"opacity-0\"\n        )}\n        initial={{ x: 0 }}\n        animate={armWrap}\n      >\n        <motion.div\n          className=\"absolute top-1/2 left-1/2 size-full origin-left -translate-x-[35%] -translate-y-1/2\"\n          initial={{ scaleX: 1 }}\n          animate={arm}\n        >\n          <BearArm />\n        </motion.div>\n      </motion.div>\n\n      <motion.div\n        className=\"absolute top-1/2 left-1/2 z-50 size-5 origin-right translate-x-[52px] -translate-y-1/2 rounded-full bg-[var(--impossible-bear)]\"\n        initial={{ scaleX: 0 }}\n        animate={paw}\n      />\n\n      <label\n        className=\"group has-focus-visible:ring-ring has-focus-visible:ring-offset-muted absolute top-1/2 left-1/2 z-40 h-16 w-32 -translate-x-1/2 -translate-y-1/2 cursor-pointer rounded-full has-focus-visible:ring-2 has-focus-visible:ring-offset-2 has-disabled:cursor-not-allowed has-disabled:opacity-50\"\n        onPointerEnter={peek}\n        onPointerLeave={hide}\n      >\n        <span className=\"sr-only\">{ariaLabel}</span>\n        <input\n          {...inputProps}\n          ref={forwardedRef}\n          type=\"checkbox\"\n          checked={checked}\n          disabled={disabled}\n          aria-label={ariaLabel}\n          aria-describedby={\n            ariaDescribedBy ? `${ariaDescribedBy} ${statusId}` : statusId\n          }\n          onChange={() => void refuse()}\n          className=\"cursor-inherit absolute inset-0 z-10 m-0 size-full opacity-0\"\n        />\n        <span\n          className={cn(\n            \"bg-border absolute inset-0 rounded-full transition-colors duration-200 motion-reduce:transition-none\",\n            checked && \"bg-primary\"\n          )}\n          aria-hidden=\"true\"\n        />\n        <span\n          className={cn(\n            \"bg-background absolute top-1 left-1 size-14 rounded-full shadow-sm transition-transform duration-200 motion-reduce:transition-none\",\n            checked && \"translate-x-16\"\n          )}\n          aria-hidden=\"true\"\n        />\n      </label>\n\n      <span className=\"sr-only\" id={statusId} aria-live=\"polite\">\n        {message}\n      </span>\n    </div>\n  )\n})\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "checkbox",
    "feedback",
    "motion",
    "playful"
  ],
  "type": "registry:ui"
}