{
  "name": "stateful-button",
  "type": "registry:ui",
  "files": [
    {
      "path": "components/ui/stateful-button.tsx",
      "content": "\"use client\";\nimport { cn } from \"@/lib/utils\";\nimport React from \"react\";\nimport { motion, AnimatePresence, useAnimate } from \"motion/react\";\n\ninterface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  className?: string;\n  children: React.ReactNode;\n}\n\nexport const Button = ({ className, children, ...props }: ButtonProps) => {\n  const [scope, animate] = useAnimate();\n\n  const animateLoading = async () => {\n    await animate(\n      \".loader\",\n      {\n        width: \"20px\",\n        scale: 1,\n        display: \"block\",\n      },\n      {\n        duration: 0.2,\n      },\n    );\n  };\n\n  const animateSuccess = async () => {\n    await animate(\n      \".loader\",\n      {\n        width: \"0px\",\n        scale: 0,\n        display: \"none\",\n      },\n      {\n        duration: 0.2,\n      },\n    );\n    await animate(\n      \".check\",\n      {\n        width: \"20px\",\n        scale: 1,\n        display: \"block\",\n      },\n      {\n        duration: 0.2,\n      },\n    );\n\n    await animate(\n      \".check\",\n      {\n        width: \"0px\",\n        scale: 0,\n        display: \"none\",\n      },\n      {\n        delay: 2,\n        duration: 0.2,\n      },\n    );\n  };\n\n  const handleClick = async (event: React.MouseEvent<HTMLButtonElement>) => {\n    await animateLoading();\n    await props.onClick?.(event);\n    await animateSuccess();\n  };\n\n  const {\n    onClick,\n    onDrag,\n    onDragStart,\n    onDragEnd,\n    onAnimationStart,\n    onAnimationEnd,\n    ...buttonProps\n  } = props;\n\n  return (\n    <motion.button\n      layout\n      layoutId=\"button\"\n      ref={scope}\n      className={cn(\n        \"flex min-w-[120px] cursor-pointer items-center justify-center gap-2 rounded-full bg-green-500 px-4 py-2 font-medium text-white ring-offset-2 transition duration-200 hover:ring-2 hover:ring-green-500 dark:ring-offset-black\",\n        className,\n      )}\n      {...buttonProps}\n      onClick={handleClick}\n    >\n      <motion.div layout className=\"flex items-center gap-2\">\n        <Loader />\n        <CheckIcon />\n        <motion.span layout>{children}</motion.span>\n      </motion.div>\n    </motion.button>\n  );\n};\n\nconst Loader = () => {\n  return (\n    <motion.svg\n      animate={{\n        rotate: [0, 360],\n      }}\n      initial={{\n        scale: 0,\n        width: 0,\n        display: \"none\",\n      }}\n      style={{\n        scale: 0.5,\n        display: \"none\",\n      }}\n      transition={{\n        duration: 0.3,\n        repeat: Infinity,\n        ease: \"linear\",\n      }}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"24\"\n      height=\"24\"\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      className=\"loader text-white\"\n    >\n      <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\n      <path d=\"M12 3a9 9 0 1 0 9 9\" />\n    </motion.svg>\n  );\n};\n\nconst CheckIcon = () => {\n  return (\n    <motion.svg\n      initial={{\n        scale: 0,\n        width: 0,\n        display: \"none\",\n      }}\n      style={{\n        scale: 0.5,\n        display: \"none\",\n      }}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"24\"\n      height=\"24\"\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      className=\"check text-white\"\n    >\n      <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\n      <path d=\"M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0\" />\n      <path d=\"M9 12l2 2l4 -4\" />\n    </motion.svg>\n  );\n};\n",
      "type": "registry:ui",
      "target": "components/ui/stateful-button.tsx"
    }
  ],
  "author": "Manu Arora <hi@manuarora.in>",
  "title": "Stateful Button"
}