{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "draw-signature",
  "type": "registry:component",
  "title": "Draw Signature",
  "description": "A premium interactive signature component that captures fluid strokes with a custom pen cursor and step-based workflow.",
  "dependencies": [
    "lucide-react",
    "motion",
    "next-themes",
    "react-icons",
    "react-use-measure"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "components/watermelon/draw-signature.tsx",
      "type": "registry:component",
      "content": "'use client';\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { motion, AnimatePresence, MotionConfig } from 'motion/react';\nimport { X } from 'lucide-react';\nimport { FaPen } from 'react-icons/fa6';\nimport { MdDraw } from 'react-icons/md';\nimport { FaCheckCircle, FaRedo } from 'react-icons/fa';\nimport { useTheme } from 'next-themes';\nimport useMeasure from 'react-use-measure';\nimport { cn } from '@/lib/utils';\n\ninterface DrawSignatureComponentProps {\n  startLabel?: string;\n  finishLabel?: string;\n  doneLabel?: string;\n  defaultStep?: 'idle' | 'drawing' | 'done';\n  onFinish?: (canvas: HTMLCanvasElement | null) => void;\n  onClear?: () => void;\n  onStepChange?: (step: 'idle' | 'drawing' | 'done') => void;\n}\n\nexport const DrawSignatureComponent: React.FC<DrawSignatureComponentProps> = ({\n  startLabel = 'Start Signing',\n  finishLabel = 'Finish Signing',\n  doneLabel = 'Signing Done',\n  defaultStep = 'idle',\n  onFinish,\n  onClear,\n  onStepChange,\n}) => {\n  const [step, setStep] = useState<'idle' | 'drawing' | 'done'>(defaultStep);\n  const [ref, bounds] = useMeasure({ offsetSize: true });\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const [isDrawing, setIsDrawing] = useState(false);\n  const [savedSignature, setSavedSignature] = useState<string | null>(null);\n  const { resolvedTheme } = useTheme();\n  const [mounted, setMounted] = useState(false);\n\n  useEffect(() => {\n    // eslint-disable-next-line react-hooks/set-state-in-effect\n    setMounted(true);\n  }, []);\n\n  useEffect(() => {\n    onStepChange?.(step);\n  }, [step, onStepChange]);\n\n  useEffect(() => {\n    if (step === 'drawing' && canvasRef.current) {\n      const canvas = canvasRef.current;\n      const ctx = canvas.getContext('2d');\n      if (!ctx) return;\n\n      ctx.strokeStyle = resolvedTheme === 'dark' ? '#ffffff' : '#000000';\n      ctx.lineWidth = 3;\n      ctx.lineCap = 'round';\n      ctx.lineJoin = 'round';\n\n      if (savedSignature) {\n        const img = new Image();\n        img.src = savedSignature;\n        img.onload = () => {\n          ctx.clearRect(0, 0, canvas.width, canvas.height);\n          ctx.drawImage(img, 0, 0);\n        };\n      }\n    }\n  }, [step, resolvedTheme, savedSignature]);\n\n  if (!mounted) return null;\n\n  const startDrawing = (e: React.MouseEvent | React.TouchEvent) => {\n    setIsDrawing(true);\n    draw(e);\n  };\n\n  const stopDrawing = () => {\n    setIsDrawing(false);\n    const ctx = canvasRef.current?.getContext('2d');\n    ctx?.beginPath();\n  };\n\n  const draw = (e: React.MouseEvent | React.TouchEvent) => {\n    if (!isDrawing || !canvasRef.current) return;\n    const canvas = canvasRef.current;\n    const ctx = canvas.getContext('2d');\n    if (!ctx) return;\n\n    const rect = canvas.getBoundingClientRect();\n    const x = ('touches' in e ? e.touches[0].clientX : e.clientX) - rect.left;\n    const y = ('touches' in e ? e.touches[0].clientY : e.clientY) - rect.top;\n\n    ctx.lineTo(x, y);\n    ctx.stroke();\n    ctx.beginPath();\n    ctx.moveTo(x, y);\n  };\n\n  const clearCanvas = () => {\n    const canvas = canvasRef.current;\n    const ctx = canvas?.getContext('2d');\n    if (canvas && ctx) {\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n    }\n\n    setSavedSignature(null);\n    onClear?.();\n  };\n\n  const finishSigning = () => {\n    if (canvasRef.current) {\n      const dataUrl = canvasRef.current.toDataURL();\n      setSavedSignature(dataUrl);\n    }\n\n    setStep('done');\n    onFinish?.(canvasRef.current);\n  };\n\n  const penColor = resolvedTheme === 'dark' ? 'white' : 'black';\n\n  return (\n    <MotionConfig\n      transition={{\n        type: 'spring',\n        bounce: 0.15,\n        duration: 0.7,\n      }}\n    >\n      <motion.div\n        animate={{\n          width: bounds.width > 0 ? bounds.width : 'auto',\n          height: bounds.height > 0 ? bounds.height : 'auto',\n        }}\n        className={cn(\n          'relative z-10 flex items-center justify-center overflow-hidden border-4 border-dashed border-transparent transition-colors duration-400 ease-out',\n          step === 'drawing' &&\n          'border-4 border-dashed border-neutral-300 dark:border-neutral-700',\n        )}\n        style={{\n          borderRadius: 32,\n        }}\n      >\n        <div ref={ref} className=\"i flex shrink-0 p-1\">\n          <AnimatePresence mode=\"popLayout\" initial={false}>\n            {step === 'idle' && (\n              <motion.button\n                key=\"start\"\n                // exit={{ opacity: 0, transition: { duration: 0 } }}\n                layoutId=\"container-button\"\n                onClick={() => setStep('drawing')}\n                className=\"flex items-center gap-2 rounded-full bg-neutral-100 px-8 py-5 text-lg font-bold text-neutral-900 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-100 dark:hover:bg-neutral-700\"\n              >\n                <motion.div layoutId=\"container-button-icon\">\n                  <MdDraw size={24} />\n                </motion.div>\n                <motion.span layoutId=\"container-button-text\">\n                  {startLabel}\n                </motion.span>\n              </motion.button>\n            )}\n\n            {step === 'drawing' && (\n              <motion.div\n                key=\"pad\"\n                exit={{\n                  opacity: 0,\n                  y: '-30%',\n                  x: '-10%',\n                }}\n                className=\"w-[320px] max-w-[320px] rounded-[34px] bg-white p-6 pb-4 will-change-transform dark:bg-neutral-900\"\n              >\n                <div className=\"mb-6 flex items-center justify-between\">\n                  <button\n                    onClick={clearCanvas}\n                    className=\"text-neutral-400 hover:text-neutral-600 dark:text-neutral-500 dark:hover:text-neutral-300\"\n                  >\n                    <FaRedo size={22} />\n                  </button>\n\n                  <span className=\"text-lg font-bold text-neutral-500 dark:text-neutral-400\">\n                    Sign\n                  </span>\n\n                  <button\n                    onClick={() => setStep('idle')}\n                    className=\"flex h-7 w-7 items-center justify-center rounded-full bg-neutral-400 text-white hover:bg-neutral-500 dark:bg-neutral-700 dark:hover:bg-neutral-600\"\n                  >\n                    <X size={20} />\n                  </button>\n                </div>\n\n                <canvas\n                  ref={canvasRef}\n                  width={290}\n                  height={200}\n                  onMouseDown={startDrawing}\n                  onMouseMove={draw}\n                  onMouseUp={stopDrawing}\n                  onMouseLeave={stopDrawing}\n                  onTouchStart={startDrawing}\n                  onTouchMove={draw}\n                  onTouchEnd={stopDrawing}\n                  className=\"h-[200px] w-full touch-none\"\n                  style={{\n                    cursor: `url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"34\" height=\"34\" viewBox=\"0 0 24 24\" fill=\"${penColor}\" stroke=\"${resolvedTheme === 'dark' ? 'black' : 'white'}\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z\"/><path d=\"m15 5 4 4\"/></svg>') 0 22, auto`,\n                  }}\n                />\n\n                <motion.button\n                  layoutId=\"container-button\"\n                  exit={{ opacity: 0, transition: { duration: 0 } }}\n                  whileTap={{ scale: 0.97 }}\n                  onClick={finishSigning}\n                  className=\"mt-4 flex w-full items-center justify-center gap-2 rounded-full bg-neutral-100 px-6 py-4 text-lg font-bold text-neutral-900 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-100 dark:hover:bg-neutral-700\"\n                >\n                  <motion.div layoutId=\"container-button-icon\">\n                    <MdDraw size={28} />\n                  </motion.div>\n                  <motion.span layoutId=\"container-button-text\">\n                    {finishLabel}\n                  </motion.span>\n                </motion.button>\n              </motion.div>\n            )}\n\n            {step === 'done' && (\n              <motion.div\n                key=\"done\"\n                exit={{ opacity: 0, transition: { duration: 0 } }}\n                className=\"flex items-center gap-3\"\n                layoutId=\"container-button\"\n              >\n                <motion.div className=\"flex items-center gap-2 rounded-full bg-neutral-900 px-6 py-4 text-lg font-bold text-white dark:bg-neutral-100 dark:text-neutral-900\">\n                  <motion.div layoutId=\"container-button-icon\">\n                    <FaCheckCircle size={24} />\n                  </motion.div>\n                  <motion.span layoutId=\"container-button-text\">\n                    {doneLabel}\n                  </motion.span>\n                </motion.div>\n\n                <motion.button\n                  // initial={{ scale: 0.5, opacity: 0 }}\n                  // animate={{ scale: 1, opacity: 1 }}\n                  onClick={() => setStep('drawing')}\n                  className=\"rounded-full bg-neutral-100 p-4 text-neutral-900 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-100 dark:hover:bg-neutral-700\"\n                >\n                  <FaPen size={22} />\n                </motion.button>\n              </motion.div>\n            )}\n          </AnimatePresence>\n        </div>\n      </motion.div>\n    </MotionConfig>\n  );\n};\n"
    }
  ]
}
