{"$schema":"https://ui.shadcn.com/schema/registry-item.json","author":"Eduardo Calvo <educlopez93@gmail.com>","css":{},"dependencies":["motion","lucide-react"],"description":"A ButtonCopy component for SmoothUI.","devDependencies":[],"files":[{"content":"\"use client\";\n\nimport { Check, Copy, LoaderCircle } from \"lucide-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { type ReactNode, useCallback, useState } from \"react\";\n\nexport interface ButtonCopyProps {\n  className?: string;\n  disabled?: boolean;\n  duration?: number;\n  idleIcon?: ReactNode;\n  loadingDuration?: number;\n  loadingIcon?: ReactNode;\n  onCopy?: () => Promise<void> | void;\n  successIcon?: ReactNode;\n}\n\nconst defaultIcons = {\n  idle: <Copy size={16} />,\n  loading: <LoaderCircle className=\"animate-spin\" size={16} />,\n  success: <Check size={16} />,\n};\n\nexport default function ButtonCopy({\n  onCopy,\n  idleIcon = defaultIcons.idle,\n  loadingIcon = defaultIcons.loading,\n  successIcon = defaultIcons.success,\n  className = \"\",\n  duration = 2000,\n  loadingDuration = 1000,\n  disabled = false,\n}: ButtonCopyProps) {\n  const [buttonState, setButtonState] = useState<\n    \"idle\" | \"loading\" | \"success\"\n  >(\"idle\");\n  const shouldReduceMotion = useReducedMotion();\n\n  const handleClick = useCallback(async () => {\n    setButtonState(\"loading\");\n    if (onCopy) {\n      await onCopy();\n    }\n    setTimeout(() => {\n      setButtonState(\"success\");\n    }, loadingDuration);\n    setTimeout(() => {\n      setButtonState(\"idle\");\n    }, loadingDuration + duration);\n  }, [onCopy, loadingDuration, duration]);\n\n  const icons = {\n    idle: idleIcon,\n    loading: loadingIcon,\n    success: successIcon,\n  };\n\n  const ariaLabels = {\n    idle: \"Copy\",\n    loading: \"Copying...\",\n    success: \"Copied\",\n  };\n\n  return (\n    <div className=\"flex justify-center\">\n      <button\n        aria-label={ariaLabels[buttonState]}\n        aria-live=\"polite\"\n        className={`relative min-h-[44px] w-auto min-w-[44px] cursor-pointer overflow-hidden rounded-full border bg-background p-3 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 ${className}`}\n        disabled={buttonState !== \"idle\" || disabled}\n        onClick={handleClick}\n        type=\"button\"\n      >\n        <AnimatePresence initial={false} mode=\"popLayout\">\n          <motion.span\n            animate={\n              shouldReduceMotion\n                ? { opacity: 1 }\n                : { filter: \"blur(0px)\", opacity: 1, y: 0 }\n            }\n            className=\"flex w-full items-center justify-center\"\n            exit={\n              shouldReduceMotion\n                ? { opacity: 0, transition: { duration: 0 } }\n                : { filter: \"blur(10px)\", opacity: 0, y: 25 }\n            }\n            initial={\n              shouldReduceMotion\n                ? { opacity: 1 }\n                : { filter: \"blur(10px)\", opacity: 0, y: -25 }\n            }\n            key={buttonState}\n            transition={\n              shouldReduceMotion\n                ? { duration: 0 }\n                : { bounce: 0, duration: 0.25, type: \"spring\" as const }\n            }\n          >\n            {icons[buttonState]}\n          </motion.span>\n        </AnimatePresence>\n      </button>\n    </div>\n  );\n}\n","path":"index.tsx","target":"components/smoothui/button-copy/index.tsx","type":"registry:ui"}],"name":"button-copy","registryDependencies":[],"title":"Button Copy","type":"registry:ui"}